diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f900ddf41..67b987f8d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -108,14 +108,14 @@ remove: Total 10 (delta 1), reused 10 (delta 1) Unpacking objects: 100% (10/10), done. ``` -## Switch to `master` branch +## Switch to `main` branch -In order to add your changes, you will need to do those in the `master` branch. +In order to add your changes, you will need to do those in the `main` branch. -Type the following command in the console to switch to `master` branch: +Type the following command in the console to switch to `main` branch: ``` -git checkout master +git checkout main ``` Now, you can update existing docs or add new docs to the docs repo. @@ -131,15 +131,15 @@ Depending on the doc's intent, you can choose to add your doc into `basics` or ## Submit a pull request -Once you have completed adding your changes, you can submit a pull request. +Once you have completed adding your changes, you can submit a pull request. -Navigate to the forked sp-dev-docs repo in your account. Make sure your current branch is `master` branch. +Navigate to the forked sp-dev-docs repo in your account. Make sure your current branch is `main` branch. -Once you are in the `master` branch, you should see a message stating `This branch is 1 commit ahead of SharePoint:master` and next to it will be a `Pull request` link. +Once you are in the `main` branch, you should see a message stating `This branch is 1 commit ahead of Sharepoint:main` and next to it will be a `Pull request` link. ![Submit a pull request to sp-dev-docs repo](../images/contribute-docs-submit-pr.png) -Click the `Pull request` link to start a new pull request. Make sure you use this [template](PULL_REQUEST_TEMPLATE.md) to fill in your changes. Make sure you are creating this pull request against the `master` branch. +Click the `Pull request` link to start a new pull request. Make sure you use this [template](PULL_REQUEST_TEMPLATE.md) to fill in your changes. Make sure you are creating this pull request against the `main` branch. Once you have all the information, click the `Create pull request` button to submit your pull request. diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 92c5a2dd6..6d3825f0c 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -8,7 +8,7 @@ body: value: | - [x] Bug - This is for SharePoint development bugs. If your submission is now about SharePoint development such as out-of-the-box capabilities, SharePoint configuration, please use refer to other support options listed on the [new issue chooser page](https://github.com/SharePoint/sp-dev-docs/issues/new/choose). Please provide as much information as possible so we can best address your submission. Thanks! + This is for SharePoint development bugs. If your submission is not about SharePoint development such as out-of-the-box capabilities, SharePoint configuration, please refer to other support options listed on the [new issue chooser page](https://github.com/SharePoint/sp-dev-docs/issues/new/choose). Please provide as much information as possible so we can best address your submission. Thanks! - Follow our guidance on [How To Create Good Issues](https://github.com/sharepoint/sp-dev-docs/wiki/How-to-Create-Good-Issues). - Remember to include sufficient details and context. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 92a598428..99aeec9af 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -22,6 +22,9 @@ > - **!!IMPORTANT!!** - All submissions must complete the baseline sections included in this template. Ignoring or deleting this template may result in closing the issue with the label **type:incomplete-submission**. > - Follow our guidance on [How To Create Good Pull Requests](https://github.com/SharePoint/sp-dev-docs/wiki/How-to-Create-Good-Pull-Requests). -> - Target the `master` branch of this repo. Released documents are in `live` branch. +> - Target the `main` branch of this repo. +> - When changing a page, ensure you update the `ms.date` front matter wih the current date in the format `MM/DD/YYYY`. +> - Review all build checks and address the automated errors, warnings, and suggestions. +> - *NOTE: The live site is based on the `live` branch. Site owners periodically refresh `live` branch from the `main` branch so merged PRs won't immediately appear on the live site. Please be patient to see your changes appear on the live site.* > > **DELETE THIS SECTION BEFORE SUBMITTING** diff --git a/.github/fabricbot.json b/.github/fabricbot.json new file mode 100644 index 000000000..6dcaf2f39 --- /dev/null +++ b/.github/fabricbot.json @@ -0,0 +1,1149 @@ +{ + "version": "1.0", + "tasks": [ + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isEvent", + "parameters": { + "eventName": "issues" + } + }, + { + "name": "isAction", + "parameters": { + "action": "opened" + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isAssignedToSomeone", + "parameters": {} + } + ] + } + ] + }, + "taskName": "Auto-label incoming issues as Needs Triage", + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible." + } + }, + { + "name": "addLabels", + "parameters": { + "labels": [ + "Needs: Triage :mag:" + ] + } + } + ] + }, + "id": "DhSdUvTfU" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": "msft-github-bot" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + }, + { + "name": "hasLabel", + "parameters": { + "label": "no-recent-activity" + } + } + ] + }, + "taskName": "Remove no recent activity label", + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "no-recent-activity" + } + } + ] + }, + "id": "EuTNKsOAX" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isEvent", + "parameters": { + "eventName": "issue_comment" + } + }, + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isActivitySender", + "parameters": { + "user": { + "type": "author" + } + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "Needs: Author Feedback" + } + } + ] + }, + "taskName": "Add needs attention label to issues", + "actions": [ + { + "name": "addLabels", + "parameters": { + "labels": [ + "Needs: Attention :wave:" + ] + } + } + ] + }, + "id": "4g_ssp7c7" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssueResponder", + "version": "1.0", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": { + "type": "author" + } + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + }, + { + "name": "hasLabel", + "parameters": { + "label": "Needs: Author Feedback" + } + } + ] + }, + "taskName": "Remove needs author feedback label from issues and pull requests", + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "Needs: Author Feedback" + } + } + ] + }, + "id": "LSpcATOkS" + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "id": "R2LaDi6Kz", + "config": { + "taskName": "Closed answered issues in 3 days", + "frequency": [ + { + "weekDay": 0, + "hours": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + }, + { + "weekDay": 1, + "hours": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + }, + { + "weekDay": 2, + "hours": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + }, + { + "weekDay": 3, + "hours": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + }, + { + "weekDay": 4, + "hours": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + }, + { + "weekDay": 5, + "hours": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + }, + { + "weekDay": 6, + "hours": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + } + ], + "searchTerms": [ + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "status:answered" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 3 + } + } + ], + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Closing this issue as \"answered\". If you encounter a similar issue(s), please open up a new issue. See our wiki for more details: [Issue-List: Our approach to closed issues](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#our-approach-to-closed-issues)" + } + }, + { + "name": "closeIssue", + "parameters": {} + }, + { + "name": "lockIssue", + "parameters": { + "reason": "resolved" + } + } + ] + } + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "id": "ejaaeLe6G", + "config": { + "frequency": [ + { + "weekDay": 0, + "hours": [ + 1, + 5, + 9, + 13, + 17, + 21 + ], + "timezoneOffset": -5 + }, + { + "weekDay": 1, + "hours": [ + 1, + 5, + 9, + 13, + 17, + 21 + ], + "timezoneOffset": -5 + }, + { + "weekDay": 2, + "hours": [ + 1, + 5, + 9, + 13, + 17, + 21 + ], + "timezoneOffset": -5 + }, + { + "weekDay": 3, + "hours": [ + 1, + 5, + 9, + 13, + 17, + 21 + ], + "timezoneOffset": -5 + }, + { + "weekDay": 4, + "hours": [ + 1, + 5, + 9, + 13, + 17, + 21 + ], + "timezoneOffset": -5 + }, + { + "weekDay": 5, + "hours": [ + 1, + 5, + 9, + 13, + 17, + 21 + ], + "timezoneOffset": -5 + }, + { + "weekDay": 6, + "hours": [ + 1, + 5, + 9, + 13, + 17, + 21 + ], + "timezoneOffset": -5 + } + ], + "searchTerms": [ + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "Needs: Author Feedback" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "no-recent-activity" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 7 + } + } + ], + "taskName": "Close stale issues", + "actions": [ + { + "name": "closeIssue", + "parameters": {} + }, + { + "name": "addReply", + "parameters": { + "comment": "Closing issue due to no response from the original author. Please refer to our wiki for more details, including how to remediate this action if you feel this was done prematurely or in error: [No response from the original issue author](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#no-response-from-the-original-issue-author)" + } + }, + { + "name": "lockIssue", + "parameters": {} + } + ] + }, + "disabled": false + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "JN4EianUp", + "config": { + "conditions": { + "operator": "or", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "type:invalid-not-dev-issue" + } + }, + { + "name": "labelAdded", + "parameters": { + "label": "type:invalid" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "Reply & close issues tagged \"type:invalid-not-dev-issue\"", + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Thank you for your submission. As explained in our wiki ([Issue List: What doesn't belong in the issue list](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#what-doesnt-belong-in-the-issue-list)), this issue list is for SharePoint developer/development issues. All capability question/discussion questions, or topics related to SharePoint administration & end-user topics should be reported through the support user interface available in the tenant admin settings. You can also have a discussion and ask questions at the [SharePoint TechCommunity](https://techcommunity.microsoft.com/t5/SharePoint/ct-p/SharePoint) forum. You can learn more about this in our wiki: [type:invalid-not-dev-issue](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List-Labels#typeinvalid-not-dev-issue)" + } + }, + { + "name": "closeIssue", + "parameters": {} + }, + { + "name": "lockIssue", + "parameters": { + "reason": "off-topic" + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "dTcNyMD5a", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "type:uservoice-request" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Thank you for your submission. As explained in our wiki ([Issue List: What doesn't belong in the issue list](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#what-doesnt-belong-in-the-issue-list)), all new feature requests and change requests to existing features should be posted to the [SP Dev UserVoice](https://aka.ms/sp-dev-uservoice) site. You can learn more about this in our wiki: [type:uservoice-request](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List-Labels#typeuservoice-request)" + } + }, + { + "name": "closeIssue", + "parameters": {} + } + ], + "taskName": "Reply & close issues tagged \"type:uservoice-request\"" + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "TXAA0OOon", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "Needs: Context Detail :question:" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "Reply issues tagged \"Needs: Context Detail\"", + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "The more context details you can provide, the easier it is to help assist on issues. Any code you can provide and/or screenshots of the issue also help. The easier you can make it to reproduce the issue, the easier and quicker it is for someone to help you. Please refer to [How to Create Good Issues](https://github.com/SharePoint/sp-dev-docs/wiki/How-to-Create-Good-Issues), specifically [How to Create Good Issues: Include context](https://github.com/SharePoint/sp-dev-docs/wiki/How-to-Create-Good-Issues#include-context), in our wiki for more details." + } + }, + { + "name": "addLabel", + "parameters": { + "label": "Needs: Author Feedback" + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "vAHQpj0AT", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "status:duplicate" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "Close issues tagged \"status:duplicate\"", + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Closing this issue as a dupe. Please refer to our wiki for more details: [Issue List Labels: status:duplicate](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List-Labels#statusduplicate)" + } + }, + { + "name": "closeIssue", + "parameters": {} + }, + { + "name": "lockIssue", + "parameters": { + "reason": "resolved" + } + } + ] + } + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "id": "Lzyb5Csy_", + "config": { + "frequency": [ + { + "weekDay": 0, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 1, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 2, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 3, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 4, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 5, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 6, + "hours": [ + 0, + 6, + 12, + 18 + ] + } + ], + "searchTerms": [ + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isClosed", + "parameters": {} + }, + { + "name": "noActivitySince", + "parameters": { + "days": 7 + } + }, + { + "name": "isUnlocked", + "parameters": {} + } + ], + "taskName": "Lock issues if inactive 7d after closing", + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Issues that have been closed & had no follow-up activity for at least 7 days are automatically locked. Please refer to our wiki for more details, including how to remediate this action if you feel this was done prematurely or in error: [Issue List: Our approach to locked issues](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#our-approach-to-locked-issues)" + } + }, + { + "name": "lockIssue", + "parameters": { + "reason": "resolved" + } + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "k84udcNf_", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "bodyContains", + "parameters": { + "bodyPattern": "Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking." + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "area:docs-comment" + } + } + ], + "taskName": "Label new issues created as comment on docs with \"area:docs-comment\"" + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "NbeJ2zWgh", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "type:incomplete-submission" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "taskName": "Reply & tag issues tagged with type:incomplete-submission", + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Thank you for your submission, but there isn't enough detail in the issue for us to review & move forward. The new issue template includes sections for you to fill out. Please resubmit your issue and complete the provided sections in the new item template so we can move forward on it refer to our wiki for more information: [How to Create Good Issues](https://github.com/SharePoint/sp-dev-docs/wiki/How-to-Create-Good-Issues)" + } + }, + { + "name": "removeLabel", + "parameters": { + "label": "Needs: Triage :mag:" + } + }, + { + "name": "closeIssue", + "parameters": {} + } + ] + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "id": "SgmbtMnlk", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "type:incomplete-submission" + } + } + ] + }, + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ], + "taskName": "Reply & tag PRs tagged with type:incomplete-submission", + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "Thank you for your submission, but there isn't enough detail in the pull request for us to review & move forward. The new PR template includes sections for you to fill out. Please resubmit your PR and complete the provided sections in the new item template so we can move forward on it refer to our wiki for more information: [How to Create Good Pull Requests]https://github.com/SharePoint/sp-dev-docs/wiki/How-to-Create-Good-Pull-Requests)" + } + }, + { + "name": "closeIssue", + "parameters": {} + } + ] + } + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "id": "ECBdzA7w3Y7R-jcBx0icn", + "config": { + "frequency": [ + { + "weekDay": 0, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 1, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 2, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 3, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 4, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 5, + "hours": [ + 0, + 6, + 12, + 18 + ] + }, + { + "weekDay": 6, + "hours": [ + 0, + 6, + 12, + 18 + ] + } + ], + "searchTerms": [ + { + "name": "isIssue", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "Needs: Author Feedback" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 7 + } + } + ], + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "no-recent-activity" + } + }, + { + "name": "addReply", + "parameters": { + "comment": "This issue has been automatically marked as stale because it has marked as requiring author feedback but has not had any activity for **7 days**. It will be closed if no further activity occurs **within the next 7 days of this comment**. Please see our wiki for more information: [Issue List Labels: Needs Author Feedback](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List-Labels#needs-author-feedback) & [Issue List: No response from the original issue author](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#no-response-from-the-original-issue-author)" + } + } + ], + "taskName": "Mark issue with no-recent-activity label if there's no actions in 7 days" + } + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "id": "MdPj2K40N73yDGFnu9REz", + "config": { + "conditions": { + "operator": "and", + "operands": [ + { + "name": "labelAdded", + "parameters": { + "label": "listmaintenance-oldissues" + } + } + ] + }, + "eventType": "issue", + "eventNames": [ + "issues", + "project_card" + ], + "actions": [ + { + "name": "addReply", + "parameters": { + "comment": "This issue is being closed as part of an issue list cleanup project. Issues with no activity in the past 6 months that aren't tracked by engineering as bugs were closed as part of this inititive. If this is still an issue, please [follow the steps outlined to re-open or submit a new issue](https://github.com/sharepoint/sp-dev-docs/wiki/Issue-List#our-approach-to-closed-issues)." + } + }, + { + "name": "closeIssue", + "parameters": {} + } + ], + "taskName": "Close inactive issues based on list maintenance label" + } + } + ], + "userGroups": [] +} diff --git a/.github/label-actions.yml b/.github/label-actions.yml new file mode 100644 index 000000000..80a5bf7aa --- /dev/null +++ b/.github/label-actions.yml @@ -0,0 +1,14 @@ +# Configuration for Label Actions - https://github.com/dessant/label-actions + +# Actions taken when the `type:archive-old-issue` label is added to issues that are being archived. +type:archive-old-issue: + # Post a comment + comment: |+ + Thank you for taking the time to file an issue. We periodically **archive** older or inactive issues as part of our issue management process, which automatically closes them once they are archived. + + If you’d like to understand more about why and how we handle archived (closed) issues, please see [Our approach to closed issues](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#our-approach-to-closed-issues). + + We appreciate your contribution and if this is still an active issue with the latest SPFx versions, please do resubmit the details. We needed to perform a cleanup, so that we can start with a **clean table** with a new process. We apologize for the inconvenience this might cause. + + # Close the issue + close: true diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml new file mode 100644 index 000000000..43263aa44 --- /dev/null +++ b/.github/policies/resourceManagement.yml @@ -0,0 +1,115 @@ +id: bot-issue-management +name: Issue Management +description: Enable tracking & monitoring of issues +resource: repository +disabled: false +configuration: + resourceManagementConfiguration: + scheduledSearches: + - description: Close answered issues after 3 days of inactivity + frequencies: + - hourly: { hour: 0 } + filters: + - isIssue + - isOpen + - hasLabel: { label: status:answered } + - noActivitySince: { days: 3 } + actions: + - addReply: + reply: > + Closing this issue as "answered". If you encounter a similar issue(s), please open up a new issue. See our wiki for more details: [Issue-List: Our approach to closed issues](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#our-approach-to-closed-issues) + - closeIssue + - lockIssue: + reason: resolved + + - description: Close stale issues with no recent author activity after 7 days + frequencies: + - hourly: { hour: 6 } + filters: + - isIssue + - isOpen + - hasLabel: { label: 'Needs: Author Feedback' } + - hasLabel: { label: no-recent-activity } + - noActivitySince: { days: 7 } + actions: + - addReply: + reply: > + Closing issue due to no response from the original author. Please refer to our wiki for more details, including how to remediate this action if you feel this was done prematurely or in error: [No response from the original issue author](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#no-response-from-the-original-issue-author) + - closeIssue + - lockIssue + + - description: Mark issues as no recent activity after 7 days + frequencies: + - hourly: { hour: 6 } + filters: + - isIssue + - isOpen + - hasLabel: { label: 'Needs: Author Feedback' } + - noActivitySince: { days: 7 } + actions: + - addLabel: { label: no-recent-activity } + - addReply: + reply: > + This issue has been automatically marked as stale because it has marked as requiring author feedback but has not had any activity for **7 days**. It will be closed if no further activity occurs **within the next 7 days of this comment**. Please see our wiki for more information: [Issue List Labels: Needs Author Feedback](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List-Labels#needs-author-feedback) & [Issue List: No response from the original issue author](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#no-response-from-the-original-issue-author) + + - description: Lock issues inactive 7 days after closing + frequencies: + - hourly: { hour: 6 } + filters: + - isIssue + - isClosed + - noActivitySince: { days: 7 } + - isUnlocked + actions: + - addReply: + reply: > + Issues that have been closed & had no follow-up activity for at least 7 days are automatically locked. Please refer to our wiki for more details, including how to remediate this action if you feel this was done prematurely or in error: [Issue List: Our approach to locked issues](https://github.com/SharePoint/sp-dev-docs/wiki/Issue-List#our-approach-to-locked-issues) + - lockIssue: + reason: resolved + + eventResponderTasks: + - if: + - payloadType: Issues + - isAction: { action: opened } + - not: + isAssignedToSomeone: true + then: + - addReply: + reply: > + Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible. + - addLabel: + label: 'Needs: Triage :mag:' + + - if: + - payloadType: Issue_Comment + - isActivitySender: { issueAuthor: true } + - hasLabel: { label: 'Needs: Author Feedback' } + - isOpen + then: + - addLabel: + label: 'Needs: Attention :wave:' + + - if: + - payloadType: Issues + - isActivitySender: { issueAuthor: true } + - not: + isAction: { action: closed } + - hasLabel: { label: 'Needs: Author Feedback' } + then: + - removeLabel: { label: 'Needs: Author Feedback' } + + - if: + - payloadType: Issues + - not: + isActivitySender: { user: microsoft-github-policy-service } + - not: + isAction: { action: closed } + - hasLabel: { label: no-recent-activity } + then: + - removeLabel: { label: no-recent-activity } + + - if: + - payloadType: Issue_Comment + - hasLabel: { label: no-recent-activity } + then: + - removeLabel: { label: no-recent-activity } diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml new file mode 100644 index 000000000..d2dd0ff59 --- /dev/null +++ b/.github/workflows/label-actions.yml @@ -0,0 +1,18 @@ +name: 'Check for Incomplete Issues' + +on: + issues: + types: [labeled, unlabeled] + +permissions: + issues: write + pull-requests: write + +jobs: + reaction: + runs-on: ubuntu-latest + steps: + - uses: dessant/label-actions@v2 + with: + github-token: ${{ github.token }} + process-only: 'issues' diff --git a/.openpublishing.build.ps1 b/.openpublishing.build.ps1 deleted file mode 100644 index aadef7620..000000000 --- a/.openpublishing.build.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -param( - [string]$buildCorePowershellUrl = "https://opbuildstorageprod.blob.core.windows.net/opps1container/.openpublishing.buildcore.ps1", - [string]$parameters -) -# Main -$errorActionPreference = 'Stop' - -# Step-1: Download buildcore script to local -echo "download build core script to local with source url: $buildCorePowershellUrl" -$repositoryRoot = Split-Path -Parent $MyInvocation.MyCommand.Definition -$buildCorePowershellDestination = "$repositoryRoot\.openpublishing.buildcore.ps1" -Invoke-WebRequest $buildCorePowershellUrl -OutFile "$buildCorePowershellDestination" - -# Step-2: Run build core -echo "run build core script with parameters: $parameters" -& "$buildCorePowershellDestination" "$parameters" -exit $LASTEXITCODE diff --git a/.openpublishing.publish.config.json b/.openpublishing.publish.config.json index d15c23789..f3522487f 100644 --- a/.openpublishing.publish.config.json +++ b/.openpublishing.publish.config.json @@ -24,12 +24,12 @@ ], "notification_subscribers": [ "vesaj@microsoft.com", - "bjansen@microsoft.com", - "v-licapu@microsoft.com" + "bjansen@microsoft.com" ], + "sync_notification_subscribers": null, "branches_to_filter": [], "git_repository_url_open_to_public_contributors": "https://github.com/SharePoint/sp-dev-docs", - "git_repository_branch_open_to_public_contributors": "master", + "git_repository_branch_open_to_public_contributors": "main", "skip_source_output_uploading": false, "need_preview_pull_request": true, "contribution_branch_mappings": {}, @@ -37,13 +37,13 @@ { "path_to_root": "_themes", "url": "https://github.com/Microsoft/templates.docs.msft", - "branch": "master", + "branch": "main", "branch_mapping": {} }, { "path_to_root": "_themes.pdf", "url": "https://github.com/Microsoft/templates.docs.msft.pdf", - "branch": "master", + "branch": "main", "branch_mapping": {} }, { @@ -60,11 +60,11 @@ ] }, "need_generate_pdf_url_template": true, - "Targets": { - "Pdf": { - "template_folder": "_themes.pdf" - } - }, + "Targets": { + "Pdf": { + "template_folder": "_themes.pdf" + } + }, "JoinTOCPlugin": [ { "ConceptualTOC": "/docs/toc.yml", diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 66c60dd15..78222f726 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1,84 +1,274 @@ { - "redirections": [ - { - "source_path": "docs/apis/rest/complete-basic-operations-using-sharepoint-rest-endpoints.md", - "redirect_url": "docs/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/determine-sharepoint-rest-service-endpoint-uris.md", - "redirect_url": "docs/sp-add-ins/determine-sharepoint-rest-service-endpoint-uris", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/get-to-know-the-sharepoint-rest-service.md", - "redirect_url": "docs/sp-add-ins/get-to-know-the-sharepoint-rest-service.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/make-batch-requests-with-the-rest-apis.md", - "redirect_url": "docs/sp-add-ins/make-batch-requests-with-the-rest-apis.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/navigate-the-sharepoint-data-structure-represented-in-the-rest-service.md", - "redirect_url": "docs/sp-add-ins/navigate-the-sharepoint-data-structure-represented-in-the-rest-service.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/set-custom-permissions-on-a-list-by-using-the-rest-interface.md", - "redirect_url": "docs/sp-add-ins/set-custom-permissions-on-a-list-by-using-the-rest-interface.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/synchronize-sharepoint-items-using-the-rest-service.md", - "redirect_url": "docs/sp-add-ins/synchronize-sharepoint-items-using-the-rest-service.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/upload-a-file-by-using-the-rest-api-and-jquery.md", - "redirect_url": "docs/sp-add-ins/upload-a-file-by-using-the-rest-api-and-jquery.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/use-odata-query-operations-in-sharepoint-rest-requests.md", - "redirect_url": "docs/sp-add-ins/use-odata-query-operations-in-sharepoint-rest-requests.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/working-with-folders-and-files-with-rest.md", - "redirect_url": "docs/sp-add-ins/working-with-folders-and-files-with-rest.md", - "redirect_document_id": false - }, - { - "source_path": "docs/apis/rest/working-with-lists-and-list-items-with-rest.md", - "redirect_url": "docs/sp-add-ins/working-with-lists-and-list-items-with-rest.md", - "redirect_document_id": false - }, - { - "source_path": "docs/schema/index.md", - "redirect_url": "docs/schema/upgrade-definition-schema.md", - "redirect_document_id": false - }, - { - "source_path": "docs/sp-add-ins/add-a-custom-content-type-to-a-sharepoint-hostedsharepoint-add-in.md", - "redirect_url": "docs/sp-add-ins/add-a-custom-content-type-to-a-sharepoint-hosted-sharepoint-add-in.md", - "redirect_document_id": false - }, - { - "source_path": "docs/sp-add-ins/add-custom-columns-to-a-sharepoint-hostedsharepoint-add-in.md", - "redirect_url": "docs/sp-add-ins/add-custom-columns-to-a-sharepoint-hosted-sharepoint-add-in.md", - "redirect_document_id": false - }, - { - "source_path": "docs/spfx/web-parts/guidance/creating-team-manifest-manually-for-webpart.md", - "redirect_url": "docs/spfx/deployment-spfx-teams-solutions.md", - "redirect_document_id": false - }, - { - "source_path": "docs/general-development/office-365-cdn.md", - "redirect_url": "/office365/enterprise/use-office-365-cdn-with-spo", - "redirect_document_id": false - } - ] -} \ No newline at end of file + "redirections": [ + { + "source_path": "docs/apis/rest/complete-basic-operations-using-sharepoint-rest-endpoints.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/determine-sharepoint-rest-service-endpoint-uris.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/determine-sharepoint-rest-service-endpoint-uris", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/get-to-know-the-sharepoint-rest-service.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/make-batch-requests-with-the-rest-apis.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/make-batch-requests-with-the-rest-apis", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/navigate-the-sharepoint-data-structure-represented-in-the-rest-service.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/navigate-the-sharepoint-data-structure-represented-in-the-rest-service", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/set-custom-permissions-on-a-list-by-using-the-rest-interface.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/set-custom-permissions-on-a-list-by-using-the-rest-interface", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/synchronize-sharepoint-items-using-the-rest-service.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/synchronize-sharepoint-items-using-the-rest-service", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/upload-a-file-by-using-the-rest-api-and-jquery.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/upload-a-file-by-using-the-rest-api-and-jquery", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/use-odata-query-operations-in-sharepoint-rest-requests.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/use-odata-query-operations-in-sharepoint-rest-requests", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/working-with-folders-and-files-with-rest.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest", + "redirect_document_id": false + }, + { + "source_path": "docs/apis/rest/working-with-lists-and-list-items-with-rest.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/working-with-lists-and-list-items-with-rest", + "redirect_document_id": false + }, + { + "source_path": "docs/schema/index.md", + "redirect_url": "/sharepoint/dev/schema/upgrade-definition-schema", + "redirect_document_id": false + }, + { + "source_path": "docs/sp-add-ins/add-a-custom-content-type-to-a-sharepoint-hostedsharepoint-add-in.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/add-a-custom-content-type-to-a-sharepoint-hosted-sharepoint-add-in", + "redirect_document_id": false + }, + { + "source_path": "docs/sp-add-ins/add-custom-columns-to-a-sharepoint-hostedsharepoint-add-in.md", + "redirect_url": "/sharepoint/dev/sp-add-ins/add-custom-columns-to-a-sharepoint-hosted-sharepoint-add-in", + "redirect_document_id": false + }, + { + "source_path": "docs/spfx/web-parts/guidance/creating-team-manifest-manually-for-webpart.md", + "redirect_url": "/sharepoint/dev/spfx/deployment-spfx-teams-solutions", + "redirect_document_id": false + }, + { + "source_path": "docs/general-development/office-365-cdn.md", + "redirect_url": "/sharepoint/dev/office365/enterprise/use-office-365-cdn-with-spo", + "redirect_document_id": false + }, + { + "source_path": "docs/spfx/toolchain/scaffolding-projects-using-yeoman-sharepoint-generator.md", + "redirect_url": "/sharepoint/dev/spfx/yeoman-generator-for-spfx-intro", + "redirect_document_id": false + }, + { + "source_path": "docs/spfx/office-addins-create.md", + "redirect_url": "/sharepoint/dev/spfx/release-1.14", + "redirect_document_id": false + }, + { + "source_path": "docs/spfx/web-parts/get-started/office-addins-tutorial.md", + "redirect_url": "/sharepoint/dev/spfx/release-1.14", + "redirect_document_id": false + }, + { + "source_path": "docs/spfx/sharepoint-2019-support.md", + "redirect_url": "/sharepoint/dev/spfx/sharepoint-2019-and-subscription-edition-support", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/mslearn/m01-01-intro.md", + "redirect_url": "/training/modules/sharepoint-embedded-setup/", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/mslearn/m02-01-intro.md", + "redirect_url": "/training/modules/sharepoint-embedded-create-app/", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/adoptions-and-use.md", + "redirect_url": "/sharepoint/dev/embedded/scenarios-and-use-cases", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/billing.md", + "redirect_url": "/sharepoint/dev/embedded/concepts/admin-exp/billing/billing", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/cta.md", + "redirect_url": "/sharepoint/dev/embedded/concepts/admin-exp/consuming-tenant-admin/cta", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/dev-admin.md", + "redirect_url": "/sharepoint/dev/embedded/concepts/admin-exp/developer-admin/dev-admin", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/app-concepts/terms-and-def.md", + "redirect_url": "/sharepoint/dev/embedded/overview", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/getting-started/enable-sharepoint-embedded.md", + "redirect_url": "/sharepoint/dev/embedded/overview", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/terms-of-service.md", + "redirect_url": "/sharepoint/dev/embedded/overview", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/adminrole.md", + "redirect_url": "/sharepoint/dev/embedded/administration/adminrole", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/billing/billing.md", + "redirect_url": "/sharepoint/dev/embedded/administration/billing/billing", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/billing/billingmanagement.md", + "redirect_url": "/sharepoint/dev/embedded/administration/billing/billingmanagement", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/billing/meters.md", + "redirect_url": "/sharepoint/dev/embedded/administration/billing/meters", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/consuming-tenant-admin/cta.md", + "redirect_url": "/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/consuming-tenant-admin/ctaUX.md", + "redirect_url": "/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaUX", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/consuming-tenant-admin/ctapowershell.md ", + "redirect_url": "/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/admin-exp/developer-admin/dev-admin.md", + "redirect_url": "/sharepoint/dev/embedded/administration/developer-admin/dev-admin", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/security-and-compliance.md", + "redirect_url": "/sharepoint/dev/embedded/compliance/security-and-compliance", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/app-concepts/app-architecture.md", + "redirect_url": "/sharepoint/dev/embedded/development/app-architecture", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/app-concepts/auth.md", + "redirect_url": "/sharepoint/dev/embedded/development/auth", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/content-experiences/office-experience.md", + "redirect_url": "/sharepoint/dev/embedded/development/content-experiences/office-experience", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/content-experiences/search-content.md", + "redirect_url": "/sharepoint/dev/embedded/development/content-experiences/search-content", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/content-experiences/user-experiences-overview.md", + "redirect_url": "/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/fluid.md", + "redirect_url": "/sharepoint/dev/embedded/development/fluid", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/app-concepts/limits-calling.md", + "redirect_url": "/sharepoint/dev/embedded/development/limits-calling", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/app-concepts/sharing-and-perm.md", + "redirect_url": "/sharepoint/dev/embedded/development/sharing-and-perm", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/tutorials/doc-processing-acs.md", + "redirect_url": "/sharepoint/dev/embedded/development/tutorials/doc-processing-acs", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/tutorials/launch-experience.md", + "redirect_url": "/sharepoint/dev/embedded/development/tutorials/launch-experience", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/tutorials/metadata.md", + "redirect_url": "/sharepoint/dev/embedded/development/tutorials/metadata", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/tutorials/migrate-abs-to-spe.md", + "redirect_url": "/sharepoint/dev/embedded/development/tutorials/migrate-abs-to-spe", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/tutorials/using-file-preview.md", + "redirect_url": "/sharepoint/dev/embedded/development/tutorials/using-file-preview", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/tutorials/using-webhooks.md", + "redirect_url": "/sharepoint/dev/embedded/development/tutorials/using-webhooks", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/app-concepts/containertypes.md", + "redirect_url": "/sharepoint/dev/embedded/getting-started/containertypes", + "redirect_document_id": false + }, + { + "source_path": "docs/embedded/concepts/app-concepts/register-api-documentation.md", + "redirect_url": "/sharepoint/dev/embedded/getting-started/register-api-documentation", + "redirect_document_id": false + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..ed9462b7e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "markdownlint.config": { + "MD028": false, + "MD025": { + "front_matter_title": "" + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 7fd1a10a7..4e77f8fcb 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Welcome to the SharePoint Framework! +# Welcome to the SharePoint Framework! The SharePoint Framework (SPFx) is a page and part model that enables client-side development for building SharePoint experiences. It facilitates easy integration with the SharePoint data, and provides support for open source tooling development. * [Official SharePoint Framework Documentation](https://aka.ms/spfx) -This repository contains the raw documents published to docs.microsoft.com site. +This repository contains the raw documents published to Microsoft Docs. ## Questions & Help @@ -14,20 +14,19 @@ You can also tweet / follow [@Microsoft365Dev](https://twitter.com/Microsoft365D ## SharePoint Framework Releases -Review all the SPFx releases here from the initial GA release in February 2017 in the docs: https://docs.microsoft.com/sharepoint/dev/spfx/roadmap +Review all the SPFx releases here from the [initial GA release in February 2017](https://learn.microsoft.com/sharepoint/dev/spfx/roadmap) ## Get Started -* [Setup your Office 365 Developer Tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant) -* [Setup your Machine](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment) -* [Go build your first web part](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part) - +* [Setup your Office 365 Developer Tenant](https://learn.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant) +* [Setup your Machine](https://learn.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment) +* [Go build your first web part](https://learn.microsoft.com/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part) ## Learn More -* [Background and Philosophy](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview) -* [Design Great Web Parts](https://docs.microsoft.com/sharepoint/dev/design/design-guidance-overview) -* [API Docs](/javascript/api/sp-application-base) +* [Background and Philosophy](https://learn.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview) +* [Design Great Web Parts](https://learn.microsoft.com/sharepoint/dev/design/design-guidance-overview) +* [API Docs](https://learn.microsoft.com/javascript/api/sp-application-base) ## Updates & Feedback @@ -49,7 +48,7 @@ Please see following guidance if you are planning to submit changes on the Share * [Contribution guidance](https://github.com/SharePoint/sp-dev-docs/blob/master/.github/CONTRIBUTING.md) * [How to Create Good Pull Requests](https://github.com/SharePoint/sp-dev-docs/wiki/How-to-Create-Good-Pull-Requests) -* If you are a Microsoft contributor, please review official guidance from our [internal documentation](https://review.docs.microsoft.com/help/contribute/?branch=master) for docs.microsoft.com contributors +* If you are a Microsoft contributor, please review official guidance from our [internal documentation](https://review.learn.microsoft.com/help/contribute/?branch=main) for Microsoft Docs contributors ## Have Fun diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..e138ec5d6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + diff --git a/assets/ace/URL.txt b/assets/ace/URL.txt new file mode 100644 index 000000000..7d3d66ec3 --- /dev/null +++ b/assets/ace/URL.txt @@ -0,0 +1 @@ +me/events?$select=subject,body,bodyPreview,organizer,attendees,start,end,location \ No newline at end of file diff --git a/assets/ace/calendar-top.png b/assets/ace/calendar-top.png new file mode 100644 index 000000000..d8cb719da Binary files /dev/null and b/assets/ace/calendar-top.png differ diff --git a/assets/ace/email-top.png b/assets/ace/email-top.png new file mode 100644 index 000000000..d9170e95a Binary files /dev/null and b/assets/ace/email-top.png differ diff --git a/assets/ace/events-quick-view.json b/assets/ace/events-quick-view.json new file mode 100644 index 000000000..fb16cb82b --- /dev/null +++ b/assets/ace/events-quick-view.json @@ -0,0 +1,85 @@ +{ + "type": "AdaptiveCard", + "version": "1.5", + "@odata.type": "#microsoft.graph.message", + "body": [ + { + "type": "Container", + "items": [ + { + "type": "Image", + "url": "https://raw.githubusercontent.com/SharePoint/sp-dev-docs/main/assets/ace/calendar-top.png" + }, + { + "type": "TextBlock", + "text": "This control displays the latest calendar events. You can open the event in Outlook or, if it's a meeting, you can join it simply clicking on the button next to the event.", + "wrap": true + } + ] + }, + { + "type": "Container", + "$data": "${value}", + "items": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "${subject}", + "size": "Medium" + }, + { + "type": "TextBlock", + "text": "${location.displayName}", + "spacing": "None" + }, + { + "type": "TextBlock", + "text": "${formatDateTime(substring(start.dateTime,0,19), 'dd/MM/yyyy hh:mm')}-${formatDateTime(substring(end.dateTime,0,19), 'hh:mm')}", + "spacing": "None", + "size": "Small" + } + ] + }, + { + "type": "Column", + "width": "auto", + "items": [ + { + "type": "Image", + "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAvBJREFUSEvtVUtIalEUXdeKiDDIiIY1i7CIBkqRRrNCAqFM6AsRQhMLx5VSVvTBoqwIIqTIoCYV1aBZ/4EDk4gkmgg16iP9cFQaez+89N4zrz148AZvw+XCufectddeZ68tRCKRCP5iCP8MgM/nQ39/P9bX15Gfnw+bzYb6+nokJyfH5Z8Qg0AggObmZqjVarS2tsLr9WJ4eBhjY2PQ6/UMEA6H8fT0BJlMhoyMDAiCwOsJAayuroKehYUFZGZmgmSbm5vD+fk5HA4H3t/f0d3djcnJScjlcvT29sJisTC7hADcbjd2d3cxMzPDB1AsLS3h5OQEExMTODo64kNnZ2dxe3uLnp4eLC4uQqlUQgiHwxGPx4PDw0POJFbc3NzwhunpaTQ0NODy8hKdnZ1cHnqvra2JDB8fH7mcxKy0tBTC/f19pKmpiTP8TnR1dWFwcBDp6emIahQKhUCPRqPB+Pj4Dy0+A9DNqKys/A1nb28PfX190Gq1XIqioiLk5OSIQtKGh4cHbG1tMaBOp+M3i/wZYHl5GcTm1yANiLZCoUBxcTFSUlIkydbW1qK9vf1ngJKSEmRnZ6OmpgZmsxlOpxPb29u4u7vD6ekpCgoKYDQakZaWJgIEg0Fsbm6yHpQABWl2dXUFSiymBtRQVAq73Q6r1SoeVlVVxZuysrLEtajgU1NT3IAUx8fHvPc/AJfjj0pkMpnQ2NiIlZUVzM/Pf1uDg4MDDA0Nfa3BV3cwEZHf3t7YaV9fXzE6OhrfKigTioqKCiQlJXGjkaNGnZK+nZ2dwWAw8A0qKysD2TpZD92g8vLy+GZH7rmzsyO6aCxm9I/L5YJKpcLFxQUKCwu5h/Ly8qTtOuoxpElLSwt7/efw+/1oa2vjA2M5QELzYH9/HwRAndrR0YHc3Fy8vLxgY2MDIyMjqK6uFk0vFkPJeUDDhWxiYGCAx2U0qObU5XV1dUhNTf3SmyQBojsJ6Pn5GdfX1+xXZBdS8zihEknapsQPH6Mh/FGBh+hUAAAAAElFTkSuQmCC", + "selectAction": { + "type": "Action.OpenUrl", + "url": "${onlineMeeting.joinUrl}" + }, + "$when": "${isOnlineMeeting}" + } + ] + }, + { + "type": "Column", + "width": "auto", + "items": [ + { + "type": "Image", + "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAR5JREFUSEvtljGuRFAUhv8rIdGQSHQahc4ORG8PbMICVBZgE+xBL3agU2h0RIJCQsLkSt4kM2/e3Fu8ea+hPef4zvnOjYscx3Hggw95BizLgjAM4boufN/nQmdZhqIokCQJZFl+qCHzPB9pmmIcxzOwbRvyPIdpmrBtmwtQVRWapoHneRBF8axRVRVBEID0fX/QTilAURTs+466rqFpGnRd5wJ0XYdhGGBZFgRBwDRNJ4BOdgdEUQTHcfAbisqyRBzHrwF057QDSZK++fxpHNrUuq6nAUIIXgLoeIZhcClhJbVte2p+UPS1A1YxT/ztDnhewMp5uwNWMU/8AjAtXYouRUwDzIT/OUUf+9g9X5nM+TkT7lfmn/9VcDbInXYDn/BFftWPiLMAAAAASUVORK5CYII=", + "selectAction": { + "type": "Action.OpenUrl", + "url": "${webLink}" + } + } + ] + } + ] + } + ], + "separator": true + } + ], + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json" +} \ No newline at end of file diff --git a/assets/ace/messages-quick-view.json b/assets/ace/messages-quick-view.json new file mode 100644 index 000000000..74e7f40a1 --- /dev/null +++ b/assets/ace/messages-quick-view.json @@ -0,0 +1,84 @@ +{ + "type": "AdaptiveCard", + "version": "1.5", + "@odata.type": "#microsoft.graph.message", + "body": [ + { + "type": "Container", + "items": [ + { + "type": "Image", + "url": "https://raw.githubusercontent.com/SharePoint/sp-dev-docs/main/assets/ace/email-top.png" + }, + { + "type": "TextBlock", + "text": "This control displays the last email message received in your inbox. To view the message, simply click on the button. The message will open directly in Outlook, allowing you to read and respond to it as needed.", + "wrap": true + } + ] + }, + { + "type": "Container", + "$data": "${value}", + "items": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "text": "${from.emailAddress.name}", + "size": "Medium", + "weight": "${if(isRead, 'normal', 'bolder')}" + }, + { + "type": "TextBlock", + "text": "${subject}", + "spacing": "None", + "weight": "${if(isRead, 'normal', 'bolder')}" + } + ] + }, + { + "type": "Column", + "width": "auto", + "items": [ + { + "type": "TextBlock", + "text": "${if(hasAttachments, '📎', '')} ${if(importance == 'normal', '', '❗')} ${if(flag.flagStatus == 'flagged', '🚩', '')}", + "horizontalAlignment": "Right" + }, + { + "type": "TextBlock", + "text": "{{DATE(${sentDateTime}, COMPACT)}} {{TIME(${sentDateTime})}}", + "spacing": "None", + "size": "Small" + } + ], + "verticalContentAlignment": "Center" + }, + { + "type": "Column", + "width": "auto", + "items": [ + { + "type": "Image", + "url": "${if(isRead, 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAY5JREFUSEvt1aGLwlAcB/DvQ2FNg6BFMPg3WDRZRayGLWkxKViUgUkYWgRNKy5psG52kxb/BoOwMtEwTaLwjudxntObb3onHMe9uvH97Pd9vDdCKaV44SK/Btjv9zAMAz6fD5lMBoIgeJqbOwELHo/HaLfbME3zFBqNRlGr1ZDNZrmQK3AZvFqtUKlUUCwWT0C/30e320U4HOZCN4BbcCAQcFSy3W49QWfAa/B18TyIHA4Hqus6Wq0WLqu4/mLejl5D9XoduVwOZL1eU1EUEYlE0Ol0EAqFeFl3n282G1SrVViWheFw+AnMZjMoioJSqQS/3/8UcjweoaoqZFlGMpl0AolEAqPRCOVy+SnkI7zX6yGfz2M+nzuBRqMBttFsgkeRy3A2ATuEzWbzFmBjTSYTFAoFLJfLh2qKxWLQNA3pdBqs7i+BVCoFdvctFovzqfWqsNMdj8dBCMF0OnUHvAbee+8f4Lb4RyuybRuPXnBuXbGLLxgMvh+03W5HB4MBGPCTiwGSJIH7y/wu+nLgDSewZ7NrDNFAAAAAAElFTkSuQmCC', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAARBJREFUSEvtlS2qhUAYhl+LRbALYhMsrsAF2MXmLhRsJpugu7CJ3QW4AotgE8EiBsFimYNevJxz8Th6YZpThpnv55nvnT+OEELAsHEPgKYue4nGcSS+76NtW9pibtkVRUEUReCGYSCO46Cua6y9KIq3Ev11nqYJaZpC07St/wUURQFd1+F5HmzbhiAIt0DzPCPLMsRxjKqqYJrmJ8B1XfR9vzms7SroPfEeJ0kSkiT5BARBAMMwcBRwVNGZX1mWCMPwGLDr8i3Bat+l+FbpJcARaFmWbZrn+VMJbwHeQXmeb0PLsk4Pwb8Ad47UA6CqdSiRqqqQZZkafMWh6zo0TfNzD5g/ds+PRtsT9j8a6z14AbwnH7bn+xIdAAAAAElFTkSuQmCC')}", + "selectAction": { + "type": "Action.OpenUrl", + "url": "${webLink}" + } + } + ] + } + ] + } + ], + "separator": true + } + ], + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json" +} \ No newline at end of file diff --git a/assets/bot-powered/Media/Collect-Feedback.png b/assets/bot-powered/Media/Collect-Feedback.png new file mode 100644 index 000000000..16aecc8a0 Binary files /dev/null and b/assets/bot-powered/Media/Collect-Feedback.png differ diff --git a/assets/bot-powered/Media/Ok-Feedback.png b/assets/bot-powered/Media/Ok-Feedback.png new file mode 100644 index 000000000..ea5aa3a3b Binary files /dev/null and b/assets/bot-powered/Media/Ok-Feedback.png differ diff --git a/assets/bot-powered/TeamsAppManifest/icon-color.png b/assets/bot-powered/TeamsAppManifest/icon-color.png new file mode 100644 index 000000000..b8cf81afb Binary files /dev/null and b/assets/bot-powered/TeamsAppManifest/icon-color.png differ diff --git a/assets/bot-powered/TeamsAppManifest/icon-outline.png b/assets/bot-powered/TeamsAppManifest/icon-outline.png new file mode 100644 index 000000000..2c3bf6fa6 Binary files /dev/null and b/assets/bot-powered/TeamsAppManifest/icon-outline.png differ diff --git a/assets/bot-powered/TeamsAppManifest/manifest.json b/assets/bot-powered/TeamsAppManifest/manifest.json new file mode 100644 index 000000000..7a502770d --- /dev/null +++ b/assets/bot-powered/TeamsAppManifest/manifest.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.14/MicrosoftTeams.schema.json", + "manifestVersion": "1.16", + "version": "1.0.0", + "id": "", + "packageName": "collectfeedback.botpoweredace", + "developer": { + "name": "", + "websiteUrl": "", + "privacyUrl": "", + "termsOfUseUrl": "", + "mpnId": "" + }, + "name": { + "short": "Collect Feedaback Bot Powered ACE", + "full": "This is a basic sample of a Bot Powered ACE for Microsoft Viva Connections Dashboard to collect user's feedback" + }, + "description": { + "short": "Basic sample of a Bot Powered ACE for Microsoft Viva Connections Dashboard to collect user's feedback", + "full": "Basic sample of how to use the latest release of the Bot Framework SDK to build a Bot Powered ACE for Microsoft Viva Connections Dashboard to collect user's feedback" + }, + "icons": { + "outline": "icon-outline.png", + "color": "icon-color.png" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "", + "needsChannelSelector": false, + "isNotificationOnly": false, + "supportsCalling": false, + "supportsVideo": false, + "supportsFiles": false, + "scopes": [ + "team", + "personal", + "groupchat" + ] + } + ], + "dashboardCards": [ + { + "id": "", + "displayName": "Collect Feedaback", + "description": "Bot Powered ACE to collect user's feedback", + "icon": { + "officeUIFabricIconName": "Feedback" + }, + "contentSource": { + "sourceType": "bot", + "botConfiguration": { + "botId": "" + } + }, + "defaultSize": "medium" + } + ], + "permissions": [ + "identity" + ], + "validDomains": [ + ".ngrok.io" + ] +} \ No newline at end of file diff --git a/assets/spfx/spfx-matrix.json b/assets/spfx/spfx-matrix.json new file mode 100644 index 000000000..66ddda059 --- /dev/null +++ b/assets/spfx/spfx-matrix.json @@ -0,0 +1,545 @@ +[ + { + "spfx": "1.21.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.21.1", + "node": [ + "v22" + ], + "typescript": [ + "v5.3" + ], + "react": [ + "v17.0.1" + ] + }, + { + "spfx": "1.21.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.21", + "node": [ + "v22" + ], + "typescript": [ + "v5.3" + ], + "react": [ + "v17.0.1" + ] + }, + { + "spfx": "1.20.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.20", + "node": [ + "v18" + ], + "typescript": [ + "v4.5", + "v4.7" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2024-09-26" + }, + { + "spfx": "1.19.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.19", + "node": [ + "v18" + ], + "typescript": [ + "v4.5", + "v4.7" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2024-05-01" + }, + { + "spfx": "1.18.2", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.18.2", + "node": [ + "v16", + "v18" + ], + "typescript": [ + "v4.5", + "v4.7" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2023-11-21" + }, + { + "spfx": "1.18.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.18.1", + "node": [ + "v16", + "v18" + ], + "typescript": [ + "v4.5", + "v4.7" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2023-11-07" + }, + { + "spfx": "1.18", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.18", + "node": [ + "v16", + "v18" + ], + "typescript": [ + "v4.5", + "v4.7" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2023-09-12" + }, + { + "spfx": "1.17.4", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.17.4", + "node": [ + "v16.13+" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v17.0.1" + ] + }, + { + "spfx": "1.17.3", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.17.3", + "node": [ + "v16.13+" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2023-06-21" + }, + { + "spfx": "1.17.2", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.17.2", + "node": [ + "v16.13+" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2023-05-08" + }, + { + "spfx": "1.17.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.17.1", + "node": [ + "v16.13+" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2023-04-12" + }, + { + "spfx": "1.17.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.17", + "node": [ + "v16.13+" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2023-04-04" + }, + { + "spfx": "1.16.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.16.1", + "node": [ + "v16.13+" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2022-11-30" + }, + { + "spfx": "1.16.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.16", + "node": [ + "v16.13+" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v17.0.1" + ], + "releaseDate": "2022-11-15" + }, + { + "spfx": "1.15.2", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.15.2", + "node": [ + "v12", + "v14", + "v16" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v16.13.1" + ], + "releaseDate": "2022-08-02" + }, + { + "spfx": "1.15.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.15", + "node": [ + "v12", + "v14", + "v16" + ], + "typescript": [ + "v4.5" + ], + "react": [ + "v16.13.1" + ], + "releaseDate": "2022-06-21" + }, + { + "spfx": "1.14.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.14", + "node": [ + "v12", + "v14" + ], + "typescript": [ + "v3.9" + ], + "react": [ + "v16.13.1" + ], + "releaseDate": "2022-02-17" + }, + { + "spfx": "1.13.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.13.1", + "node": [ + "v12", + "v14" + ], + "typescript": [ + "v3.9" + ], + "react": [ + "v16.13.1" + ], + "releaseDate": "2021-11-23" + }, + { + "spfx": "1.13.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.13", + "node": [ + "v12", + "v14" + ], + "typescript": [ + "v3.9" + ], + "react": [ + "v16.13.1" + ], + "releaseDate": "2021-10-21" + }, + { + "spfx": "1.12.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.12.1", + "node": [ + "v10", + "v12", + "v14" + ], + "typescript": [ + "v3.7" + ], + "react": [ + "v16.9.0" + ], + "releaseDate": "2021-04-28" + }, + { + "spfx": "1.12.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.12.0", + "node": [ + "v12", + "v10" + ], + "typescript": [ + "v3.7" + ], + "react": [ + "v16.9.0" + ], + "deprecated": true, + "releaseDate": "2021-03-15" + }, + { + "spfx": "1.11.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.11.0", + "node": [ + "v10" + ], + "typescript": [ + "v3.3" + ], + "react": [ + "v16.8.5" + ] + }, + { + "spfx": "1.10.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.10.0", + "node": [ + "v8", + "v10" + ], + "typescript": [ + "v3.3" + ], + "react": [ + "v16.8.5" + ], + "releaseDate": "2020-07-16" + }, + { + "spfx": "1.9.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.9.1", + "node": [ + "v8", + "v10" + ], + "typescript": [ + "v2.9" + ], + "react": [ + "v16.8.5" + ], + "releaseDate": "2019-08-14" + }, + { + "spfx": "1.8.2", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.8.2", + "node": [ + "v8", + "v10" + ], + "typescript": [ + "v2.9" + ], + "react": [ + "v16.7.0" + ], + "releaseDate": "2019-05-07" + }, + { + "spfx": "1.8.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.8.1", + "node": [ + "v8" + ], + "typescript": [ + "v2.7", + "v2.9", + "v3" + ], + "react": [ + "v16.7.0" + ], + "releaseDate": "2019-04-16" + }, + { + "spfx": "1.8.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.8.0", + "node": [ + "v8" + ], + "typescript": [ + "v2.7", + "v2.9", + "v3" + ], + "react": [ + "v16.7.0" + ], + "releaseDate": "2019-03-14" + }, + { + "spfx": "1.7.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.7.1", + "node": [ + "v8" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v16.3.2" + ], + "releaseDate": "2018-12-18" + }, + { + "spfx": "1.7.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.7", + "node": [ + "v8" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v16.3.2" + ], + "releaseDate": "2018-11-08" + }, + { + "spfx": "1.6.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.6", + "node": [ + "v6", + "v8" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ] + }, + { + "spfx": "1.5.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.5.1", + "node": [ + "v6", + "v8" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ], + "releaseDate": "2018-06-26" + }, + { + "spfx": "1.5.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.5", + "node": [ + "v6", + "v8" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ], + "releaseDate": "2018-06-05" + }, + { + "spfx": "1.4.1", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.4.1", + "node": [ + "v6", + "v8" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ], + "releaseDate": "2018-02-18" + }, + { + "spfx": "1.4.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.4", + "node": [ + "v6" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ], + "releaseDate": "2017-12-07" + }, + { + "spfx": "1.3.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.3", + "node": [ + "v6" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ], + "releaseDate": "2017-08-25" + }, + { + "spfx": "1.1.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.1", + "node": [ + "v6" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ], + "releaseDate": "2017-06-06" + }, + { + "spfx": "1.0.0", + "url": "https://learn.microsoft.com/sharepoint/dev/spfx/release-1.0.0", + "node": [ + "v6" + ], + "typescript": [ + "v2.4" + ], + "react": [ + "v15" + ], + "releaseDate": "2017-02-22" + } +] \ No newline at end of file diff --git a/assets/vc-backgrounds/01_Teal.png b/assets/vc-backgrounds/01_Teal.png new file mode 100644 index 000000000..98158b37b Binary files /dev/null and b/assets/vc-backgrounds/01_Teal.png differ diff --git a/assets/vc-backgrounds/02_Blue.png b/assets/vc-backgrounds/02_Blue.png new file mode 100644 index 000000000..a9c23fb91 Binary files /dev/null and b/assets/vc-backgrounds/02_Blue.png differ diff --git a/assets/vc-backgrounds/03_Orange.png b/assets/vc-backgrounds/03_Orange.png new file mode 100644 index 000000000..8e811de8f Binary files /dev/null and b/assets/vc-backgrounds/03_Orange.png differ diff --git a/assets/vc-backgrounds/04_Red.png b/assets/vc-backgrounds/04_Red.png new file mode 100644 index 000000000..b42888406 Binary files /dev/null and b/assets/vc-backgrounds/04_Red.png differ diff --git a/assets/vc-backgrounds/05_Purple.png b/assets/vc-backgrounds/05_Purple.png new file mode 100644 index 000000000..888e21a84 Binary files /dev/null and b/assets/vc-backgrounds/05_Purple.png differ diff --git a/assets/vc-backgrounds/06_Green.png b/assets/vc-backgrounds/06_Green.png new file mode 100644 index 000000000..494d7dd31 Binary files /dev/null and b/assets/vc-backgrounds/06_Green.png differ diff --git a/assets/vc-backgrounds/07_Gray.png b/assets/vc-backgrounds/07_Gray.png new file mode 100644 index 000000000..3ec725883 Binary files /dev/null and b/assets/vc-backgrounds/07_Gray.png differ diff --git a/assets/vc-backgrounds/08_Periwinkle.png b/assets/vc-backgrounds/08_Periwinkle.png new file mode 100644 index 000000000..23b6fa00a Binary files /dev/null and b/assets/vc-backgrounds/08_Periwinkle.png differ diff --git a/assets/vc-backgrounds/09_Black.png b/assets/vc-backgrounds/09_Black.png new file mode 100644 index 000000000..4a1837aa9 Binary files /dev/null and b/assets/vc-backgrounds/09_Black.png differ diff --git a/assets/vc-backgrounds/10_Cerulean.png b/assets/vc-backgrounds/10_Cerulean.png new file mode 100644 index 000000000..86c8be663 Binary files /dev/null and b/assets/vc-backgrounds/10_Cerulean.png differ diff --git a/assets/vc-backgrounds/11_Cobalt.png b/assets/vc-backgrounds/11_Cobalt.png new file mode 100644 index 000000000..a2f354798 Binary files /dev/null and b/assets/vc-backgrounds/11_Cobalt.png differ diff --git a/assets/vc-backgrounds/12_Dark Yellow.png b/assets/vc-backgrounds/12_Dark Yellow.png new file mode 100644 index 000000000..224126c84 Binary files /dev/null and b/assets/vc-backgrounds/12_Dark Yellow.png differ diff --git a/assets/vc-backgrounds/13_Dark Blue.png b/assets/vc-backgrounds/13_Dark Blue.png new file mode 100644 index 000000000..f38b33e1f Binary files /dev/null and b/assets/vc-backgrounds/13_Dark Blue.png differ diff --git a/assets/vc-backgrounds/14_Custom_Color.png b/assets/vc-backgrounds/14_Custom_Color.png new file mode 100644 index 000000000..624e7605d Binary files /dev/null and b/assets/vc-backgrounds/14_Custom_Color.png differ diff --git a/assets/vc-backgrounds/15_Hero_Connections_Dark.png b/assets/vc-backgrounds/15_Hero_Connections_Dark.png new file mode 100644 index 000000000..90cf818b5 Binary files /dev/null and b/assets/vc-backgrounds/15_Hero_Connections_Dark.png differ diff --git a/docs/apis/addin-management-apis.md b/docs/apis/addin-management-apis.md new file mode 100644 index 000000000..f5cab6571 --- /dev/null +++ b/docs/apis/addin-management-apis.md @@ -0,0 +1,346 @@ +--- +title: SharePoint Add-in related APIs +description: We provided some Add-in related APIs to get Add-in's installation info and uninstall the Add-in. +audience: admin +ms.date: 03/25/2023 +ms.localizationpriority: medium +--- + +# SharePoint Add-in Management APIs + +This documentation will introduce some APIs which related to SharePoint Add-ins. They could help to have a clear view +and better management of the Add-ins in tenant level, including these: + +- Get available Add-ins in sites +- Get Add-in permissions in site collections +- Get tenant ACS service principals +- Get Add-in principals in site collections +- Uninstall Add-ins +- Get uninstall Add-in job status + +For more information about SharePoint Add-in, see [SharePoint Add-ins](../sp-add-ins/sharepoint-add-ins.md). + +## Prerequisites + +- App-only mode token. [Get token example](https://github.com/pnp/pnpcore/blob/dev/docs/polyglot/Getting%20started%20-%20application%20permissions.ipynb) +- Called on the admin site. Example: https://www.contoso-admin.sharepoint.com +- For uninstall Add-in API, the app needs to have Sites.FullControl.All permission. For others, the app needs at least Sites.Read.All permission. + +## Get available Add-ins in sites + +This API will return the Add-ins that could be used on the given sites. This contains two kinds of install, one is the Add-in installed on the site. +The other is the Add-in installed on the tenant level app catalog site, and it matches the conditions to use the Add-in. +For more information, see [Tenancies and deployment scopes for SharePoint Add-ins](../sp-add-ins/tenancies-and-deployment-scopes-for-sharepoint-add-ins.md). + +This API needs the app to have at least Sites.Read.All permission. + +### HTTP request + +```HTTP +POST {adminSiteUrl}/_api/web/AvailableAddIns +``` + +### Request body + +| Name | Required | Type | Description | +|--------------------|----------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------| +| serverRelativeUrls | no | string[] | List of the server relative url of sites that want to get the available Add-ins. Maximum size is 500. | +| urls | no | string[] | List of the url of sites that want to get the available Add-ins, both server relative url and absolute url are acceptable. Maximum size is 500. | + +When urls is not null, serverRelativeUrls will be disregarded. + +### Responses + +| Name | Type | Description | +|-----------------------------|--------------------------------|--------------------------------------------------------------------------------------| +| addins | SPAddinInstanceInfo[] | Available Add-in instance object. | +| errorsWithServerRelativeUrl | SPErrorWithServerRelativeUrl[] | Server relative urls that failed to get available add-ins and corresponding reasons. | + +#### SPAddinInstanceInfo + +| Name | Type | Description | +|-------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| title | string | Title of the Add-in. | +| appInstanceId | Guid | Id of the installation. | +| launchUrl | String | The Add-in's launch page address. | +| installedSiteId | Guid | Site collection id where the Add-in installed. | +| installedWebId | Guid | Site id where the Add-in installed. | +| installedWebName | string | Site name where the Add-in installed. | +| installedWebUrl | string | Site url where the Add-in installed. | +| currentSiteId | Guid | Site collection id of current site. | +| currentWebId | Guid | Site id of current site. | +| currentWebName | string | Site name of current site. | +| currentWebUrl | string | Site url of current site. | +| status | string | The status of current Add-in. | +| appWebFullUrl | string | The full url of the app web. The SharePoint components are generally in a special child web of the host web called the app web. The app web will be created during install the add-in. | +| appWebId | Guid | Id of the app web. | +| appWebName | string | Name of the app web. | +| installedBy | string | User name of who installed the add-in. | +| appIdentifier | string | The identifier of the app principal. It could be used to get the Add-in's permission. | +| creationTimeUtc | DateTime | Date time when installed the add-in. | +| productId | Guid | The global unique id of the add-in. It is same for all tenants. | +| assetId | string | The id of the app in the office store, this will be empty for app catalog user uploaded apps. | +| purchaserIdentity | string | The identify of person who bought the license of the add-in. | +| licensePurchaseTime | DateTime | When purchased the app license. | +| locale | string | which locale installed on the site. | +| appSource | string | Indicate where the app come from. | +| tenantAppData | string | After the Add-in installed in the tenant app catalog site. It could enable tenant level usage. This data indicates the conditions how to filter the sites. If this field is not empty, it means this Add-in installed on tenant app catalog site, deployed to tenant level, and current site matches the conditions. For more information, see [Tenancies and deployment scopes for SharePoint Add-ins](../sp-add-ins/tenancies-and-deployment-scopes-for-sharepoint-add-ins.md). | +| tenantAppDataUpdateTime | DateTime | The tenant app data update time. | + +### SPErrorWithServerRelativeUrl + +| Name | Type | Description | +|-------------------|--------|--------------------------------------------------------| +| serverRelativeUrl | string | The serverRelativeUrl or url in the request body. | +| errorMessage | string | The error message why fetch the site's Add-ins failed. | + +## Get Add-in permissions in site collections + +This API will return the permissions that were granted to the add-in. For more information, see [Add-in permissions in SharePoint](../sp-add-ins/add-in-permissions-in-sharepoint.md). + +This API needs the app to have at least Sites.Read.All permission. + +### HTTP request + +```HTTP +POST {adminSiteUrl}/_api/web/AddinPermissions +``` + +### Request body + +| Name | Required | Type | Description | +|--------|----------|----------------------------|----------------------------------------------------------------------------------| +| addins | yes | SPAddinPermissionRequest[] | List of the Add-in that want to get the permissions. Maximum Add-in size is 500. | + +#### SPAddinPermissionRequest + +| Name | Type | Description | +|-------------------|----------|-------------------------------------------------------------------------------------------| +| serverRelativeUrl | string | The server relative url of the site collection. | +| url | string | The url of the site collection, both server relative url and absolute url are acceptable. | +| appIdentifiers | string[] | The identifier list of the Add-ins. | + +The serverRelativeUrl and url can't be both null. If both serverRelativeUrl and url are provided, the url will be used. + +### Responses +| Name | Type | Description | +|------------------|-------------------------------|-----------------------------------------------------------------------| +| addinPermissions | SPAddinPermissionInfo[] | The returned permissions. | +| failedAddins | SPAddinPermissionFailedInfo[] | The Add-ins that failed to get permissions and corresponding reasons. | + +#### SPAddinPermissionInfo + +| Name | Type | Description | +|---------------------------------|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| tenantScopedPermissions | SPTenantScopedPermissionInfo[] | This is the permissions grant in tenant scope level. | +| siteCollectionScopedPermissions | SPSiteCollectionScopedPermissionInfo[] | This is the permissions grant in site collection scope level. | +| appIdentifier | string | The identifier of the Add-in. | +| serverRelativeUrl | string | The server relative url of the site collection. | +| absoluteUrl | string | The absolute url of the site collection. | +| allowAppOnly | bool | This identifies if the Add-in allows app only mode. For more information, see [Add-in authorization policy types in SharePoint](../sp-add-ins/add-in-authorization-policy-types-in-sharepoint.md). | + +#### SPTenantScopedPermissionInfo + +| Name | Type | Description | +|---------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| feature | string | The feature name of the permissions, it should be one of these:
  • Taxonomy
  • Social
  • ProjectServer
  • Search
  • BcsConnection
  • Content
| +| scope | string | The scope of the permission. | +| right | string | The right of the permission. | +| id | Guid | The id of the resource that the Add-in have permission to. For example, it may be the id of one specific project when the feature is ProjectServer and the scope is projectserver/projects/project. | + + +#### SPSiteCollectionScopedPermissionInfo + +| Name | Type | Description | +|--------|--------|------------------------------------------------------------------------------------------------------------------------------------------------| +| siteId | Guid | The site collection id which the Add-in has access to. | +| webId | Guid | The site id which the Add-in has access to. If this field is empty, then the permission grant in site collection level. | +| listId | Guid | The list id which the Add-in has access to. If this field is empty, then the permission grant in site collection level or grant is site level. | +| right | string | Available rights: Guest, Read, Write, Manage, FullControl. | + + +#### SPAddinPermissionFailedInfo + +| Name | Type | Description | +|-------------------|--------|-----------------------------------------------------------------| +| serverRelativeUrl | string | The server relative url or absolute url of the site collection. | +| appIdentifier | string | The identifier list of the Add-in. | +| errorMessage | string | The error message why fetch the Add-in permission failed. | + +## Get tenant ACS service principals + +This API takes the app id list as input, it will filter the ones that present ACS service principals. +For more information, see [Register SharePoint Add-ins](../sp-add-ins/register-sharepoint-add-ins.md). + +This API needs the app to have at least Sites.Read.All permission. + +### HTTP request + +```HTTP +POST {adminSiteUrl}/_api/web/GetACSServicePrincipals +``` + +### Request body + +| Name | Required | Type | Description | +|--------|----------|--------|------------------------------------| +| appIds | yes | Guid[] | List app ids. Maximum size is 500. | + +### Responses + +| Name | Type | Description | +|------|-----------------------------|-------------------------------------| +| | SPACSServicePrincipalInfo[] | The SPACSServicePrincipalInfo list. | + +#### SPACSServicePrincipalInfo + +| Name | Type | Description | +|---------------|----------|-----------------------------------------------------------------------------------------------| +| appIdentifier | string | The app identifier of the Add-in. | +| appId | Guid | The app id of the Add-in. | +| title | string | A user friendly title. | +| redirectUri | string | The endpoint in your remote application or service to which ACS sends an authentication code. | +| appDomains | string[] | The host name of the remote component of the SharePoint Add-in. | + +## Get Add-in principals in site collections + +This API takes the site collections' server relative url as input, it will return the Add-in principals that have permissions in given sites. + +This API needs the app to have at least Sites.Read.All permission. + +### HTTP request + +```HTTP +POST {adminSiteUrl}/_api/web/GetAddinPrincipalsHavingPermissionsInSites +``` + +### Request body + +| Name | Required | Type | Description | +|--------------------|----------|----------|------------------------------------------------------------------------------------------------------------| +| serverRelativeUrls | no | string[] | List site collections' server relative url. Maximum size is 500. | +| urls | no | string[] | List site collections' url, both server relative url and absolute url are acceptable. Maximum size is 500. | + +When urls is not null, serverRelativeUrls will be disregarded. + +### Responses + +| Name | Type | Description | +|-----------------------------|--------------------------------|-------------| +| addinPrincipals | SPAddinPrincipalInfo[] | | +| errorsWithServerRelativeUrl | SPErrorWithServerRelativeUrl[] | | + +#### SPAddinPrincipalInfo + +| Name | Type | Description | +|-------------------|--------|-------------------------------------------------| +| title | string | The title of the Add-in. | +| appIdentifier | string | The app identifier. | +| serverRelativeUrl | string | The server relative url of the site collection. | +| absoluteUrl | string | The absolute url of the site collection. | + + +#### SPErrorWithServerRelativeUrl + +| Name | Type | Description | +|-------------------|--------|------------------------------------------------------------| +| serverRelativeUrl | string | The site collection's server relative url or absolute url. | +| errorMessage | string | The error message why fetch the Add-in principal failed. | + +## Uninstall Add-ins + +This API will trigger an async job to uninstall the Add-in. If the job triggered successfully, the job id will be returned. + +This API needs the app to have Sites.FullControl.All permission. + +### HTTP request + +```HTTP +POST {adminSiteUrl}/_api/web/UninstallAddins +``` + +### Request body + +| Name | Required | Type | Description | +|-----------------|----------|---------------------------|---------------------------------------------------------------| +| uninstallAddins | yes | SPUninstallAddinRequest[] | List of Add-ins need to uninstall. Maximum Add-in size is 50. | + +#### SPUninstallAddinRequest + +| Name | Type | Description | +|-------------------|--------|---------------------------------------------------------------------------| +| serverRelativeUrl | string | The site's server relative url. | +| url | string | The site's url, both server relative url and absolute url are acceptable. | +| appInstanceIds | Guid[] | The instance ids of the Add-ins. | + +The serverRelativeUrl and url can't be both null. If both serverRelativeUrl and url are provided, the url will be used. + +### Responses + +| Name | Type | Description | +|-----------|--------------------------------------------|---------------------------------------------------------------------------| +| executing | SPTriggeredUninstallAddinJobResponse[] | This field contains the ones that successed to trigger the uninstall job. | +| failed | SPFailToTriggerUninstallAddinJobResponse[] | This field contains the ones that failed to trigger the uninstall job. | + +#### SPTriggeredUninstallAddinJobResponse + +| Name | Type | Description | +|-------------------|--------|---------------------------------| +| appInstanceId | Guid | The instance id of the Add-in. | +| serverRelativeUrl | string | The site's server relative url. | +| absoluteUrl | string | The site's absolute url. | +| uninstallJobId | Guid | The triggered uninstall job id. | + +#### SPFailToTriggerUninstallAddinJobResponse + +| Name | Type | Description | +|-------------------|--------|---------------------------------------------------------| +| appInstanceId | Guid | The instance id of the Add-in. | +| serverRelativeUrl | string | The site's server relative url. | +| errorMessage | Guid | The error message why the uninstall job trigger failed. | + + +## Get uninstall Add-in job status + +Since the uninstall Add-in is an async process, this API will provide the ability to check if the uninstall ends successfully. +If the job ends successfully, then the job will be not found. If the job ends with failure, then it will return the error detail. + +This API needs the app to have at least Sites.Read.All permission. + +### HTTP request + +```HTTP +POST {adminSiteUrl}/_api/web/GetAddinUninstallJobDetail +``` + +### Request body + +| Name | Required | Type | Description | +|-------------------|----------|--------|----------------------------------------------------------------------------| +| jobId | yes | Guid | This uninstall job id. | +| serverRelativeUrl | no | string | The site's server relative url. | +| url | no | string | The site's url, both server relative url and absolute url are acceptable. | + +The serverRelativeUrl and url can't be both null. If both serverRelativeUrl and url are provided, the url will be used. + +### Responses + +| Name | Type | Description | +|-------------------|-------------------------------|--------------------------------------------------| +| serverRelativeUrl | string | The site's server relative url. | +| absoluteUrl | string | The site's absolute url. | +| taskStartTime | DateTime | The time when the task starts executing. | +| jobId | Guid | The uninstall job id. | +| siteId | Guid | The site collection id. | +| appInstanceId | Guid | The id of the app instance. | +| errorDetails | SPUninstallAddinErrorDetail[] | The error details for the job ends with failure. | + +#### SPUninstallAddinErrorDetail + +| Name | Type | Description | +|------------------|--------|-------------------------------------| +| detail | string | The error detail. | +| exceptionMessage | string | The exception message of the error. | +| source | string | The source of the error. | +| type | string | The type of the error. | +| correlationId | Guid | The job's correlation id. | diff --git a/docs/apis/alm-api-for-spfx-add-ins.md b/docs/apis/alm-api-for-spfx-add-ins.md index 3429dd395..41afaff9a 100644 --- a/docs/apis/alm-api-for-spfx-add-ins.md +++ b/docs/apis/alm-api-for-spfx-add-ins.md @@ -1,10 +1,10 @@ --- title: Application Lifecycle Management (ALM) APIs description: ALM APIs provide simple APIs to manage deployment of your SharePoint Framework solutions and add-ins across your tenant. -ms.date: 09/07/2020 -ms.prod: sharepoint +ms.date: 06/28/2022 +ms.subservice: migration-tool ms.assetid: fdf7ecb2-8851-425b-b058-3285fba77b68 -localization_priority: Priority +ms.localizationpriority: high --- # Application Lifecycle Management (ALM) APIs @@ -28,7 +28,7 @@ ALM APIs can be used to perform exactly the same operations that are available f ALM APIs are supported for the tenant-scoped site collections and [site collection app catalog](../general-development/site-collection-app-catalog.md). Use the corresponding app catalog's URL to target a specific app catalog. You must first enabled a site collection app catalog before targeting it with the actions documented on this page. > [!IMPORTANT] -> Tenant-scoped permissions which require [tenant administrative approval](https://docs.microsoft.com/sharepoint/dev/solution-guidance/how-to-provide-add-in-app-only-tenant-administrative-permissions-in-sharepoint-online) are not supported with the ALM APIs. +> Tenant-scoped permissions which require [tenant administrative permissions](../solution-guidance/how-to-provide-add-in-app-only-tenant-administrative-permissions-in-sharepoint-online.md) are not supported with the ALM APIs. ## Options for working with ALM APIs @@ -42,12 +42,12 @@ The app catalog must be included in all HTTP requests when using the REST API as For example: -| Scope | Endpoint | -| :-------------- | :--------------------------------------------------------------------------------------------- | -| tenant | **https://contoso.sharepoint.com/sites/AppCatalog/_api/web/tenantappcatalog/{command}** | -| site collection | **https://contoso.sharepoint.com/sites/Marketing/_api/web/sitecollectionappcatalog/{command}** | +| Scope | Endpoint | +| :-------------- | :------------------------------------------------------------------------------------------- | +| tenant | `https://contoso.sharepoint.com/sites/AppCatalog/_api/web/tenantappcatalog/{command}` | +| site collection | `https://contoso.sharepoint.com/sites/Marketing/_api/web/sitecollectionappcatalog/{command}` | -- when targeting the tenant app catalog located at **https://contoso.sharepoint.com/sites/AppCatalog**, the endpoint would be ** +- when targeting the tenant app catalog located at `https://contoso.sharepoint.com/sites/AppCatalog`, the endpoint would be ** Learn more here: [SharePoint REST API](../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) @@ -57,7 +57,7 @@ The PnP CSOM implements the ALM APIs by calling the SharePoint REST API. Before using any of the ALM APIs in PnP CSOM, you need to obtain an authenticated client context using the [Microsoft.SharePointOnline.CSOM](https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM). Then use the authenticated client context to get an instance of the PnP CSOM's **AppManager** object to call the ALM commands: -```cs +```csharp using Microsoft.SharePoint.Client; using OfficeDevPnP.Core.ALM; @@ -72,7 +72,7 @@ using (var context = new ClientContext(webURL)) { In all PnP Core methods, it's assumed the request targets the tenant app catalog in the tenant you connect to using the SharePoint CSOM `ClientContext` object. you can override the scope of all commands with an optional scope argument, for example -```cs +```csharp appManager.Install('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx', AppCatalogScope.Site); ``` @@ -128,7 +128,7 @@ Byte array of the file # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp // read file var filePath = "c:\path\to\file\sharepoint-solution-package.sppkg"; // get an instance of the PnP CSOM's AppManager as shown above @@ -141,7 +141,7 @@ var result = appManager.Add(filePath); Add-PnPApp -Path ./sharepoint-solution-package.sppkg ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/add-pnpapp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Add-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -190,7 +190,7 @@ POST /_api/web/{scope}appcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx- # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp appManager.Deploy('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') ``` @@ -200,7 +200,7 @@ appManager.Deploy('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') Publish-PnPApp -Identity xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/Publish-PnPApp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Publish-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -237,7 +237,7 @@ POST /_api/web/{scope}appcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx- # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp // get an app package appManager.Retract('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') ``` @@ -248,7 +248,7 @@ appManager.Retract('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') Unpublish-PnPApp -Identity xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/Unpublish-PnPApp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Unpublish-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -274,7 +274,7 @@ POST /_api/web/{scope}appcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx- # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp appManager.Remove('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') ``` @@ -284,7 +284,7 @@ appManager.Remove('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') Remove-PnPApp -Identity xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/Remove-PnPApp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Remove-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -357,7 +357,7 @@ GET /_api/web/{scope}appcatalog/AvailableApps # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp var allAppPackages = appManager.GetAvailable(); ``` @@ -367,7 +367,7 @@ var allAppPackages = appManager.GetAvailable(); Get-PnPApp ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/Get-PnPApp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Get-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -419,7 +419,7 @@ GET /_api/web/{scope}appcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-x # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp var appPackage = appManager.GetAvailable('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx'); ``` @@ -463,7 +463,7 @@ POST /_api/web/{scope}appcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx- # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp // get an app package appManager.Install('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') ``` @@ -474,7 +474,7 @@ appManager.Install('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') Install-PnPApp -Identity xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/Install-PnPApp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Install-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -508,7 +508,7 @@ POST /_api/web/{scope}appcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx- # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp // get an app package var appPackage = appManager.GetAvailable('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx'); if (appPackage.CanUpgrade) { @@ -522,7 +522,7 @@ if (appPackage.CanUpgrade) { Update-PnPApp -Identity xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/update-pnpapp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Update-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -559,7 +559,7 @@ POST /_api/web/{scope}appcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx- # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp appManager.Uninstall('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') ``` @@ -569,7 +569,7 @@ appManager.Uninstall('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') Uninstall-PnPApp -Identity xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/Uninstall-PnPApp) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Uninstall-PnPApp.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) @@ -603,7 +603,7 @@ POST /_api/web/{scope}appcatalog/SyncSolutionToTeams(id=xxxxx) # [PnP CSOM](#tab/pnpcsom) -```cs +```csharp appManager.SyncToTeams('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') ``` @@ -613,7 +613,7 @@ appManager.SyncToTeams('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx') Sync-PnPAppToTeams -Identity xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx ``` -> Refer to the [PnP PowerShell documentation](/powershell/module/sharepoint-pnp/sync-pnpapptoteams) for complete details and examples on this cmdlet. +> Refer to the [PnP PowerShell documentation](https://pnp.github.io/powershell/cmdlets/Sync-PnPAppToTeams.html) for complete details and examples on this cmdlet. # [CLI for Microsoft 365](#tab/o365cli) diff --git a/docs/apis/amr-api-reference.md b/docs/apis/amr-api-reference.md new file mode 100644 index 000000000..2c3e44aa8 --- /dev/null +++ b/docs/apis/amr-api-reference.md @@ -0,0 +1,253 @@ +--- +title: "SharePoint Asynchronous Metadata Read (AMR) API Reference Guide" +description: "This article provides in-depth information on how to use the SharePoint AMR API." +ms.date: 04/18/2024 +ms.author: ranren +author: underreview +manager: dapodean +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- +# SharePoint Asynchronous Metadata Read (AMR) API Reference Guide + +Use this document as the guide when using SharePoint Asynchronous Metadata Read (AMR) API. + +AMR API aggregates SharePoint metadata into a manifest package. Use the package for incremental migration, structure creation, post-migration validation, or permission management. + +## CSOM and REST + +AMR API supports both SharePoint Client Side Object Model (CSOM) and REST. + +### Use NuGet Packages with CSOM + +To reference the SharePoint Client Side Object Model (CSOM) in your solution, use NuGet packages. + +Manage dependencies easily and ensure your solution is using the latest version of the CSOM library with NuGet packages. + +Get the latest version of the CSOM package at the [SharePoint Client-side Object Model Libraries](https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM) with the ID `Microsoft.SharePointOnline.CSOM`. + +Check [Get to know SharePoint REST service](/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service) for instructions on REST API. + +## CreateSPAsyncReadJob method + +Creates an AMR job to read all the metadata of the specified SharePoint URL and its children into the specified manifest container. + +### CreateSPAsyncReadJob syntax + +```csharp +public SPAsyncReadJobInfo CreateSPAsyncReadJob(String url, +SPAsyncReadOptions readOptions, +EncryptionOption encryptionOption, +string azureContainerManifestUri, +string azureQueueReportUri) +``` + +### CreateSPAsyncReadJob parameters + +#### url + +Required. + +A **String** value containing the full path URL of the path of the SharePoint List, files/folders, or Document Library **to read**. AMR API returns all the metadata of files, folders, and root objects, **including subfolders and any children content**. + +##### Example + +This example `url` returns all metadata of Shared Document, and its children: + +```http +https://www.contoso.com/Shared%20Document +``` + +#### readOptions + +Required. + +A `SPAsyncReadOptions` structure, with `readOption` values specifying the types of metadata to read. + +##### IncludeVersions + +Optional. + +A **Bool** value to indicate if AMR API reads multiple versions of files and List Items. + +Default value is `false`. When absent or set to `false`, AMR API only reads the latest version of items. + +##### IncludeSecurity + +Optional. + +A **Bool** value to indicate if AMR API reads Users and Groups information related to a Site. + +Default value is `false`. + +AMR API reads Users and Groups as Authors or Modifiers as part of the metadata of the objects. + +If set to `true`, AMR API reads all Users in Site Collections. When reading multiple Document Libraries under the same Site Collection, the same Users and Group might appear in the read package multiple times. + +##### IncludeDirectDescendantsOnly + +Optional. + +A **Bool** value to indicate if AMR API reads only the metadata of the direct descendants. + +Default value is `false`. + +If set to `true`, AMR API reads only the metadata of the direct descendants. + +Use this `readOption` along with `IncludeSecurity` `readOption` together to improve performance when reading metadata from a Document Library containing large number of items, as described in [Best practice](export-amr-api.md) to avoid slow performance. + +##### IncludeExtendedMetadata + +Optional. + +Default value is `false`. + +When set to `false`, AMR API reads basic metadata: + +- List +- Folder +- File +- List Item +- Roles +- Role Assignments + +When set to `true`, AMR API reads all metadata available: + +For Files: + +- Web Part +- Web Part personalization +- Links +- Version events +- Event receivers +- Attachment metadata + +For Lists: + +- Custom actions +- List shortcuts + +For List Items: + +- Comments +- Documents set links +- Activities +- List Item shortcuts + +Including extended metadata slows down the read significantly. For file share migrations, keep the default value `false`. Set to `true` only when necessary, for complex migration projects. + +##### IncludePermission + +Optional. + +A **Bool** value to indicate if permissions read is needed. Default value is `false`. + +When set to `true`, AMR API reads permission metadata in `RoleAssignments` tags in `Manifest.xml` files. The file includes all distinguished permission metadata for each read SharePoint object, along with property `ScopeId`. + +##### StartChangeToken + +Optional. + +A **Integer** value containing the changeToken item. + +By default, when no `StartChangeToken` is provided, `CreateSPAsyncReadJob` method returns all items available, based on the parameters. A `CurrentChangeToken` value is returned every time. + +To read only the items that changed since last read, set a `StartChangeToken` in subsequent calls to `CreateSPAsyncReadJob`. Use `CurrentChangeToken` returned from last call as the value of `StartChangeToken`. + +AMR API returns an error and stops the read, if it receives an invalid `StartChangeToken` value. + +Be careful when using this feature with large number of items. The read job could run for extended duration. AMR API cancels jobs that run over 10 minutes to protect the SharePoint infrastructure. + +#### encryptionOption + +Optional. + +A `EncryptionOption` object, containing the AES-256-CBC Key used to decrypt the output. + +By default, AMR API doesn't encrypt the output and event queue. If set with AES-256-CBC Key, AMR API encrypts the output with the key supplied. + +See [`EncryptionOption`](/dotnet/api/microsoft.sharepoint.client.encryptionoption) class for details. + +#### azureContainerManifestUri + +Required. + +A **String** value, which is the destination URL of the Azure Blob Storage Container containing the output manifest package. + +See [Azure](migration-azure.md) for instructions of using Azure Blob Storage Container in migration. + +#### azureQueueReportUri + +Required. + +A **String** value, which is the URL of the Azure Queue to receive read status messages. + +Share `azureQueueReportUri` among different jobs if necessary. AMR API returns `JobID` to identify individual jobs created. + +See [Azure](migration-azure.md) for instructions of using Azure Queue in migration. Check [Migration events in Azure Queue](migration-events.md) for types of events. + +### CreateSPAsyncReadJob return values + +#### Job ID + +A **Guid** value, which contains Job ID, the unique identifier of the migration job. The method returns a `null` value, if it fails to create the job. + +AMR API generates a `JobEnd` event when it estimates item count for each `url`. Check [Events](migration-events.md) for details. + +#### AzureContainerManifest + +A **Uri** value that contains the URL to access the Azure Blob Storage Container, which contains the metadata read. + +#### JobQueueUri + +A **Uri** value that contains the URL of the Azure Queue used for read status. + +#### EncryptionKey + +A **Byte Array** value that contains the AES-256-CBC Key for decrypting the manifest files and messages in the Azure Queue. + +## CreateSPAsyncReadJobWithMultiUrl method + +Creates an AMR job to read all the metadata of all SharePoint URLs specified, and their children into the specified manifest container. + +### CreateSPAsyncReadJobWithMultiUrl syntax + +```csharp +public SPAsyncReadJobInfo CreateSPAsyncReadJobWithMultiUrl( + String[] urls, + SPAsyncReadOptions readOptions, + EncryptionOption encryptionOption, + String azureContainerManifestUri, + String azureQueueReportUri) +``` + +### CreateSPAsyncReadJobWithMultiUrl parameters + +See `CreateSPAsyncReadJob` method for details of `readOptions`, `encryptionOption`, `azureContainerManifestUri`, and `azureQueueReportUri`. + +#### urls + +Required. + +A **Uri** **Array** containing the full path URLs of the root paths of the SharePoint Lists, files/folders, or Document Libraries to read. AMR API returns all the metadata of files, folders, and root objects, **including subfolders and any children content**. + +Specify multiple URLs when needed. Aggravated call with multiple URLs might improve the performance. See [Performance](export-amr-api.md#performance) for details. + +## Errors + +### -2146232832 + +The changeToken refers to a time before the start of the current change log. + +The change log is limited to 60 days immediately before the current date. AMR API returns this error code when the specified `changeToken` refers to a time outside the 60-day window. + +### -2147213196 + +Operation canceled. + +AMR API received a cancellation request from the client and cancels the read operation. diff --git a/docs/apis/csom-methods-for-applying-retention-labels.md b/docs/apis/csom-methods-for-applying-retention-labels.md new file mode 100644 index 000000000..ddde1e391 --- /dev/null +++ b/docs/apis/csom-methods-for-applying-retention-labels.md @@ -0,0 +1,143 @@ +--- +title: CSOM methods for retention labels +description: CSOM methods are available to apply (set) a retention label (ComplianceTag) on one or many items (ListItems) in SharePoint. Also includes settings of retention labels in ODB and SPO. +author: kyracatwork +ms.author: kyrachurney +ms.date: 9/30/2024 +--- + +# CSOM methods for applying retention labels and managing settings of record labels + +Retention labels let you apply retention settings for governance control at the item level, and are part of the Microsoft Purview compliance solutions. [Learn more about retention labels.](/microsoft-365/compliance/retention#retention-labels) + +Retention labels may classify contents as records, which place restrictions on what actions are allowed or blocked. [Learn more about declaring records by using retention labels](/microsoft-365/compliance/declare-records) + +CSOM methods are available to apply (set) a retention label (ComplianceTag) on one or many items (ListItems) in SharePoint, and change retention labels settings for deleting, versioning, and changing properties of records. Retention labels can be applied using this method without being published to the location by an existing label policy. + +## SetComplianceTagOnBulkItems + +This method can be used to set a ComplianceTag on one or many ListItems. It is strongly recommended to use this method for this purpose. + +```c# +public List SetComplianceTagOnBulkItems( + List itemIds, + string listUrl, + string complianceTagValue) +``` + +### Parameters + +- 'List' [Int](/en-us/dotnet/api/system.int32) +- 'ItemsIds' [String](/dotnet/api/system.string) +- 'ListURL' [String](/dotnet/api/system.string) +- 'ComplianceTagValue' [String](/dotnet/api/system.string) + +Attribute [RemoteAttribute](/dotnet/api/microsoft.sharepoint.client.remoteattribute) + +## GetAllowFilesWithKeepLabelToBeDeletedODB + +Get whether files with Keep Label can be deleted in ODB. + + +```c# + +public static bool GetAllowFilesWithKeepLabelToBeDeletedODB() +``` + +## SetAllowFilesWithKeepLabelToBeDeletedODB + +Set whether files with Keep Label can be deleted in ODB + + +```c# +public static void SetAllowFilesWithKeepLabelToBeDeletedODB(bool allowDeletion) +``` + +Parameters + +- 'allowDeletion' [Boolean](/dotnet/api/system.boolean) + +## GetAllowFilesWithKeepLabelToBeDeletedSPO +Get whether files with Keep Label can be deleted in SPO. + +```c# + +public static bool GetAllowFilesWithKeepLabelToBeDeletedSPO() +``` + +## SetAllowFilesWithKeepLabelToBeDeletedSPO + +Set whether files with Keep Label can be deleted in SPO. + +```c# +public static void SetAllowFilesWithKeepLabelToBeDeletedSPO(bool allowDeletion) +``` + +Parameters + +- 'allowDeletion' [Boolean](/dotnet/api/system.boolean) + +## GetAdvancedRecordVersioningDisabled + +Get whether advanced record versioning is disabled. + +```c# + +public static bool GetAdvancedRecordVersioningDisabled() +``` + +## SetAdvancedRecordVersioningDisabled + +Set to enable or disable the advanced record versioning. + +```c# +public static void SetAdvancedRecordVersioningDisabled(bool disabled) +``` + +Parameters + +- 'disabled' [Boolean](/dotnet/api/system.boolean) + +## GetMetadataEditBlockingEnabled + +Get whether metadata edit blocking is enabled. + +```c# + +public static bool GetMetadataEditBlockingEnabled() + +``` + +## SetMetadataEditBlockingEnabled + +Set metadata edit blocking enabled setting. + + +```c# +public static void SetMetadataEditBlockingEnabled(bool enabled) +``` + +Parameters + +- 'enabled' [Boolean](/dotnet/api/system.boolean) + +### Applies to + +|Product|Versions| +|:---|:---| +|SharePoint CSOM|latest| + +## Other + +> [!NOTE] +> It is strongly recommended to use SetComplianceTagOnBulkItems instead of these methods. + +The following methods are also available, but are no longer updated and may be subject to deprecation in the future. If you are using these methods, we strongly recommend use of the SetComplianceTagOnBulkItems method instead. + +* [SetComplianceTag](/dotnet/api/microsoft.sharepoint.client.listitem.setcompliancetag) +* [SetComplianceTagWithExplicitMetaInfo](/dotnet/api/microsoft.sharepoint.client.listitem.setcompliancetagwithexplicitmetasupdate) +* [SetComplianceTagWithExplicitMetasUpdate](/dotnet/api/microsoft.sharepoint.client.listitem.setcompliancetagwithexplicitmetasupdate) +* [SetComplianceTagWithHold](/dotnet/api/microsoft.sharepoint.client.listitem.setcompliancetagwithhold) +* [SetComplianceTagWithMetaInfo](/dotnet/api/microsoft.sharepoint.client.listitem.setcompliancetagwithmetainfo) +* [SetComplianceTagWithNoHold](/dotnet/api/microsoft.sharepoint.client.listitem.setcompliancetagwithnohold) +* [SetComplianceTagWithRecord](/dotnet/api/microsoft.sharepoint.client.listitem.setcompliancetagwithrecord) diff --git a/docs/apis/export-amr-api-permission-guide.md b/docs/apis/export-amr-api-permission-guide.md new file mode 100644 index 000000000..55a921cc2 --- /dev/null +++ b/docs/apis/export-amr-api-permission-guide.md @@ -0,0 +1,167 @@ +--- +title: "SharePoint Migration Export (Asynchronous Metadata Read) API permission guide" +description: This article targets ISVs and any third-party vendors/developers who are developing and maintaining a migration tool and explains the permission details and options in the export API. +ms.date: 08/25/2023 +ms.author: jhendr +author: JoanneHendrickson +manager: Serdars +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- + +# AMR Export Permission Guide + +The Asynchronous Metadata Read (AMR) API export permission lets you export SharePoint Online metadata permission info using a new export option. This guide will show you how to use this option and what changes have been introduced to the export result. + +## How to use AMR export permission option + +For both CSOM and RESTFul calls, add the below option to enable/disable AMR export permission: + +- For CSOM, when building `AsyncReadOptions` object, set `IncludePermission` property to `true` or `false`. + - If you cannot use `IncludePermission` property, please update your CSOM nuget package to the latest version. +- For RESTFul, add `IncludePermission` key to the request JSON payload's `readOptions` section, and set it to `true` or `false`. + - For example: `{..., "readOptions":{...,"IncludePermission":true,...}...}` + +## What changes have been introduced to the export result + +The new `IncludePermission=true` option will involve an additional tag called `` into **Manifest.xml** file in the export result, which includes all distinguished permission info for each exported SPO object with property `ScopeId`, like below: + +```xml +<...> + + + + + ... + + +<...> +``` + +The `RoleAssignments` tag is a list of `RoleAssignment` tags, each `RoleAssignment` tag represents a unique permission scope from exported SPO objects, identified by `ScopeId`. Each `RoleAssignment` tag contains multiple `Assignment` tags, representing an entity within that specific unique permission scope each, such as a user, a group, etc., with a principal ID. + +In the meantime, all involved entities will be listed in **UserGroup.xml** file in the export result, to help further user resolution. + +Here is an example of **Manifest.xml** file and **UserGroup.xml** with `IncludePermission=true` option: + +```xml + +<...> + + + +<...> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<...> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +## Option interaction between `IncludeSecurity` and `IncludePermission` + +Before the `IncludePermission` option, the `IncludeSecurity` option has been already used to get a full list of all user & group information of the target site. It isn't necessary that you use the `IncludePermission` option with `IncludeSecurity` option. However, if you still want to get a full list of all user and group information of target sites with permission information, you can use `IncludePermission` option with `IncludeSecurity` option together, here are the 4 combinations of the two options with expected results: + +- `IncludeSecurity=true` only: get a full list of all user & group information of the target site without permission information. +- `IncludePermission=true` only: get exported items' permission information, with a list of corresponding user & group information of exported permissions. +- `IncludeSecurity=true` + `IncludePermission=true`: get exported items' permission information, with a full list of all user & group information of the target site. +- None of them is used: get no permission, nor related user & group information. diff --git a/docs/apis/export-amr-api.md b/docs/apis/export-amr-api.md index 78c553962..fe7248b8f 100644 --- a/docs/apis/export-amr-api.md +++ b/docs/apis/export-amr-api.md @@ -1,362 +1,123 @@ --- -title: "SharePoint Migration Export (Asynchronous Metadata Read) API" -description: This document targets ISVs and any third-party vendors/developers who are developing and maintaining a migration tool. -ms.date: 07/31/2020 -ms.author: jhendr -author: JoanneHendrickson -manager: pamgreen +title: "SharePoint Asynchronous Metadata Read (AMR) API Introduction" +description: Overview how to read metadata from SharePoint, targeted to SharePoint migration tool developers. +ms.date: 07/23/2025 +ms.author: ranren +author: underreview +manager: dapodean audience: ITPro +ms.subservice: migration-tool ms.topic: article -localization_priority: Priority +ms.localizationpriority: high ms.collection: - SPMigration - m365-collaboration --- -# SharePoint Migration Export (Asynchronous Metadata Read) API +# SharePoint Asynchronous Metadata Read (AMR) API Introduction -## Overview +The SharePoint Asynchronous Metadata Read (AMR) API enables the asynchronous export of metadata from SharePoint and OneDrive. -The goal of the new Migration Asynchronous Metadata Read (AMR) API is to reduce the number of calls, reduce throttling, and improve overall migration performance for our customers. Instead of calling thousands of calls to query information from SPO, the new Migration Asynchronous Metadata Read can return the same amount of data in a single read. +Use AMR API to export metadata from SharePoint for incremental migration and post-migration validation. -When the new SharePoint Migration Export (Asynchronous Metadata Read) API performs a read operation of a provided URL, the Microsoft backend software aggregates all the information into a designated manifest. The ISV can read back from the manifest and parse the metadata without sending thousands of calls individually. The AMR API also has the ability to load balance the server, and supports an unlimited amount of metadata to be migrated. +AMR is designed exclusively for import scenarios. It exhibits poor scalability when handling requests for metadata, permissions, or versions. We can't provide performance assurances for AMR usage in data export scenarios, such as cross-tenant migrations. -This document targets ISVs and any third-party vendors/developers who are developing and maintaining a migration tool. +## What's new -### Background +### January 2024 -Currently, the [SharePoint Online Migration API](migration-api-overview.md), lets your migration tool efficiently migrate large amounts data to SharePoint Online. However, the lack of an official API to read content from SharePoint Online means that these tools must rely on CSOM/Vroom function calls to perform individual metadata read operations. +We reformatted this document to bring clarity and correct errors. -Large numbers of calls increase the likelihood of throttling, which impacts migration performance and customer experience. Ineffective call usage results in large SQL round trip per function calls that can potentially bring down the database and impact its reliability. +## Export steps overview -A migration performance study identified four areas where a high number of calls are heavily used: +Export metadata from SharePoint in three steps: -- **Incremental migration** relies on calls to retrieve the SharePoint online (SPO) content. It compares it with the source location to determine if there have been any changes to the content and whether to proceed with migration. -- **Structure creation** leverages calls for site, web part and navigation creation. -- **After migration verification** is done when migration is completed and is used to ensure the source and destination file metadata matches. -- **Permission settings** function calls are made to get user permission information. +### Provision the destination containers and the queue -## SharePoint Migration Export (Asynchronous Metadata Read) API - -The SharePoint Migration Export (Asynchronous Metadata Read) API aims to reduce the calls in areas: incremental migration, after migration verification and permission settings. - -> [!Note] -> The first version of the SharePoint Migration Export (Asynchronous Metadata Read) API supports files, folders, lists, list items, and the document library. Permissions are expected to be covered in a subsequent version. - -Key supported features: - -- Ability to aggregate small metadata requests calls (for example, CSOM) into a single AMR call with the multiple URL feature -- Ability to read unlimited items with a single API call. -- Incremental migration feature support returning of item changed since last query with *changeToken* feature -- Ability to include a rich set of metadata per item -- Ability to return only top-level structure without subfolders or children. - -More detailed information about the features and the API description is covered in the section below. - - -The Migration Asynchronous Read APIs are: - -Single - -```csharp -public SPAsyncReadJobInfo CreateSPAsyncReadJob( - Uri url, - SPAsyncReadOptions readOptions, - EncryptionOption encryptionOption, - string azureContainerManifestUri, - string azureQueueReportUri) -``` - -Multiple - -```csharp -public SPAsyncReadJobInfo CreateSPAsyncReadJobWithMultiUrl( - Uri[] urls, - SPAsyncReadOptions readOptions, - EncryptionOption encryptionOption, - string azureContainerManifestUri, - string azureQueueReportUri) -``` - -The API is made up of five input parameters and one output structure field. - -## Input Parameters - -### URL - -The full path URL lets your migration tool to specify the root URL path of the SharePoint list, files/folder document library to be read. By default, the server-side code will read and return all the metadata of files, folders, and root objects including subfolders and their children content. - -*Example:* -This document library URL, `https://www.contoso.com/Shared%20Document`, will be read back for metadata of any files or folders that live under the root URL. `https://www.contoso.com/Shared%20Documents/FolderA/` will be read back for children metadata in FolderA. - -#### Multiple URLs - -With the latest API update in Q1 2020, AMR will now support multiple URL inputs. This means the user can input multiple root URLs or subfolder URLs and aggregate them into a single call. - -As there is a fixed overhead, AMR is most effective when there is a large number of reads when processing AMR. There are cases when the migration software may not want to read the whole root level URL. The multiple URL feature lets the software to aggregate multiple requests into a single request to improve performance while reducing number of calls. - -(For more information regarding the size recommendation, see the performance section) - -*Example:* The document library URL, `https://www.contoso.com/Shared%20Document`, has folders A through J . The customer only wants to migrate folders A, B, C, D, and E. Instead of issuing a single read at the root level and returning large unnecessary content, or issuing AMR per individual folder, which is not effective, the software can issue URI [A, B, C, D, E] in the input parameters returning only required metadata. - -Currently there is a maximum of 5000 URL aggregation limits per call. - -#### readOptions Flag - -The read asynchronous function will include the SPAsyncReadOptions structure, which covers the optional flags to allow the user to specify version and security setting on the site level more is described below. - -```csharp -IncludeVersions{ get; set; } -``` - -If set, this indicates all the files and list item version history is to be included in the export operation. If absent, only the most recent version is provided. - -```csharp -IncludeSecurity{ get; set; } -``` - -This flag indicates whether to include all user or group information from a site. By default, users and groups that are part of the object metadata will be returned, such as author or modifier. - -If you use this flag, all users in the site collection will be included. If you are issuing AMR calls for different document libraries that are under the same site collection, the same set of users will be included each time, unless there has been a change. - ->[!Important] ->Using this option can result in very slow performance. Use it only as described in the steps below. - -If you have a large number of objects in a document library, it is faster to do the following two calls to read the security setting and its child folders: - -1. To get user/group info, call the AMR job on the top root folder with security on using this setting: -("IncludeSecurity=true" & "IncludeDirectDescendantsOnly=true"). -1. For the rest of the structure, call the AMR job with the security off: -"IncludeSecurity=false" - -```csharp -public bool IncludeDirectDescendantsOnly { get; set;} -``` - -If specified only the top-level metadata item is read back. Example: The root URL contains file A and folder B. If this flag is specified, the manifest returns only file A and folder B metadata. It will not return any metadata included inside folder B. - -The use case for this function: The ISV can issue a default read to retrieve the top-level items and then issue multiple `CreateSPAsyncReadJob` to read back all the sub folder content in parallel to improve throughput. - -```csharp -public bool IncludeExtendedMetadata { get; set; } -``` - -This flag indicates whether to return the extended set of metadata content of object query. By default this option is off and only basic content is provided (for example, names, URL, author, modifier, dates) . Turning on this flag provides all the metadata content; however, it will also impact the performance as query will take longer. - -Recommendation is to keep the default for file share migration, but consider setting this flag on for SharePoint on-premises or other more complex migration. - -```csharp -public string StartChangeToken { get; set; } -``` - -This option applies to input URL of list or document library only. - -One of the key calls contributor is incremental migration. ChangeToken idea is introduced to reduce the unnecessary calls. If StartChangeToken is not specified, the CreateSPAsyncReadJob will query and read back all the items specified by the API function. Once specified with the ChangeToken value, only the item changed since last query is returned. - -During incremental migration, instead of query everything again, by populating StartChangeToken with the change token received from the CurrentChangeToken output in returning job info, createSPAsyncReadJob then returns only the items that got changed since the specified StartChangeToken, reducing the overall calls. - -Below is a sample of how the `startChangeToken` might work. This example uses the optional feature setting for initial call and the parameter setting for incremental passes. - -![Export API process](../images/async-read-api-flow.png) - -#### Invalid Value - -If an invalid value is detected, other than NULL, an error will be generated, and the operation will be terminated. - -#### encryptionOption - -This is an optional parameter. If it is specified, the AES256CBCKey is used to encrypt output files and queue messages. Otherwise, there is no encryption. - -For more information, see [EncryptionOption Class](/dotnet/api/microsoft.sharepoint.client.encryptionoption). - -#### azureContainerManifestUri - -The valid URL including SAS token for accessing the Azure Blob Storage Container, which contains the block blobs for the manifest and other package describing XML files. This location will also be used for the log output response. The SAS token must have been created with only Read and Write permissions or the asynchronous metadata read job will fail. The SAS token should at least have a lifetime that starts at from no later than when the job was submitted, until a reasonable time for successful import to have concluded. - -#### azureQueueReportUri - -The valid URL including SAS token for accessing the user provided Azure Queue used for returning notifications of asynchronous metadata read job progress. If this value is not null and proper access is granted in the SAS token in this URI, it will be used for real-time status update. The SAS token must have been created with Add permissions or the migration job will be unable to add events to the queue. - -Once accepted, the job ID will be written to the notification queue if it was provided and access is valid. The notification queue can be used for multiple migration jobs at the same time, as each job will identify itself in values sent back to the notification queue. - -## Output Parameters - -### CurrentChangeToken - -```csharp -public string CurrentChangeToken { get; set; } -``` - -This function returns the changeToken associates with this query. By specifying this changeToken in the input field with subsequent read, the API will return only items changed since this last query. - -#### Manifest Output - -After the *asyncMigrationRead* function prepares execution, the final manifest will be placed in the container specified, under a folder named **JobId**. The manifest export package structure will be like the *createMigration* Import Package structure. The general output structure is summarized in table below. - -> [!NOTE] -> Once the AMR manifest package reaches 25MB, it will split into multiple packages per request. - -Below is an example on how to query the folder: - -```csharp -CloudBlobDirectory folder = blobContainerObj.GetDirectoryReference(jobid); -CloudBlockBlob blob = folder.GetBlockBlobReference(manifestFileName); -``` - -|XML file|Schema File|Description| -|:-----|:-----|:-----| -|ExportSettings.XML|DeploymentExportSettings Schema|ExportSettings.XML does the following:

- Contains the export settings specified by using the SPExportSettings class and other classes that are part of the content migration object model.

- Ensures that the subsequent export process (at the migration target site) enforces the directives specified in the export settings.

- Maintains a catalog of all objects exported to the migration package.| -|LookupListMap.XML|DeploymentLookupListMap Schema|Provides validation for the LookupListMap.XML file exported into the content migration package. LookupListMap.XML maintains a simple lookup list that records SharePoint list item (list item to list item) references.| -|Manifest.XML|DeploymentManifest Schema|Provides validation for the Manifest.xml file that is exported into the content migration package. Provides a comprehensive manifest containing listings of both the contents and the structure of the destination site (for example, SPO) . | -|Requirements.XML|DeploymentRequirements Schema|"Provides validation for the Requirements.xml file exported into the content migration package. Requirements.xml maintains list of deployment requirements in the form of installation requirements on the migration target, such as feature definitions, template versions, Web Part assemblies, and language packs."| -|RootObjectMap.XML|DeploymentRootObjectMap Schema|"Provides validation for the RootObjectMap.xml file exported into the content migration package.RootObjectMap.xml maintains a list of mappings of secondary (dependent) objects, which allows the import phase of the migration operation to correctly place the dependent objects relative to the locations of the root object mappings."| -|SystemData.XML|DeploymentSystemData Schema|Provides validation for the SystemData.xml file exported into the content migration package.SystemData.xml does the following: Collects a variety of low-level system data. Records the number and names of Manifest.xml files (in cases where the migration uses multiple manifests).| -|UserGroupMap.XML|DeploymentUserGroupMap Schema|Provides validation for the UserGroup.xml file exported into the content migration package. UserGroup.xml maintains a list of users and user security groups with respect to access security and permissions.| -|ViewFormsList.XML|DeploymentViewFormsList Schema|Provides validation for the ViewFormsList.xml file exported into the content migration package.ViewFormsList.xml maintains a list of Web Parts and tracks whether each is a view or form.| - -#### How to retrieve the manifest from the Azure blob - -The following example code demonstrates how to get the Azure blob of a manifest file and decipher it: - -```csharp -// Get Azure blob of a manifest file -CloudBlockBlob blob = folder.GetBlockBlobReference(blobName); -blob.FetchAttributes(); - -using (Stream stmTemp = new MemoryStream()) -{ - // Download current manifest file - blob.DownloadToStream(stmTemp); - - // Get IV and decrypt the content into output dir - byte[] IV = Convert.FromBase64String(blob.Metadata[“IV”]); +> [!IMPORTANT] +> Use [GetMigrationJobProgress API](migration-job-progress-api-reference.md) to retrieve migration job status. +> +> Provisioning Azure Queues for migration job status tracking is no longer required. Deprecation of Azure Queues is planned for the second half of 2026. Until then, Azure Queues will remain available for status retrieval. - using (Stream targetStream = System.IO.File.Open(outputFileFullPath, FileMode.Append)) - { - using (Aes alg = new AesCryptoServiceProvider()) - { - stmTemp.Seek(0, SeekOrigin.Begin); - using (CryptoStream csDecrypt = new CryptoStream( - stmTemp, - alg.CreateDecryptor(key, IV), - CryptoStreamMode.Read)) - { - csDecrypt.CopyTo(targetStream); - } - } - } -} -``` +Use `ProvisionMigrationContainers` method to provision the containers. Check [Use Azure Blob Storage Containers and Azure Queues with Migration API](migration-azure.md) for details. You can also use your own containers and queues if needed. -#### JobQueueUri +### Use `CreateSPAsyncReadJob` method to start the export -```csharp -public Uri JobQueueUri { get; set; } -``` +Use `CreateSPAsyncReadJob` method to export metadata from a single URL, or `CreateSPAsyncReadJobWithMultiUrl` from multiple URLs if needed. Check [AMR API Reference](amr-api-reference.md) for details. -The reporting features are the same as they are for `CreateMigrationJob`. Logging is provided to track the status of the asynchronous metadata read. After a scan of the database and an estimate of your tools, the log provides an estimate of the number of items to be read per URL. By default, blob queue permissions and settings are set to "all access", the same as when the ISV calls `ProvisionMigrationContainer` during the `CreateMigrationJob`. +Get incremental updates with `ChangeToken` feature. -In addition to the events supported by the Import API (CreationMigrationJob), a new job event called `FinishManifestFileUpload` will be added to the status queue in real time. This is added after the manifest file is generated and uploaded. +Both methods return the Job ID, which can be used to track the export status. -As it’s a real time event, ISVs and developers can also immediately download and parse the manifest files once `FinishManifestFileUpload` is generated. Use the field `ManifestFileName` to parse this event to get every manifest file name, including systemdata.xml, usergroup.xml, etc. +Check [AMR API Reference](amr-api-reference.md) for details. -The new event will look like this: +### Checking status -```json -{"Event", "FinishManifestFileUpload"}, -{"JobId", “f8d7d577-676e-47ce-ab69-ae7803979883”}, -{"Time", “2019-09-03T19:11:33.903”}, -{"ManifestFileName", “f8d7d577-676e-47ce-ab69-ae7803979883/ExportSettings.xml”} -``` +> [!IMPORTANT] +> Use [GetMigrationJobProgress API](migration-job-progress-api-reference.md) to retrieve migration job status. +> +> Provisioning Azure Queues for migration job status tracking is no longer required. Deprecation of Azure Queues is planned for the second half of 2026. Until then, Azure Queues will remain available for status retrieval. -#### EncryptionKey +Check Azure Queue supplied for export status. Monitor events as listed in [Events](migration-events.md) for details. -```csharp -public byte[] EncryptionKey { get; set; } -``` -It returns the AES256CBC encryption key used to decrypt the message in azureManifest container and azureReport Queue. +AMR API exports metadata in the manifest container supplied, under a folder named by `JobID`. Check [Manifest files](migration-manifest.md) for the format and validation of the metadata. -|Output parameter|Description| -|:-----|:-----| -|JobID/GUID|Return a unique Job ID associated with this asynchronous read| -|AzureContainerManifest|Return the URL for accessing the async read manifest| -|JobQueueUri|URL for accessing Azure queue used for returning notification of migration job process| -|EncryptionKey|AES256CBC encryption key used to decrypt messages from job/manifest queue| +AMR API splits manifest packages larger than 25 MB into multiple manifest files per request. -## Set up Guidelines +## Best practice -The following provides high-level guidelines for implementing the asynchronous metadata migration function. This documentation does not go into details on how to interact with SharePoint RESTful service. It is assumed that the ISV has prior knowledge and will be able to access the target website with proper permission. +AMR API is powerful. Ensure good performance to achieve the scale for large migration projects. -For more information on how to access the SharePoint website, see [Get to know the SharePoint REST service](../sp-add-ins/get-to-know-the-sharepoint-rest-service.md). +### Export security and permissions on top level if possible -1. Install and update the latest Microsoft.SharePointOnline.CSOM version. The minimum version requirement is V16.1.9119.1200 or later. -1. ISVs figure out the folder, document library or files of interested to be query and issued with CreateSPAsyncReadJob function. -1. Once successfully created, query the job status using the *jobQueueUri*. It provides the job process status and any error logging. After job completion, parse the manifest to retrieve the metadata. +Exporting security with `IncludeSecurity` consumes more resources and slows down the export. It's faster to export this metadata at the upper-level folder first, then export the children without them. -### SharePoint Migration Export (Asynchronous Metadata Read) API Example +### Metadata export on a single item -#### Scenario: Large file share (> 1 million) with nested files/folders +Use Microsoft Graph instead of AMR. -Suggestion: -1. Issue CreateSPAsyncReadJob - - URL = root URL (for example, `www.contoso.com/my-resource-document`) - - Optional Flag: `IncludeDirectDescendantsOnly(true)` +### Folders with less than 10,000 items - For each of the sub folders, issue createSPAsyncReadJob if the folder has > 10K +Use `CreateSPAsyncReadJobWithMultiUrl` to combine the URLs of multiple folders into a single export job. - **Sample source code** +### Folders with 10,000 to 1 million items - ```powershell - $site = get-spsite https://test.sharepoint.com # get site - $web = get-spweb https://test.sharepoint.com # get web - $list = $web.GetList("Shared Documents") # get the document library under this web +Use `CreateSPAsyncReadJob`, and set **readOption** `IncludeDirectDescendantsOnly` to `false`. This value is the default setting. - # Get the Doclib root folder - $rootFolder = $web.GetFolder($list.Rootfolder.ServerRelativeUrl) +### Nested folders with over 1 million items - # You can call 1 AMR job here, to get metadata of the direct children of the root folder only - CreateAMRJob($rootFolder) +Plan carefully when dividing folders into jobs. Object count in export jobs is the major factor of export performance. - # Create parallel AMR jobs for the direct level subfolders - Foreach ($folder in $rootFolder.SubFolders) - { - // Create 1 AMR job per folder tree - CreateAMRJob($folder) - } - ``` +This example shows how to export metadata from nested folders with over 1 million items. AMR API has the highest performance when the item count is large. - The ISV can optimize the recursive highlight part by leveraging the $ folder.item["SMTotalFileCount"] that will return the cumulative file count in the folder tree for a given folder item. Follow the recommendations in the performance section on type of AMR jobs to issue +- Use `CreateSPAsyncReadJob` method at the root URL, for example: `www.contoso.com/my-resource-document`, and set **readOption** `IncludeDirectDescendantsOnly` to `true`. +- Utilize `SMTotalFileCount` attribute to get the file count in folders. +- Continue to use `createSPAsyncReadJob` method at subfolder level, on each of the subfolders, if the folder has more than 10,000 items. +- Use `CreateSPAsyncReadJobWithMultiUrl` method, combining subfolders with less than 10,000 items. -1. object, issued in multiple URLs if < 10K objects +## Performance -> [!IMPORTANT] -> This scenario is only recommended for top level folders or if the sub-folder contains greater than one million objects. The performance of the AMR API is *not as effective* when reading a small set of items. +AMR API processes jobs through a queue mechanism with preconfigured workload management settings. AMR API processes the jobs on a best-effort basis, without Service Level Agreement (SLA) or guaranteed performance. -#### Scenario: Incremental Migration of FileShare for a sub folder +### Lab-tested performance baseline -1. Issue CreateSPAsyncReadJob:
- 1. URL = root URL (for example, `www.contoso.com/my-resource-document/a`) - 1. Remembered the `CurrentChangeToken` +We tested the performance in a lab setting. AMR API exported about 400 items per second for every 250-K objects, in the average case. The peak performance reached 700 items per second. -1. After some time, the software wishes to perform incremental migration. Issue CreateSPAsyncReadJob with following term:
- 1. URL = root URL (for example, `www.contoso.com/my-resource-document/a`) - 1. Optional Flag: `StartChangeToken(CurrentChangeToken)` +Multiple factors affect real-life performance. These factors include: -## Limitations +- The number of items that are being exported +- The way AMR API is implemented +- Throttling -Asynchronous Metadata Read (Export API) now supports unlimited list, document library, file, and folder metadata export. +### Optimize migration performance -## Performance Expectation +In order to ensure optimal performance for your migration projects, it's important to plan carefully, especially when dealing with large-scale migrations. For more information on how to estimate timespans and optimize performance, see our [performance guide](/sharepointmigration/sharepoint-online-and-onedrive-migration-speed). -The preliminary performance test provides a rough estimate of more than 400 items per second throughput for every 250K of objects read. We have seen over 700 items per second throughput in a testing environment. However, this is highly dependent on the number of items that are being read plus the implementation of the AMR API. This does not account for any potential throttle over the network. If the asynchronous read function fails to reach the server due to throttling, then performance will be impacted. +### I'm seeing throttling messages -This measure of throughput assumes the software package has a sufficient number of items per read. Microsoft recommends the following: +To ensure good user experiences for all Microsoft 365 customers, SharePoint uses throttling to protect the SharePoint infrastructure. Avoid getting throttled by following [throttling guidance](https://aka.ms/spo429). -| Folder size | Recommendation | -| :------------------------------------------------ | :----------------------------------------------------------------------------------------------------------- | -| Less than 10,000 items | Combine the URLs of multiple folders into a single call | -| Greater than 10,000 items but less than 1,000,000 | Run AMR at the root folder level | -| Greater than 1,000,000 | Use the recursive call logic to explore that folder's direct level children until there are no more folders. | +### Tenant-to-Tenant migrations -For a single read query, it is faster to use the Graph API or a RESTful/CSOM query. +AMR isn't intended for scenarios where contents from a SharePoint tenant are moved to another. This type of migration requires the use of many resource-heavy read options. The long processing time of these read options slows down the overall migration significantly. -One of the key performance benefits of using the asynchronous metadata read is the ability to balance the server-side load and the backend query. It is much more efficient than using individual CSOM load reducing to lessen your chance of throttling. +Microsoft provides no performance guarantee in this scenario. Use Graph or CSOM as needed. diff --git a/docs/apis/migrate-webparts-with-migrationapi.md b/docs/apis/migrate-webparts-with-migrationapi.md index 7702e6bd4..25114eea9 100644 --- a/docs/apis/migrate-webparts-with-migrationapi.md +++ b/docs/apis/migrate-webparts-with-migrationapi.md @@ -1,17 +1,18 @@ --- title: "Migrating web parts using the Migration API" -ms.reviewer: +description: "Migrating web parts using the Migration API" ms.author: jhendr author: JoanneHendrickson manager: pamgreen audience: ITPro +ms.date: 06/28/2022 +ms.subservice: migration-tool ms.topic: conceptual -localization_priority: Normal +ms.localizationpriority: medium search.appverid: MET150 -msCollection: +msCollection: - SPMigration - M365-collaboration -description: "Migrating web parts using the Migration API" --- # Migrating web parts using the Migration API @@ -24,151 +25,145 @@ An advantage in using the Migration API for your web part migration is the abili There are two attributes that are handled in a unique way that requires using the WebPart User Properties Serializer DLL. There is a technical challenge to generate the property values for *AllUsersProperties* and *PerUserProperties* when building the PRIME package. This challenge is because the property values are BASE64 encoded blob, which is serialized web part properties and web part connection info. - To get the Serializer .dll, perform following steps: - 1. Install the SPMT Client on your local computer: [Install SPMT](https://aka.ms/spmt-GA-page). -2. Browse to the install location of SPMT -3. Locate and copy the *microsoft.sharepoint.migration.webpart.serializer.dll* and you can copy it into your project. +1. Browse to the install location of SPMT +1. Locate and copy the *microsoft.sharepoint.migration.webpart.serializer.dll* and you can copy it into your project. For a complete list of the supported web parts, see: -- [SPMT & Migration API supported SharePoint web parts](https://docs.microsoft.com/sharepointmigration/spmt-supported-webparts) - - +- [SPMT & Migration API supported SharePoint web parts](/sharepointmigration/spmt-supported-webparts) ## Schema: For an explanation of the **SPWebPart** fields see: -- [SPWebPart](https://docs.microsoft.com/openspecs/sharepoint_protocols/ms-primepf/25cfceeb-7769-4331-9936-ce3b9ced87ad) - - +- [SPWebPart](/openspecs/sharepoint_protocols/ms-primepf/25cfceeb-7769-4331-9936-ce3b9ced87ad) ### PRIME Web Part Schema example ```xml - - - - - - - - - - - …… - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + +…… + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ``` ## Security controls Due to the security control design on the server side, the following behavior: - + - If the NoScript is off, then go on migrating all web part as currently - If NoScript is on, then first check web part level safety - - If SafeAgainstScript is false, do not import it - - If SafeAgainstScript is true, then check the web part property level safety - - If the web part has any property with ‘RequiresDesignerPermission’, then ignore this web part (or ignore this property if feasible) - - Otherwise, go on migrating this web part - - + - If SafeAgainstScript is false, do not import it + - If SafeAgainstScript is true, then check the web part property level safety + - If the web part has any property with ‘RequiresDesignerPermission’, then ignore this web part (or ignore this property if feasible) + - Otherwise, go on migrating this web part + + Here is the list of web parts that will be ignored by server-side code (treated as untrusted webpart) when NoScript is turned ON: - XsltListViewWebPart @@ -195,141 +190,138 @@ Here is the list of web parts that will be ignored by server-side code (treated ## FAQ *Question:* How do I fetch the web part properties as the input for serialization API? -*Answer:* The web part properties can be found in element in the response of operation ‘GetWebPartProperties2’ in ‘WebPartPagesWebService’. Find the payload details in WSDL ‘/_vti_bin/WebPartPage.asmx?WSDL’. +*Answer:* The web part properties can be found in \ element in the response of operation ‘GetWebPartProperties2’ in ‘WebPartPagesWebService’. Find the payload details in WSDL ‘/_vti_bin/WebPartPage.asmx?WSDL’. *Question:* How to fetch the web part connection info as the input for serialization API? -*Answer:* The web part connections could be found in elements from the web part page in the response of operation ‘GetWebPartPage’ in ‘WebPartPagesWebService’. +*Answer:* The web part connections could be found in \ elements from the web part page in the response of operation ‘GetWebPartPage’ in ‘WebPartPagesWebService’. -View flags: refer to this https://docs.microsoft.com/openspecs/sharepoint_protocols/ms-wssfob/252d2086-6571-430f-863d-bcaf9d267e62, for example, all the view flags https://docs.microsoft.com/openspecs/sharepoint_protocols/ms-wssfob/16a9d8ca-185d-40ec-956e-bb6bf3488cf7. You will need to convert all flag values to PRIME element ‘flags’. +View flags: refer to [this](/openspecs/sharepoint_protocols/ms-wssfob/252d2086-6571-430f-863d-bcaf9d267e62), for example, all the [view flags](/openspecs/sharepoint_protocols/ms-wssfob/16a9d8ca-185d-40ec-956e-bb6bf3488cf7). You will need to convert all flag values to PRIME element ‘flags’. ## Appendix -### Sample Web Part Properties v2 XmlNode Element +### Sample Web Part Properties v2 XmlNode Element ```xml - - - Content Editor - Default - Allows authors to enter rich text content. - true - wpz - 0 - Normal - - - true - true - true - true - true - true - true - - - Modeless - Default - - - /_layouts/15/images/mscontl.gif - - true - 00000000-0000-0000-0000-000000000000 - g_d6def51c_7a91_40fe_9f59_de9ceed5c347 - Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c - Microsoft.SharePoint.WebPartPages.ContentEditorWebPart - - - - + + Content Editor + Default + Allows authors to enter rich text content. + true + wpz + 0 + Normal + + + true + true + true + true + true + true + true + + + Modeless + Default + + + /_layouts/15/images/mscontl.gif + + true + 00000000-0000-0000-0000-000000000000 + g_d6def51c_7a91_40fe_9f59_de9ceed5c347 + Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c + Microsoft.SharePoint.WebPartPages.ContentEditorWebPart + + + + ``` ### Sample Web Part Properties v3 XmlNode Element ```xml - - - - - - - - - False - - - True - - - False - - a316c9a6-e664-426b-9069-77cabd22429c - /Lists/TestPromotedLinks - False - NotSet - False - Html, TabularView, Hidden, Ordered - True - {A316C9A6-E664-426B-9069-77CABD22429C} - - True - Normal - True - - - All - False - True - True - - Modeless - - True - 86400 - Default - - - /_layouts/15/images/itgen.png?rev=23 - - True - - -1 - True - - - False - - PAGE_NORMALVIEW - - True - False - 00000000-0000-0000-0000-000000000000 - - main.xsl - True - - False - <View Name="{2B37E456-6FD3-4708-AC83-5D7B0D13E9B4}" Type="HTML" Hidden="TRUE" OrderedView="TRUE" DisplayName="" Url="/SitePages/TestPage.aspx" Level="1" BaseViewID="3" ContentTypeID="0x" ><Query><OrderBy><FieldRef Name="TileOrder" Ascending="TRUE"/><FieldRef Name="Modified" Ascending="FALSE"/></OrderBy></Query><ViewFields><FieldRef Name="Title"/><FieldRef Name="BackgroundImageLocation"/><FieldRef Name="Description"/><FieldRef Name="LinkLocation"/><FieldRef Name="LaunchBehavior"/><FieldRef Name="TileOrder"/></ViewFields><RowLimit Paged="TRUE">30</RowLimit><JSLink>clienttemplates.js</JSLink><XslLink Default="TRUE">main.xsl</XslLink><Toolbar Type="Standard"/></View> - False - True - <ParameterBinding Name="dvt_sortdir" Location="Postback;Connection" /><ParameterBinding Name="dvt_sortfield" Location="Postback;Connection" /><ParameterBinding Name="dvt_startposition" Location="Postback" DefaultValue="" /><ParameterBinding Name="dvt_firstrow" Location="Postback;Connection" /><ParameterBinding Name="OpenMenuKeyAccessible" Location="Resource(wss,OpenMenuKeyAccessible)" /><ParameterBinding Name="open_menu" Location="Resource(wss,open_menu)" /><ParameterBinding Name="select_deselect_all" Location="Resource(wss,select_deselect_all)" /><ParameterBinding Name="idPresEnabled" Location="Resource(wss,idPresEnabled)" /><ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" /><ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_DEFAULT)" /> - List - 60 - False - - Cannot import this Web Part. - - - - - + + + + + + + + False + + + True + + + False + + a316c9a6-e664-426b-9069-77cabd22429c + /Lists/TestPromotedLinks + False + NotSet + False + Html, TabularView, Hidden, Ordered + True + {A316C9A6-E664-426B-9069-77CABD22429C} + + True + Normal + True + + + All + False + True + True + + Modeless + + True + 86400 + Default + + + /_layouts/15/images/itgen.png?rev=23 + + True + + -1 + True + + + False + + PAGE_NORMALVIEW + + True + False + 00000000-0000-0000-0000-000000000000 + + main.xsl + True + + False + <View Name="{2B37E456-6FD3-4708-AC83-5D7B0D13E9B4}" Type="HTML" Hidden="TRUE" OrderedView="TRUE" DisplayName="" Url="/SitePages/TestPage.aspx" Level="1" BaseViewID="3" ContentTypeID="0x" ><Query><OrderBy><FieldRef Name="TileOrder" Ascending="TRUE"/><FieldRef Name="Modified" Ascending="FALSE"/></OrderBy></Query><ViewFields><FieldRef Name="Title"/><FieldRef Name="BackgroundImageLocation"/><FieldRef Name="Description"/><FieldRef Name="LinkLocation"/><FieldRef Name="LaunchBehavior"/><FieldRef Name="TileOrder"/></ViewFields><RowLimit Paged="TRUE">30</RowLimit><JSLink>clienttemplates.js</JSLink><XslLink Default="TRUE">main.xsl</XslLink><Toolbar Type="Standard"/></View> + False + True + <ParameterBinding Name="dvt_sortdir" Location="Postback;Connection" /><ParameterBinding Name="dvt_sortfield" Location="Postback;Connection" /><ParameterBinding Name="dvt_startposition" Location="Postback" DefaultValue="" /><ParameterBinding Name="dvt_firstrow" Location="Postback;Connection" /><ParameterBinding Name="OpenMenuKeyAccessible" Location="Resource(wss,OpenMenuKeyAccessible)" /><ParameterBinding Name="open_menu" Location="Resource(wss,open_menu)" /><ParameterBinding Name="select_deselect_all" Location="Resource(wss,select_deselect_all)" /><ParameterBinding Name="idPresEnabled" Location="Resource(wss,idPresEnabled)" /><ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" /><ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_DEFAULT)" /> + List + 60 + False + + Cannot import this Web Part. + + + + + ``` -4 - Sample Web Part Connection XmlNode Element +### Sample Web Part Connection XmlNode Element ```xml - ``` diff --git a/docs/apis/migration-api-azure-container-and-queue.md b/docs/apis/migration-api-azure-container-and-queue.md index d330e2135..1dff25363 100644 --- a/docs/apis/migration-api-azure-container-and-queue.md +++ b/docs/apis/migration-api-azure-container-and-queue.md @@ -1,16 +1,16 @@ --- title: SPO provided Migration Azure container and queue +description: "One of the Main requirement for using our Migration API is the usage of an Azure container as a temporary storage. We now provide a default container that can be used for using the migration API." +ms.date: 07/08/2022 ms.author: jhendr author: JoanneHendrickson manager: pamgreen -ms.date: 04/23/2020 -description: "One of the Main requirement for using our Migration API is the usage of an Azure container as a temporary storage. We now provide a default container that can be used for using the migration API." -localization_priority: Normal +ms.subservice: migration-tool +ms.localizationpriority: medium --- - # SPO provided Migration Azure container and queue -Microsoft’s Migration API requires the use of an Azure container for temporary storage. To simplify the process, you are now provided with a default container while using the migration API. If you choose, you can still provide your own Azure container. +Microsoft’s Migration API requires the use of an Azure container for temporary storage. To simplify the process, you are now provided with a default container while using the migration API. To use the provided container you will need to [decorate your traffic correctly](/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online#how-to-decorate-your-http-traffic) to avoid throttling. If you choose, you can still provide your own Azure container. ## Encryption is required @@ -18,13 +18,13 @@ For the Migration API to accept a Migration Job coming from a SPO provided Azure ## Advantages -|Advantage|Description| -|:-----|:-----| -|Cost of Azure container goes to SPO|Since we are providing the containers, those containers are now part of the basic SharePoint online Offering. Every tenant who signs up for SharePoint Online will get this for free).| -|Containers and queues are unique per request and not reused|Once a container is given to a customer this container will not be reused or shared.| -|Containers and queue are automatically deleted|As per the standard SharePoint Online Compliance, we will destroy the container within 30 to 90 days automatically.| -|Containers and queues are in the customer’s datacenter location|We make sure to provision containers that are in the same physical location than their SharePoint online tenant.| -|They are obtainable programmatically|There is no need to interact with Azure unless the user chooses. +| Advantage | Description | +| :-------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Cost of Azure container goes to SPO | Since we are providing the containers, those containers are now part of the basic SharePoint online Offering. Every tenant who signs up for SharePoint Online will get this for free). | +| Containers and queues are unique per request and not reused | Once a container is given to a customer this container will not be reused or shared. | +| Containers and queue are automatically deleted | As per the standard SharePoint Online Compliance, we will destroy the container within 30 to 90 days automatically. | +| Containers and queues are in the customer’s datacenter location | We make sure to provision containers that are in the same physical location than their SharePoint online tenant. | +| They are obtainable programmatically | There is no need to interact with Azure unless the user chooses. | ## How to use it @@ -34,16 +34,16 @@ For the Migration API to accept a Migration Job coming from a SPO provided Azure public SPProvisionedMigrationContainersInfo ProvisionMigrationContainers() ``` -The call will return an object that contains two strings containing two SAS tokens for accessing the two required containers and a byte array for the AES256CBC encryption. +The call will return an object that contains two strings containing two SAS tokens for accessing the two required containers and a byte array for the AES256CBC encryption. This key will need to be used when encrypting the data. We forget the key once we give it out, therefore you must keep it to pass it again for the Submit Migration Job call. ```csharp -Uri DataContainerUri +Uri DataContainerUri Uri MetadataContainer Uri -byte[] EncryptionKey +byte[] EncryptionKey ``` ### Getting Queue @@ -66,10 +66,9 @@ Once those calls have been made, the rest of the flow remains the same for using ### Required endpoints for goverment cloud -If your tenant is hosted in a government cloud (GCC), you must have the proper endpoints set when calling the API. -*Example:* usgovcloudapi.net +If your tenant is hosted in a government cloud (GCC), you must have the proper endpoints set when calling the API. For example: `usgovcloudapi.net`. -|**Required Endpoint**|**Why**| -|:-----|:-----| -|https://*.blob.core.usgovcloudapi.net|Migration API Azure Government requirement| -|https://*.queue.core.usgovcloudapi.net|Migration API Azure Government requirement| +| **Required Endpoint** | **Why** | +| :--------------------------------------- | :----------------------------------------- | +| `https://*.blob.core.usgovcloudapi.net` | Migration API Azure Government requirement | +| `https://*.queue.core.usgovcloudapi.net` | Migration API Azure Government requirement | diff --git a/docs/apis/migration-api-encryption.md b/docs/apis/migration-api-encryption.md index 830964a73..c46879621 100644 --- a/docs/apis/migration-api-encryption.md +++ b/docs/apis/migration-api-encryption.md @@ -1,11 +1,12 @@ --- title: OneDrive for Business and SharePoint Online Migration API – Encryption +description: "How to pass encrypted content at rest to the API securely." +ms.date: 6/20/2022 ms.author: jhendr author: JoanneHendrickson manager: pamgreen -ms.date: 6/20/2018 -description: "How to pass encrypted content at rest to the API securely." -localization_priority: Normal +ms.subservice: migration-tool +ms.localizationpriority: medium --- # OneDrive for Business and SharePoint Online Migration API encryption @@ -20,18 +21,19 @@ Content - Files - Manifest - - Metadata - - Permissions - - List items - - Taxonomy - - Logs (created by SharePoint Online to report back on the migration results) + - Metadata + - Permissions + - List items + - Taxonomy + - Logs (created by SharePoint Online to report back on the migration results) - Queue - - Real time reportig on the progress + - Real time reportig on the progress ## What is the encryption feature? -When using the encryption parameter, everything listed above will be encrypted at rest and the key will need to be preserved in order to read the logs and the real time progress. -The main benefits is making the content useless for a malicious user who would manage to breach into the Azure container. +When using the encryption parameter, everything listed above will be encrypted at rest and the key will need to be preserved in order to read the logs and the real time progress. + +The main benefits is making the content useless for a malicious user who would manage to breach into the Azure container. This comes with a small cost of performance. This feature is optional when using the API and it is recommended to only use it for the most confidential information since it does reduce the speed of the migration by a small portion. Microsoft destroys the key once the migration job is finished and there is no way to recover the key if lost, not even from support. @@ -58,10 +60,10 @@ Example: ## Extra requirement -For the encryption, each file must be encrypted and have an IV assigned to it. The encryption method should follow the AES CBC 256 Standard. A unique, cryptographically-random IV must be generated for every file including the manifests in the package and should be stored as a property on each files. Use the AesCryptoServiceProvider.GenerateIV method to generate a unique random IV for each file. +For the encryption, each file must be encrypted and have an IV assigned to it. The encryption method should follow the AES CBC 256 Standard. A unique, cryptographically-random IV must be generated for every file including the manifests in the package and should be stored as a property on each files. Use the AesCryptoServiceProvider.GenerateIV method to generate a unique random IV for each file. -- Name = [IV] -- Value = [Base64encoded byte array of the IV] +- **Name**: [IV] +- **Value**: [Base64encoded byte array of the IV] ## Reading the queue when encrypted @@ -72,13 +74,13 @@ It is important to remember the Job ID. Without the specific key used for the jo Here is the JSON content in the queue message ```json -{"Label", "Encrypted"}, -{"JobId", "[JobId value]"}, -{"IV", "[IV value in base64format]"}, -{"Content", "[encrypted message in base64string]"} +{"Label": "Encrypted"}, +{"JobId": "[JobId value]"}, +{"IV": "[IV value in base64format]"}, +{"Content": "[encrypted message in base64string]"} ``` Once the messages are decrypted, they will be the same as the API without encryption. ->[!NOTE] ->The **Migration** is not available for users of Office 365 operated by 21Vianet in China. It is also not available for users of Office 365 with the German cloud using the data trustee, *German Telekom*. However, it is supported for users in Germany whose data location is not in the German data center. +> [!NOTE] +> The **Migration** is not available for users of Office 365 operated by 21Vianet in China. It is also not available for users of Office 365 with the German cloud using the data trustee, *German Telekom*. However, it is supported for users in Germany whose data location is not in the German data center. diff --git a/docs/apis/migration-api-overview.md b/docs/apis/migration-api-overview.md index e1afcd986..d09416b7e 100644 --- a/docs/apis/migration-api-overview.md +++ b/docs/apis/migration-api-overview.md @@ -1,1575 +1,131 @@ --- -title: "SharePoint Online Import Migration API" -ms.prod: sharepoint -ms.date: 06/22/2021 -ms.author: jhendr -author: JoanneHendrickson -manager: serdars -search.appverid: MET150 -description: "This article provides in depth information on how to use the SPO Migration API." -localization_priority: Priority +title: "SharePoint Import Migration API" +description: "This article provides an overview of how to use the SharePoint Migration API." +ms.date: 07/16/2025 +ms.author: ranren +author: underreview +manager: dapodean +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration --- -# SharePoint Import Migration API (CreationMigrationJob) +# SharePoint Migration API Introduction -## API Documention +The SharePoint Migration API imports content into SharePoint at scale. It processes content and manifest packages as jobs in a queue. The API provides process status and logs, making it easy to monitor the progress of each migration job. -The following API description is based upon use of the SharePoint Client Side Object Model (CSOM). We do recommend using NuGet packages when you reference CSOM in your solution. +Use Migration API to migrate content from file shares, SharePoint Server, and other cloud-based services. -You can find latest version of the SharePoint Online Client Side Object Model (CSOM) package from the [NuGet gallery](https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM/). Use the ID `Microsoft.SharePointOnline.CSOM`. +## What's new ->[!Important] -> Files larger than 15 GB must now create the required checksum using [QuickXorHash](/onedrive/developer/code-snippets/quickxorhash). We have provided an example [here](#what-is-stored-in-those-azure-blob-containers). -> ->The QuickXorHash/Checksum has to be computed for the original file **before** encryption (if the file is being encrypted). This is different from the MD5hash requirementt. -> ->The previous method of MD5Hash is still required for files smaller than 2 GB; however this requirement will be removed at some point in the future. - - -## Methods - -### CreateMigrationJob - -This method creates a new migration import job and queues it up for later processing by a separate timer job. The job will consume a well formed (pre-defined format) import package that is located in the Azure Blob Storage Containers specified in this method. The SLA for migration job processing is be controlled through pre-configured queue and work load throttling settings, and there is no guaranteed SLA or return time for a submitted job. - -#### Syntax - -```csharp -public Guid CreateMigrationJob( - Guid gWebId, - string azureContainerSourceUri, - string azureContainerManifestUri, - string azureQueueReportUri) -``` - -#### Parameters - -##### gWebID - -The unique identifier of the destination web targeted for the package import. Additional information and identifiers for the import are specified within the import package itself. This identifier can be found programmatically by querying the target web using CSOM calls. - -##### azureContainerSourceUri - -The valid URL including SAS token for accessing the Azure Blob Storage Container which contains the binary files of type block. The SAS token must have been created with only Read and List permissions or the migration job will fail. The SAS token should at least have a lifetime that starts no later than when the job was submitted, until a reasonable time for successful import to have concluded.
- -The required permissions are as follows in the Azure Storage API: - -```csharp -(SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.List) -``` - -**Note:** The change to enforce Read and List permissions on the SAS token is coming in a future build. Until then it will not be enforced. However, it is a best practice to use these values. - -All files in the container must have at least a single snapshot applied to them to ensure that no file modification is made by the customer during the import. Any file that does not have a snapshot will be skipped during import and have an error thrown, although the job will attempt to continue the import. The import pipeline will use the latest snapshot of the file available at the time of import. The following is an example of the code that might be used to create a snapshot on a file after it is uploaded to Azure Blob Storage: - -```csharp -CloudBlockBlob blob = blobContainerObj.GetBlockBlobReference(file); -blob.UploadFromStream(stm); -blob.CreateSnapshot(); -``` - -> [!NOTE] -> The change to require and use the latest SnapShots on all files is coming in a future build, and until then will be ignored. - -##### azureContainerManifestUri - -The valid URL including SAS token for accessing the Azure Blob Storage Container which contains the block blobs for the manifest and other package describing XML files. This location will also be used for the log output. This container cannot be the same as the one used for the azureContainerSourceUri. The SAS token must have been created with only Read, List and Write permissions or the migration job will fail. The SAS token should at least have a lifetime that starts no later than when the job was submitted, until a reasonable time for successful import to have concluded. - -> [!NOTE] -> The change to enforce Read, List and Write permissions on the SAS token is coming in a future build, and until then will be not be enforced, however it is best practice to use these values. If an issue arises using a current build, try removing the List permission as a temporary workaround, noting that it will become required soon. - -All files in the container must have at least a single snapshot applied to them to ensure that no file modification is made by the customer during the import. Any file that does not have a snapshot will cause failures during the import and have errors thrown, potentially failing the entire migration job. - -> [!NOTE] -> The change to require and use the latest SnapShots on all files is coming in a future build. Until then they will be ignored. - -##### azureQueueReportUri - -The valid URL including SAS token for accessing the user provided Azure Queue used for returning notifications of migration job progress. This value can be null if no notification queue will be used during the import. If this value is not null and proper access is granted in the SAS token in this URI, it will be used for real time status update. The SAS token must have been created with only Add, Read and Update permissions or the migration job will be unable to add events to the queue. The required permissions are as follows in the Azure Storage API: - -``` -(SharedAccessQueuePermissions.Add | SharedAccessQueuePermissions.Read | SharedAccessQueuePermissions.Update) -``` - -Once accepted, the job ID will be written to the notification queue if it was provided and access is valid. The notification queue can be used for multiple migration jobs at the same time, as each job will identify itself in values sent back to the notification queue. - -The following are examples of all event types logged into the Azure reporting queue: - -**Event:JobQueued** -JobId:845daca4-5529-4b0e-85ab-a603efee5b12 -Time:09/29/2020 19:56:02.883 -SiteId:48917234-de43-474a-9f1b-8d98ffa08425 -DbId:8fd09323-b23f-430d-8957-213586ce3861 -TotalRetryCount:0 -MigrationType:None -MigrationDirection:Import -CorrelationId:c8d97e9f-802f-0000-ceac-44663834d510 - -**Event:JobPostponed** -JobId:845daca4-5529-4b0e-85ab-a603efee5b12 -Time:09/29/2020 19:56:57.598 -NextPickupTime:09/29/2020 20:16:57.519 -SiteId:48917234-de43-474a-9f1b-8d98ffa08425 -DbId:8fd09323-b23f-430d-8957-213586ce3861 -JobsInQueue: -TotalRetryCount:0 -MigrationType:None -MigrationDirection:Import -CorrelationId:d5d97e9f-702c-0000-ceb9-354fefa5e9f6 - -**Event:JobLogFileCreate** -JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecd -Time:09/29/2020 19:56:29.053 -FileName:Import-071f9aad-36e6-4bef-9f09-40b5c7498ecd-1.log -CorrelationId:22ca20ec-23de-468b-add3-4e52e90d3a68 - -**Event:JobStart** -JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecd -Time:09/29/2020 19:56:29.100 -SiteId:48917234-de43-474a-9f1b-8d98ffa08425 -WebId:36b66979-4a43-4b93-9b92-909c7186ff98 -DBId:8fd09323-b23f-430d-8957-213586ce3861 -FarmId:211e600c-f48d-4319-ba92-61150c8e8e8c -ServerId:cfd27448-822a-420b-bcc8-4f39629b01bc -SubscriptionId:51812136-3cba-482d-9696-532cddceab31 -TotalRetryCount:0 -MigrationType:None -MigrationDirection:Import -CorrelationId:c308c0ea-a7f5-4be9-acd4-1ebd39867434 - -**Event:JobProgress** -JobId:845daca4-5529-4b0e-85ab-a603efee5b12 -Time:09/29/2020 19:56:32.265 -FilesCreated:15 -BytesProcessed:45 -ObjectsProcessed:217 -TotalExpectedSPObjects:403 -TotalErrors:0 -TotalWarnings:0 -TotalRetryCount:0 -MigrationType:None -MigrationDirection:Import -WaitTimeOnSqlThrottlingMilliseconds:0 -TotalDurationInMs:0 -CpuDurationInMs:0 -SqlDurationInMs:0 -SqlQueryCount:0 -CreatedOrUpdatedFileStatsBySize:{"0-1K":{"Count":15,"TotalSize":45,"TotalDownloadTime":251,"TotalCreationTime":6754}} -ObjectsStatsByType:{"SPUser":{"Count":1,"TotalTime":289,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPFolder":{"Count":2,"TotalTime":144,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPDocumentLibrary":{"Count":1,"TotalTime":173,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPFile":{"Count":200,"TotalTime":6765,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPListItem":{"Count":14,"TotalTime":2111,"AccumulatedVersions":0,"ObjectsWithVersions":0}} -TotalExpectedBytes:0 -CorrelationId:ccd97e9f-a0cc-0000-ceb9-37a900bec68d - -**Event:JobEnd** -JobId:16d658cf-ecd3-485f-9c9e-1ca268565e24 -Time:09/29/2020 20:29:38.180 -FilesCreated:200 -BytesProcessed:600 -ObjectsProcessed:403 -TotalExpectedSPObjects:403 -TotalErrors:0 -TotalWarnings:0 -TotalRetryCount:0 -MigrationType:None -MigrationDirection:Import -WaitTimeOnSqlThrottlingMilliseconds:0 -TotalDurationInMs:372294.0861 -CpuDurationInMs:17351 -SqlDurationInMs:98359 -SqlQueryCount:1998 -CreatedOrUpdatedFileStatsBySize:{"0-1K":{"Count":200,"TotalSize":600,"TotalDownloadTime":15448,"TotalCreationTime":275662}} -ObjectsStatsByType:{"SPUser":{"Count":1,"TotalTime":44,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPFolder":{"Count":2,"TotalTime":108,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPDocumentLibrary":{"Count":1,"TotalTime":50,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPFile":{"Count":200,"TotalTime":293628,"AccumulatedVersions":0,"ObjectsWithVersions":0},"SPListItem":{"Count":200,"TotalTime":76541,"AccumulatedVersions":0,"ObjectsWithVersions":0}} -TotalExpectedBytes:0 -CorrelationId:59db7e9f-a003-0000-ceb9-300001119ee3 - -**Event:JobDeleted** -JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecd -Time:09/29/2020 19:56:29.053 -CorrelationId:22ca20ec-23de-468b-add3-4e52e90d3a68 - -**Event:JobCancelled** -JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecd -Time:09/29/2020 19:58:29.053 -TotalRetryCount:0 -CancelledByUser:false -MigrationType:None -MigrationDirection:Import -CorrelationId:22ca20ec-23de-468b-add3-4e52e90d3a68 - -**Event:JobError** -JobId:b427d8d7-2b91-4da0-aee5-4b5a5a5d867e -Time: 02/05/2019 06:56:09.732 -TotalRetryCount:0 -MigrationType:None -MigrationDirection:Import -ObjectType:File -Url:Shared Documents/file.pdf -Id:fae7b4b0-2912-11e9-b0f3-7b554a52d6ab -ErrorCode:-2147024816 -ErrorType:Microsoft.SharePoint.SPException -Message:ErrorMessage -CorrelationId:d8e9bc9e-20e2-8000-aa83-48a62fc5ce75 - -**Event:JobWarning** -JobId:b427d8d7-2b91-4da0-aee5-4b5a5a5d867e -Time: 02/05/2019 06:56:09.732 -TotalRetryCount:0 -MigrationType:None -MigrationDirection:Import -ObjectType:File -Url:Shared Documents/file.pdf -Id:fae7b4b0-2912-11e9-b0f3-7b554a52d6ab -ErrorCode:-2147024816 -ErrorType:Microsoft.SharePoint.SPException -Message:ErrorMessage -CorrelationId:d8e9bc9e-20e2-8000-aa83-48a62fc5ce75 - -**Event:FinishManifestFileUpload** -JobId:b427d8d7-2b91-4da0-aee5-4b5a5a5d867e -Time:02/05/2019 06:56:09.732 -ManifestFileName:Filename -CorrelationId:d8e9bc9e-20e2-8000-aa83-48a62fc5ce75 - - -#### Return values - -The unique identifier for the migration job is returned if the job is successfully queued, or if unsuccessful, a null value will be returned. The migration job unique identifier can be used to query the migration job status while it is in the queue or being processed by using the GetMigrationJobStatus method. - -**Example:** - -```csharp -Guid MigrationJobId = TargetSite.CreateMigrationJob( - TargetWebId, - azureContainerSourceUri, - azureContainerManifestUri, - azureQueueReportUri); -``` - -### GetMigrationJobStatus - -This method queries the queue status for the specified migration job. It is an optional check after calling the CreateMigrationJob method. Once the migration job has completed, it will no longer show up in the queue and the notification queue and/or log output should be checked for detailed status. - -#### Syntax - -```xml -[ClientNS.ClientCallableMethod] -public SPMigrationJobState GetMigrationJobStatus(Guid MigrationJobId) -``` - -#### Parameters - -##### Id - -The unique identifier of the migration job returned from CreateMigrationJob method. - -#### Return values - -The migration job status is returned using a SPMigrationJobState object if the job is found in the queue, or if unsuccessful, a value of none (0) will be returned. - -**Example** - -```csharp -SPMigrationJobState CurrentJobState = TargetSite.GetMigrationJobStatus(MigrationJobId); -``` - -## Enumerations - -### SPMigrationJobState - -SPMigrationJobState is an enumeration that tracks possible major states in the import queue. - -#### Members - -| Member name | Description | -| ----------- | --------------------------------------------------------------------------------------------------------------------------- | -| None | Migration job is currently unknown to the queue, either through completion and removal, or invalid job identifier. Value=0. | -| Queued | Migration job is currently known by the queue and not being processed. Value=2. | -| Processing | Migration job is currently known by the queue and is being actively processed. Value=4. | - -## Import Package Structure - -Package structure is based on a constrained version of the Content Deployment package schema. Documentation for the original full schema can be found at [docs.microsoft.com](../schema/content-migration-schemas.md). Until published on docs.microsoft.com, the constrained structure can be found in this document in the appendix. - -| XML file | Schema File | Description | -| ------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| ExportSettings.xml | DeploymentExportSettings Schema | Provides validation for the ExportSettings.XML file exported into the content migration package. ExportSettings.XML does the following:
- Contains the export settings specified by using the SPExportSettings class and other classes that are part of the content migration object model.
- Ensures that the subsequent import process (at the migration target site) enforces the directives specified in the export settings.
- Maintains a catalog of all objects exported to the migration package. | -| LookupListMap.xml | DeploymentLookupListMap Schema | Provides validation for the LookupListMap.XML file exported into the content migration package. LookupListMap.XML maintains a simple lookup list that records SharePoint list item (list item to list item) references. | -| Manifest.xml | DeploymentManifest Schema | Provides validation for the Manifest.xml file that is exported into the content migration package. Provides a comprehensive manifest containing listings of both the contents and the structure of the source site. The migration operation uses the manifest file to reconstitute the source site and its components when it is imported to the destination site. | -| Requirements.xml | DeploymentRequirements Schema | Provides validation for the Requirements.xml file exported into the content migration package. Requirements.xml maintains list of deployment requirements in the form of installation requirements on the migration target, such as feature definitions, template versions, Web Part assemblies, language packs, and so forth. | -| RootObjectMap.xml | DeploymentRootObjectMap Schema | Provides validation for the RootObjectMap.xml file exported into the content migration package.RootObjectMap.xml maintains a list of mappings of secondary (dependent) objects, which allows the import phase of the migration operation to correctly place the dependent objects relative to the locations of the root object mappings. | -| SystemData.xml | DeploymentSystemData Schema | Provides validation for the SystemData.xml file exported into the content migration package.SystemData.xml does the following: Collects a variety of low-level system data. Records the number and names of Manifest.xml files (in cases where the migration uses multiple manifests). | -| UserGroupMap.xml | DeploymentUserGroupMap Schema | Provides validation for the UserGroup.xml file exported into the content migration package. UserGroup.xml maintains a list of users and user security groups with respect to access security and permissions. | -| ViewFormsList.xml | DeploymentViewFormsList Schema | Provides validation for the ViewFormsList.xml file exported into the content migration package.ViewFormsList.xml maintains a list of Web Parts and tracks whether each is a view or form. | - -### Content structure - -File content that is referenced within the manifest of the package structure must be stored in either a flat or hierarchical structure within the Azure Blob Store Container defined by the CreateMigrationJob’s `azureContainerSourceUri` parameter. For example, import packages generated form a legacy version export will not be hierarchical, and will instead have all files stored at the root level with a pattern like ########.dat where the # symbols are hexadecimal characters starting at 0 and no file names are repeated within a package. Alternately, a package generated from a file share can have the source folder hierarchy and file names preserved in the same hierarchy. - -The main requirement for the structure is that the FileValue references in the **Manifest.XML** file must refer to the exact name and physical hierarchy that the content is stored in within the Azure Blob Store location for import. The destination file names and folder hierarchy from the import operation are not directly related to the physical naming and hierarchy and are instead defined through the **Manifest.XML** file. - -### ExportSettings.XML - -The **ExportSettings.XML** file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s `azureContainerManifestUri` parameter. This required file is validated using the constrained DeploymentExportSettings.XSD, which has some limited changes from current published [full 2013 package schema](../schema/content-migration-schemas.md). - -The main requirement is that the ExportSettings `SiteUrl` value must be populated with a URL consistent with the source URL used for the rest of the import package. In the case of file shares as a source, the URL would be pre-specified to be the source URL in the rest of the package, whereas a package generated through an export operation at a source site would be its original source site collection URL. - -### LookupListMap.XML - -The **LookupListMap.XML** file, if included, is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This optional file is validated using the constrained **DeploymentLookupListMap.XSD**, which has no change from current published [full 2013 package schema](../schema/content-migration-schemas.md). - -Since an import package for the pipeline does not include defining fields or views on a list or document library, the **LookupListMap.XML** file will normally include no child nodes under the root and as such can also be excluded from the package if not required, although a warning may be logged in this case. - -### Manifest.XML - -All instances of the **Manifest.XML** file for a package are expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s `azureContainerManifestUri` parameter. This required file is validated using the constrained **DeploymentManifest.XSD**, which has multiple major changes and significant reduction in types from current published [full 2013 package schema](../schema/content-migration-schemas.md). - -The **Manifest.XML** is the primary descriptor for metadata within the package, and provides the list/folder/item hierarchy, along with metadata for the items including references back to users and groups defined in the **UserGroupMap.XML** file. There may be more than one **Manifest.XML** file (which can be identified using different file names to uniquely identify them), and all are found by the import pipeline through references within the **SystemData.XML** file’s ManifestFile entries. - -The main requirements for **Manifest.XML** to be able to successfully import through the pipeline is that the Web Id and Document Library ID/List ID be consistent with the target location. If a Web ID is used which doesn’t match the target location, errors will occur because the parent web for the import operation cannot be found. - -Likewise, an incorrect Document Library ID/List ID will prevent the importation into the target Document Library or List. IDs should never be reused within the same site collection, so same packages should not be imported to the same target site collection regardless of the destination web. - -For individual files and folders within the document library or list, their identifiers should be consistent between import events to the same location. Specifically, performing an import of a package generated from a file share would initially require generating new GUIDs for each file and folder, along with matching GUIDs for the list items that represent them. Therefore, performing a second import against the same target using the same package would keep the same IDs, but performing a second import against the same target using a new package for the same content would result in ID conflicts and import errors for all items in conflict. - -The package generated initially from a file share is effectively a form of record for the original generated IDs and can potentially be used as a reference for follow up package generation to prevent ID collisions when unintended, and to allow like IDs to ensure correct overwrite, deletion or move activities. - -### Requirements.XML - -The **Requirements.XML** file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This optional file is validated using the constrained DeploymentRequirements.XSD, which has no change from current published [full 2013 package schema](../schema/content-migration-schemas.md). - -For file shares this is expected to normally include no child nodes under the root and as such can also be excluded from the package if not required, although a warning will be logged in this case. - -### RootObjectMap.XML - -The **RootObjectMap.XML** file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s `azureContainerManifestUri` parameter. This required file is validated using the constrained **DeploymentRootObjectMap.XSD**, which has some limited changes from current published [full 2013 package schema](../schema/content-migration-schemas.md). The most common `RootObject` that will be included will be a single object of type List. The Id for this item should be the List Id for the target list, and the `ParentWebID` should match the Id of the parent target web containing this list in order for migration to be successful. The Id, WebUrl and Url values of this object must also match the related structure laid out in the **Manifest.XML** file. - -### SystemData.XML - -The **SystemData.XML** file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s `azureContainerManifestUri` parameter. This required file is validated using the constrained **DeploymentSystemData.XSD**, which has no change from current published [full 2013 package schema](../schema/content-migration-schemas.md). - -The `SchemaVersion` information is expected to reference the current Build and DatabaseVersion of the target farm, a Version of “15.0.0.0”, and the `SiteVersion` value is expected to always match the target site collection `UIVersion` (i.e. most commonly this will be “15”). Each **Manifest.XML** file for the package is expected to be listed in this file within the `ManifestFile` entries. - -The SystemObjects that define dependent objects that should remain immutable by the migration code should also be listed here to ensure correct behavior of the import operation. The following is an example of the common objects in the **SystemObjects.XML** file from a file share based import, noting that the IDs are expected to be different for each package, and the URLs may be different. - -#### Table 1: Example SystemData.XML file - -```xml - - - - - - - - - - - - - - -``` - -### UserGroupMap.XML - -The **UserGroupMap.XML** file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s `azureContainerManifestUri` parameter. This required file is validated using the constrained **DeploymentUserGroupMap.XSD**, which has no change from current published full 2013 package schema. - -The **UserGroupMap.XML** file may not contain any User or Group entries but doing so will prevent author or security information from being populated during import and warnings will be logged in this case. Login and SID values for users must be either adjusted to match the values in SharePoint Online, or if the account no longer should exist can be listed as `IsDeleted = “true”` to prevent lookup failures and additional slowdown during the import operation. - -### ViewFormsList.XML - -The **ViewForms.XML** file, if included, is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s `azureContainerManifestUri` parameter. This optional file is validated using the constrained **DeploymentViewFormsList.XSD**, which has no change from current published full 2013 package schema. - -Since an import package for the pipeline does not include defining fields or views on a list or document library, the **ViewFormsList.XML** file will normally include no child nodes under the root and as such can also be excluded from the package if not required, although a warning may be logged in this case. - -## Logging - -The logs that the import pipeline creates must be easily parsed by machine with a goal of being able to pinpoint when and where failures occur, including errors and warnings, and will tell the consumer or the ISV where and why the failure occurred. - -Upon completion, these logs will be copied to the `azureContainerManifestUri` location as the SAS token specified in the URI allows write access. The same output logs are also placed at the *“_catalogs/Maintenance Logs”* location of the target site collection as a text file. The logs will only be copied to the destination locations once the job has finished and removed from the queue. - -Several log types can be included such as the full import log, along with warning and error files that contain only the subset of import warnings or errors respectively. Log files have unique `datetime` and `job id` stamps to allow each attempted import event to have a unique log for better debugging purposes. - -## Changes for those using the "Ship Disk" option - -To use the Migration API, you must have a temporary storage container in Azure. When uploading files into the temporary storage, a checksum is required as a property on every file. For files larger than 15GB, this is done using QuickXorHash (see example below). For files 2 GB or smaller, MD5 is required as a property on every file. - -However, when shipping the data on hard drives this property doesn’t get assigned automatically. As a work around, we have adapted the Migration API to allow the checksum to be passed for every file as part of the manifest. This also applies for IV values when encrypting the data. - -Since the MD5 is generated at the source instead of at the upload time in Azure, Microsoft can confirm the integrity of the file directly against the source MD5. - -## What is stored in those Azure Blob Containers? - -The Migration API requires the Azure Container for content passing and also for log and queue reporting. It can be split down as a summary as follows:
- -| Content | Manifest | -| ----------------- | --------- | -| Files and folders | XML files | - -There are two new optional parameters in manifest.xml: - -- QuickXorHash -- MD5Hash - -### Preparing the package -The method for calling the migration job doesn’t change; only the package generation needs to be changed. - -In the Manifest container one file is named Manifest.xml. There are 2 optional attributes added to the file node: *QuickXorHash* and *MD5Hash*.
- -**Example for files over 15 GB:** - -```xml - - - - - - - - - - - - - - - - - - - - ``` - -**Example for files under 2 GB:** - -```xml - -``` - -## Best Practices and Special Mentions - -### Package size - -Even if the API support 15GB files, we recommend package sizes of up to 250 MB OR 250 items (depending which one comes first). If you have a file larger than that recommended size limit then you should send it in its own package. The same applies to versions; each version counts against the size limit and item count. Additionally, all the versions of a file should be in the same package. - -### File size - ->[!Note] ->The Migration API supports individual files over **15 GB**. The maximum size is current to that set by SharePoint Online. - -### Only un-compressed packages are supported +### December 2024 -The import pipeline does not support compressed packages. The file content must be stored in a different Azure Storage container from the manifest and related descriptive XML files. This decision was made to prevent the overhead of processing time on both ends of the migration (to compress and decompress), and also to ease package creation and modification. Compression of individual files such as into zip archives is supported as long as they are referenced in the import package as the archive itself, not the contents. +We applied quota on *Share with Me* items per user. Check [ShareWithMe event quota](/sharepoint/dev/apis/migration-api-shared#quota) for more detail. -### API supports import of multiple file versions +### November 2024 -Import packages can have references to multiple versions of a file, major and minor, up to regular limits imposed within SharePoint. It is important that each version of that file be included in the package even if some of the versions already exist in SPO. +We enabled logging all file-level events during migration, such as file deletion, to support auditing. -### API supports preservation of identifiers +### July 2024 -The identifiers used within the import package explicitly are used during import to identify content. This allows preservation of existing identifiers for document library contents from a source environment. However, it also imposes a complexity during import package creation or transformation that mandates that the package explicitly reference the target web and list identifiers. Content type identifiers, file/folder item GUIDs, and list item integer identifiers are all preserved during import. If incorrect identifiers are specified in the package, import will fail. +We started enforcing HTTPS connections to SharePoint-provided Azure Blob Storage Containers by adding a `spr=https` field in SAS tokens. This enforcement will be fully effective on July 21, 2024. Check [Use Azure Blob Storage Containers and Azure Queues with SharePoint Migration API](migration-azure.md) for details. -Additionally, due to identifier preservation, import events can potentially be done in successive iterations using different packages, allowing items to potentially move in location if their identifiers have not changed. +### April 2024 -### This is an overwrite API +We added new fields in `JobEnd` events to indicate the count and bytes imported for files. Check [Migration events in Azure Queue](migration-events.md#jobend-import) for details. -The import pipeline does support import of versioning data on files and list item metadata, but as of now if you submit a file and then resubmit the same file with changes the import process will delete and replace the original and all versions with the ones included in the ones in the current package being imported. +### January 2024 -### We do not support Active-Active scenario +We reformatted this document to bring clarity and correct errors. -This means we expect that the target site will remain non-active for users until the migration is over. The source may be kept in a read write state until the final migration event, as a method of reducing downtime for end users, but once the migration is complete there should be a switch for the users to start using their new SPO destinations and stop using the previous repository. +## Migration steps overview -### Permissions in Azure +Start a migration job with three steps. Check the guidance in each of the steps in this section. -To ensure immutability of source blobs, the import pipeline will accept a SAS key with only the Read and List access flags set for the File container. Likewise, the import pipeline requires a SAS key with Read, List and Write access for the Manifest container so that we can write back log files at the end of the import operation. If these criteria are not met, the pipeline will reject it during job creation. +### Provision the destination containers and the queue -### All files in Azure must have snapshot created to import successfully - -To prevent unintended file modification of the source blobs, the import pipeline will only import files if they have a snapshot created for them within Azure. If they do not, then the import pipeline will skip the files in this state and throw errors. The import pipeline will use the latest snapshot of the file available at the time of import. - -### Security and encryption - -The import pipeline is using Azure Blob Storage security model as is. This means we will not do any special treatment for those azure containers that would differentiate from any other azure containers. Additionally, the import pipeline currently does not accept encryption keys for content from the customer. Any encrypted content will be treated as opaque files that SharePoint may list, but be unable to index, the same as if encrypted files were uploaded through the UI to the environment. - -### Events and event handlers - -The import pipeline allows event handlers to be referenced on list items but doesn’t allow defining event handlers at the list level at this time. The import pipeline does not fire events as items are imported, so existing event handlers will not fire due to the import event. - -### Resolving Users - -If the Migration API was unable to resolve a user using the login provided in the UserGroup.xml and no System ID is provided, then: - -1. This user will be replaced by “System Account” in the associated metadata within the package ( author, editor etc.). -1. A warning will be reported in the ImportLogs – “Failed to ensure user 'user@contoso.com'” - -If the migration API was unable to resolve a user using the login provided in the UserGroup.xml and the System ID is provided (which is the SID for the user in the on-premises AD), then: - -1. A new deleted user with the provided login and SystemId is created and is used in the associated metadata within the package. -1. A warning will be reported in the ImportLogs- “Failed to retrieve user 'user@contoso.com' attributes from the SiteUsers; falling back to passed in values” - -## Appendices - -### Acronyms Defined - -| Acronym | Definition | -| ------- | --------------------------------------------------------- | -| BOT | SharePoint server running timer jobs | -| CDB | Content database, containing site collections and content | -| CFE | Content farm front end server | -| SPO | SharePoint Online | -| ABS | Azure Blob Storage | - -### Helpful Resources - -- [SharePoint Online Client Components SDK](https://www.microsoft.com/download/details.aspx?id=42038) -- [Azure Windows Azure SDK for .NET - 2.4](https://www.microsoft.com/download/details.aspx?id=43709) -- [Bulk Creation of OneDrive for Business sites](https://msdn.microsoft.com/library/office/jj163783(v=office.15).aspx) -- [Restrictions and limitations when you sync SharePoint libraries to your computer through OneDrive for Business](https://support.office.com/article/restrictions-and-limitations-when-you-sync-files-and-folders-7787566e-c352-4bd4-9409-fd100a0165f6) -- [Types of files that cannot be added to a list or library](https://support.office.com/Article/Types-of-files-that-cannot-be-added-to-a-list-or-library-30be234d-e551-4c2a-8de8-f8546ffbf5b3?ui=en-US&rs=en-US&ad=US) - -## Working with import package security structures - -This section covers a brief overview of what is contained within an export package that includes security with regard to permissions. This can allow the system to determine user and group membership along with roles, and specific assignments (unique permissions set at the object level and its children unless overridden at a deeper child object). - -### How to interpret the security identifiers in the package files - -UserGroup.xml file defines all users and groups within the exported web(s). The items within this file do the following: - -- User objects include the information about specific users, including identification of a specific security principle as a domain group or not, login, and the base 64 encoded SystemId (SID) of the security principle. -- Group objects include the information about specific groups and the direct membership list of that group. -- Owner values on group objects and UserId values on member objects within group objects map to other Id values of other user or group objects respectively. - -#### Table 2: Users and Groups annotated in UserGroupMap - -```xml - - - - - … - - - - - - - - - - … - - -``` - -**Manifest.xml** contains the metadata about all the content within the exported web(s). The items within this file do the following: - -- Roles objects include the list of defined roles on the web. -- Role objects define the individual role, including ID, internal permissions rights mask flags and display information. - - RoleId values define the identifiers of the Role objects. - - PermMask values contain the rights mask flags. -- RoleAssignments objects include the list of unique permissions (RoleAssignment objects). -- RoleAssignment objects include the list of distinct Assignment objects (if any). -- Individual RoleAssignment objects contain the actual membership of one distinct user or group and their actual Role. - - RoleId values map to the RoleId values of the Role objects. - - PrincipalId values map to Id values of user or group objects respectively in UserGroups.xml. - -#### Table 3: Roles and RoleAssignments annotated in manifest - -```xml - - … - - - - - - - - - - - - - - … - - - … - -``` - -## Constrained XSD structures - -Included below are the XSD files used for package validation in the import pipeline, when different than the original 2013 full schema which can be found at [official SharePoint documentation](../schema/content-migration-schemas.md). - -### DeploymentExportSettings.XSD - -#### Table 4: Constrained DeploymentExportSettings.XSD - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -### DeploymentLookupListMap.XSD -There is no change from current published full 2013 package schema. - -### DeploymentManifest.XSD - -##### Table 5: Constrained DeploymentManifest.XSD - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +> [!IMPORTANT] +> Use [GetMigrationJobProgress API](migration-job-progress-api-reference.md) to retrieve migration job status. +> +> Provisioning Azure Queues for migration job status tracking is no longer required. Deprecation is planned for the second half of 2026. Until then, Azure Queues will remain available for status retrieval. - - +Use the `ProvisionMigrationContainers` method to provision the containers. Check [Use Azure Blob Storage Containers and Azure Queues with Migration API](migration-azure.md) for details. You can also use your own containers and queues if needed. - - +### Prepare the content - - - - - - - - - +Package the contents in the defined format and upload them to Azure Blob Storage Containers as the content package. - - - - - - - +Check [Content package](migration-content-package.md) to see the detailed requirements. - - +### Create the manifest files - - - - - - +Based on the contents, create manifest files in XML format, and upload them to Azure Blob Storage Containers as the manifest package. - - - - +Check [Manifest files](migration-manifest.md) to see the detailed requirements. - - - - - - - - - - - - +### Use Migration API to start the migration and get status - - +The `CreateMigrationJob` method creates a migration job, which is queued up for processing. Migration API manages the queue and returns status and logs. Use the `CreateMigrationEncrypted` method to migrate encrypted contents. Check [SharePoint Migration API Reference](migration-api-reference.md) for details. - - - - +> [!IMPORTANT] +> Use GetMigrationJobProgress API to track migration job status. - +Upon creation of a new migration job, Migration API returns the Job ID. Track the status of the import with [GetMigrationJobProgress API](migration-job-progress-api-reference.md). - - +Migration API generates logs in the manifest container. Check the log entries for migration results. - - +Migration API also generates logs of file-level activities performed by migration. The supported file-level activities include FileUploaded, FileDeleted, FileRenamed, FileMoved. Check M365 Admin Center for activity details when needed. - - +## Best Practice - - - - - +### Use app-based authentication - - - - - - - -``` +Migration generates workload to the SharePoint backend differently from end user-generated traffic. To properly allocate resources with our elastic capability, only use app-based authentication in your migration solution. -### DeploymentRequirements.XSD +Don't use user mode in your migration solution. Running migration in user mode triggers increased throttling, resulting in poor performance. -There is no change from current published [full 2013 package schema](../schema/content-migration-schemas.md). +To learn more about how to register an app ID and how to implement app-based authentication, check [How to register an app ID](/azure/active-directory/develop/active-directory-v2-registration-portal) and [Microsoft Graph Auth guidance](/graph/auth). -### DeploymentRootObjectMap.XSD +### Microsoft Entra ID Permissions -#### Table 6: Constrained DeploymentRootObjectMap.XSD +Microsoft Entra ID provides two types of permission: Delegated Permission and Application Permissions. Check[ +Permissions and consent in the Azure Active Directory v1.0 endpoint](/azure/active-directory/develop/v1-permissions-and-consent) for details. -```xml - - +For SharePoint and OneDrive migration scenarios, follow the Microsoft Entra ID permission specification. - - - - +For migration tools that rely on end-user sign-in and presence, use Delegated permission. - - - - - - - - +For service-based migration tools that run without a signed-in user present, such as applications that run as background services, use Application permission. - - - - - - - - +### App IDs - - - - - +You can choose to share a single App ID to cover multiple migration solutions created or create an individual App ID for each of the products. Make sure to register App IDs. Sharing App IDs doesn't affect performance or throttling. - - -``` +### Keep destination SharePoint Site unactivated -### DeploymentSystemData.XSD +To avoid migration issues, deactivate the target site for users until migration completion. The source could remain active, allowing read and write access to keep productivity. Switch users to the new SharePoint destination sites after migration completion. -There is no change from current published [full 2013 package schema](../schema/content-migration-schemas.md). +## Performance -### DeploymentUserGroupMap.XSD +Migration API processes jobs through a queue mechanism with preconfigured workload management settings. Migration API processes the jobs on a best-effort basis, without Service Level Agreement (SLA) or guaranteed performance. -There is no change from current published full 2013 [full 2013 package schema](../schema/content-migration-schemas.md). +### Optimize migration performance -### DeploymentViewFormsList.XSD +In order to ensure optimal performance for your migration projects, it's important to plan carefully, especially when dealing with large-scale migrations. For more information on how to estimate timespans and optimize performance, see our [performance guide](/sharepointmigration/sharepoint-online-and-onedrive-migration-speed). -There is no change from current published [full 2013 package schema](../schema/content-migration-schemas.md). +### I'm seeing throttling messages -## Sample: Using REST to call the API +To ensure good user experiences for all Microsoft 365 customers, SharePoint uses throttling to protect the SharePoint infrastructure. Avoid getting throttled by following [throttling guidance](https://aka.ms/spo429). -```http -https://{site_url}/_api/site/CreateMigrationJobEncrypted +## Special articles -{ - "options": { - "AES256CBCKey": "000000000000000000000000000000000000000000000000000000=" - }, - "gWebId": "00000000-0000-0000-0000-000000000000", - "azureContainerSourceUri": "https://tenant.blob.core.windows.net:443/00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=rw", - "azureContainerManifestUri": "https://tenant.blob.core.windows.net:443/00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=rw" -} -``` +### Migrating sharing events of files and folders -For the container: +Check [Sharing events](/sharepoint/dev/apis/migration-api-shared) article for instructions when migrating shared events metadata with files and folders. -```http -https://{site_url}/_api/site/ProvisionMigrationContainers -``` +### Web Parts -> [!NOTE] -> The **Migration API** is not available for users of Office 365 operated by 21Vianet in China. It is also not available for users of Office 365 with the German cloud using the data trustee, *German Telekom*. However, it is supported for users in Germany whose data location is not in the German data center. +Use SharePoint Migration Tool (SPMT)'s Web Part serializer DLL to migrate Web Parts into SharePoint. Check [Migrate Web Parts](/sharepoint/dev/apis/migrate-webparts-with-migrationapi) for instructions. diff --git a/docs/apis/migration-api-reference.md b/docs/apis/migration-api-reference.md new file mode 100644 index 000000000..0db09f400 --- /dev/null +++ b/docs/apis/migration-api-reference.md @@ -0,0 +1,232 @@ +--- +title: "SharePoint Migration API Reference Guide" +description: "This article provides in-depth information on how to use the SharePoint Migration API." +ms.date: 07/16/2025 +ms.author: ranren +author: underreview +manager: dapodean +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- + +# SharePoint Migration API Reference Guide + +This guide describes the usage of SharePoint Migration API, which imports content into SharePoint, based on manifest files. + +## CSOM and REST + +Migration API supports both SharePoint Client Side Object Model (CSOM) and REST. + +### Use NuGet Packages with CSOM + +To reference the SharePoint Client Side Object Model (CSOM) in your solution, use NuGet packages. + +Manage dependencies easily and ensure your solution is using the latest version of the CSOM library with NuGet packages. + +Get the latest version of the CSOM package at the [SharePoint Client-side Object Model Libraries](https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM) with the ID `Microsoft.SharePointOnline.CSOM`. + +Check [Get to know SharePoint REST service](/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service) for instructions on REST API. + +## CreateMigrationJob method + +Creates a new migration import job with the import package specified in `azureContainerSourceUri` parameter. + +### CreateMigrationJob syntax + +```csharp +public Guid CreateMigrationJobEncrypted( +Guid gWebId, +string azureContainerSourceUri, +string azureContainerManifestUri, +string azureQueueReportUri, +EncryptionOption AES256CBCKey +) +``` + +```rest +POST https://{site_url}/_api/site/CreateMigrationJobEncrypted +{ + "options": { + "AES256CBCKey": "000000000000000000000000000000000000000000000000000000=" + }, + "gWebId": "00000000-0000-0000-0000-000000000000", + "azureContainerSourceUri": "https://tenant.blob.core.windows.net:443/00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=rw", + "azureContainerManifestUri": "https://tenant.blob.core.windows.net:443/00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=rw" +} +``` + +### CreateMigrationJob parameters + +#### gWebID + +Required. + +A **String** value that contains the unique identifier of the destination web targeted for the package import. The import package itself specifies additional information and identifiers for the import. You can programmatically find this identifier by querying the target web using CSOM calls. + +#### azureContainerSourceUri + +Required. + +A **String** value that contains the valid URI, including the SAS token, to access the Azure Blob Storage Container that contains the binary files of type block. + +See [Use Azure Blob Storage Containers and Azure Queues with SharePoint Migration API](migration-azure.md) for instructions on using Azure Blob Storage Containers in migration. + +When using content containers not provided by this method, Migration API requires `Read`, and `List` permissions only. Ensure that the start time of the SAS token is set at or before the job submission. Also, when setting the expiration time, allow a reasonable duration for the import process to complete. + +Migration API doesn't require `List` permission from containers provisioned with `ProvisionMigrationContainers` method. + +#### azureContainerManifestUri + +Required. + +A **String** value that contains the valid URI, including the SAS token, to access the Azure Blob Storage Container, which contains the block blobs for the manifest and other packages describing XML files. Migration API writes log to this container. This container can't be the same as the one used for the `azureContainerSourceUri`. + +See [Use Azure Blob Storage Containers and Azure Queues with SharePoint Migration API](migration-azure.md) for instructions on using Azure Blob Storage Containers in migration. + +When using content containers not provided by this method, Migration API requires `Read`, `List`, and `Write` permissions only. Ensure that the start time of the SAS token is set at or before the job submission. Also, when setting the expiration time, allow a reasonable duration for the import process to complete. + +#### azureQueueReportUri + +Optional. + +A **String** value that contains the valid URL, including the SAS token, to access the user-provided Azure Queue for migration job progress. Use `null` if receiving import status updates isn't necessary. + +If this value isn't `null`, and the SAS token contains the correct permissions, Migration API writes import status updates to the queue at the URL provided. + +Share the notification queue among multiple migration jobs. Migration API identifies each job with unique Job ID values in the notification queue. + +See [Azure](migration-azure.md) for instructions on using Azure Queue in migration. Check [Migration events in Azure Queue](migration-events.md) for types of events. + +Requires `Add`, `Read`, and `Update` permissions only. If the SAS token has other permissions, the migration job will be unable to add events to the queue. + +### CreateMigrationJob return value + +#### Job ID + +A **Guid** value, which contains Job ID, the unique identifier of the migration job. The method returns a `null` value, if it fails to create the job. Use Job ID to query the status of migration jobs with `GetMigrationJobStatus` method. + +### Example + +```csharp +Guid MigrationJobId = TargetSite.CreateMigrationJob( +TargetWebId, +azureContainerSourceUri, +azureContainerManifestUri, +azureQueueReportUri); +``` + +## CreateMigrationJobEncrypted method + +Creates a new migration import job with an encrypted PRIME package. + +Check the encryption instructions in [Azure](migration-azure.md) for Azure Blob Storage Container and Azure Queue encryption used. + +### CreateMigrationJobEncrypted syntax + +```csharp +public Guid CreateMigrationJobEncrypted( +Guid gWebId, +string azureContainerSourceUri, +string azureContainerManifestUri, +string azureQueueReportUri, +EncryptionOption AES256CBCKey +) +``` + +```rest +POST https://{site_url}/_api/site/CreateMigrationJobEncrypted +{ + "options": { + "AES256CBCKey": "000000000000000000000000000000000000000000000000000000=" + }, + "gWebId": "00000000-0000-0000-0000-000000000000", + "azureContainerSourceUri": "https://tenant.blob.core.windows.net:443/00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=rw", + "azureContainerManifestUri": "https://tenant.blob.core.windows.net:443/00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=rw" +} +``` + +### CreateMigrationJobEncrypted parameters + +`gWebID`, `azureContainerSourceUri`, `azureContainerManifestUri`, and `azureQueueReportUri` parameters have the same requirements as in `CreateMigrationJob` method. + +Provide `EncryptionOption` parameter as instructed below. + +#### EncryptionOption + +Required. + +A `EncryptionOption` object, containing the AES256CBCKey used to decrypt the output. + +Migration API encrypts the output with the AES256CBCKey key supplied. + +See `[EncryptionOption](https://learn.microsoft.com/en-us/dotnet/api/microsoft.sharepoint.client.encryptionoption)` class for details. + +### CreateMigrationJobEncrypted return value + +See Return value in `CreateMigrationJob` method. + +## GetMigrationJobStatus method + +> [!IMPORTANT] +> Use [GetMigrationJobProgress API](migration-job-progress-api-reference.md) to retrieve migration job status. Deprecation of GetMigrationJobStatus API is planned for the second half of 2026. Until then, it will remain available for status retrieval. + +Retrieves the processing status for a designated migration job. + +Migration API removes completed migration jobs from the timer job queue. Check the notification queue and/or log outputs for import results. + +### GetMigrationJobStatus syntax + +```csharp +[ClientNS.ClientCallableMethod] +public SPMigrationJobState GetMigrationJobStatus(Guid MigrationJobId) +``` + +### GetMigrationJobStatus parameters + +#### ID + +Required. + +A **Guid** value, which contains the migration Job ID, is returned from `CreateMigrationJob`. + +### GetMigrationJobStatus return value + +A `SPMigrationJobState` object, which contains the status of the migration job. + +### GetMigrationJobStatus example + +```csharp +SPMigrationJobState CurrentJobState = TargetSite.GetMigrationJobStatus(MigrationJobId); +``` + +## SPMigrationJobState enumeration + +Contains members representing the status of migration jobs in the import queue. + +### SPMigrationJobState members + +#### None + +Value: 0 + +The queue doesn't contain the migration job with the Job ID. The possible reasons are: + +- Migration API has completed the job and removed it from the queue. +- The Job ID is invalid. + +#### Queued + +Value: 2 + +The queue contains the migration job. Migration API isn't processing the job. + +#### Processing + +Value: 4 + +The queue contains the migration job. Migration API is processing the job. diff --git a/docs/apis/migration-api-shared.md b/docs/apis/migration-api-shared.md index f0ecb7f18..dfcc26fd9 100644 --- a/docs/apis/migration-api-shared.md +++ b/docs/apis/migration-api-shared.md @@ -1,74 +1,84 @@ --- title: "SPO Migration API: Migrating shared files and folders" -ms.author: jhendr -author: JoanneHendrickson -manager: pamgreen -ms.topic: article description: "Migrating shared files and folders using item references." ---- - - +ms.date: 06/28/2022 +ms.author: jihongzuo +author: shiongzuo +manager: Dan.Podeanu +ms.topic: article +ms.subservice: migration-tool +--- # Migrating shared files and folders ## Implementation As documented in the Migration PRIME API, apply sharing metadata by using **item references**. The older method of using the *Shared With* column should not be used any further. -For an item that is shared with a user, add the **SharedWithEvents** block within its *ListItem* block. The **SharedWithEvents** block represents an occurrence when the item was shared, including the user who did the sharing (SharingInitatiorId and SharedById), as well as the time of sharing (SharedTime). +For an item that is shared with a user, add the **SharedWithEvents** block within its *ListItem* block. The **SharedWithEvents** block represents an occurrence when the item was shared, including the user who did the sharing (SharingInitatiorId and SharedById), as well as the time of sharing (SharedTime). Add a SharedWithMember block for each person that the item was shared with during that occurrence. All user ids must be valid entries in the UserGroup.xml. ```XML - - - - - - - - - - - + + + + + + + + + + ``` + ## Best Practices + ### The basics + For each file or folder that was shared with a user in the source, create an item reference for that item in the recipient’s OneDrive. Every item reference created will appear in the user’s *Shared with Me* view in OneDrive. Remember to give the user permission to access the item as well. ### Inheritance -Be sure to use inheritance correctly for sharing. When creating an item reference for a file or folder, check if its parent folder (or higher) already has an item reference created for it. If so, do not create another one for the child item. This will prevent users from seeing duplicate items in their *Shared with Me* view and reduce migration and service load as well. -**Example:** When a folder is shared and the recipient can access all of the folder’s contents, an item reference should *only* be created for the shared folder -- not for its contents. The only item that should appear in the recipients *Shared with Me* is the shared folder. +Be sure to use inheritance correctly for sharing. When creating an item reference for a file or folder, check if its parent folder (or higher) already has an item reference created for it. If so, do not create another one for the child item. This will prevent users from seeing duplicate items in their *Shared with Me* view and reduce migration and service load as well. + +**Example:** When a folder is shared and the recipient can access all of the folder’s contents, an item reference should *only* be created for the shared folder -- not for its contents. The only item that should appear in the recipient's *Shared with Me* is the shared folder. -This same guidance should also be used for permissions (ACLs). Only apply permissions on a child item where the required permissions are different than its parent item. Make sure not to exceed 5000 unique ACLs on a site. It may be useful to check how many ACLs you create and warn the user prior to migration. There is also a hard limit of 50,000 unique ACL's that will be enforced. If you are close to reaching the 5000 limits, we recommend that the permission model be simplified on the source before migration. +This same guidance should also be used for permissions (*access control lists, also known as ACLs*). Only apply permissions on a child item where the required permissions are different than its parent item. Make sure not to exceed 5000 unique ACLs on a site. It may be useful to check how many ACLs you create and warn the user prior to migration. There is also a hard limit of 50,000 unique ACLs that will be enforced. If you are close to reaching the 5000 limits, we recommend that the permission model be simplified on the source before migration. ### Sharing with groups + For items shared with a group of individuals in the source, the content may be migrated into a shared library (eg. a team site) in which all of those individuals are given access. ### Anonymous sharing links + Do not migrate anonymous sharing links from the source; this is not useful as it’s not possible to know which users used that link in the source. Users should evaluate whether anonymous links are still needed and create new ones on the destination if so. ### Sharing with external users -Before starting migration, you must ensure all users are provisioned in the customer tenant. For users external to the tenant (ie. from a different organization), provision them as B2B collaboration users in Azure Active Directory. This is done in the Azure portal following these steps: -- [Add Azure Active Directory B2B collaboration users in the Azure portal](/azure/active-directory/b2b/add-users-administrator). +Before starting migration, you must ensure all users are provisioned in the customer tenant. For users external to the tenant (ie. from a different organization), provision them as B2B collaboration users in Azure Active Directory. This is done in the Azure portal following these steps: + +- [Add Azure Active Directory B2B collaboration users in the Azure portal](/azure/active-directory/b2b/add-users-administrator). Once the external users are provisioned, share files and folders with them during migration the same way as internal users. ### Permission and Sharing -The per user sharing model in SharePoint relies on both permissions and “Shared With” data references for an object to be considered shared with an individual. If a user has access to content, but no “Shared With” references, they will not see the content show up in their Shared With Me view within their OneDrive For Business site. + +The per-user sharing model in SharePoint relies on both permissions and “Shared With” data references for an object to be considered shared with an individual. If a user has access to content, but no “Shared With” references, they will not see the content show up in their Shared With Me view within their OneDrive For Business site. However, if they are indicated in “Shared With” references but do not have any access to the content, they will either never see the content show up in their Shared With Me view within their OneDrive For Business site or when they try to use a link from there it will be denied access. To preserve sharing information, both the permissions and “Shared With” references will need to be correctly set. The permissions can be set at different levels of the content hierarchy using scopes (unique ACLs), that apply to that object and any of its children unless they themselves have unique permissions. -Using PRIME, content can be migrated by using SPFile/SPFolder objects with a document library followed by SPListItem objects that reference the imported File/Folder objects. During the ListItem import, the “Shared With” references data can be imported, and then the security can be applied afterward within the same migration package, by setting up scopes (ACLs) and role assignments (ACEs) for the content hierarchy as needed. +Using PRIME, content can be migrated by using SPFile/SPFolder objects with a document library followed by SPListItem objects that reference the imported File/Folder objects. During the ListItem import, the “Shared With” references data can be imported, and then the security can be applied afterward within the same migration package, by setting up scopes (ACLs) and role assignments (ACEs) for the content hierarchy as needed. Permissions migration is performed using the DeploymentRoleAssignments object with RoleAssignment entries representing specific scopes and Assignment entries representing assignments of specific roles to specific principals. Since this code ends up breaking inheritance for content and applying the specified role assignments, it has the same limitations as using other object model approaches to setting permissions in SharePoint. +> [!NOTE] +> The **Migration API** is not available for users of Office 365 operated by 21Vianet in China. + +### Quota ->[!NOTE] ->The **Migration API** is not available for users of Office 365 operated by 21Vianet in China. It is also not available for users of Office 365 with the German cloud using the data trustee, *German Telekom*. However, it is supported for users in Germany whose data location is not in the German data center. +Do not migrate more than 1,000 *Share with Me* events for any receiver within 24 hours. If a receiver already has 1,000 *Share with Me* events being imported within 24 hours, they will NOT receive any additional *Share with Me* events during the time window. And Import API will send back warning messages indicating some *Share with Me* events have been throttled. diff --git a/docs/apis/migration-api-video-transcripts.md b/docs/apis/migration-api-video-transcripts.md new file mode 100644 index 000000000..324d77d57 --- /dev/null +++ b/docs/apis/migration-api-video-transcripts.md @@ -0,0 +1,66 @@ +--- +title: "Exporting video transcripts when using the SharePoint Import Migration API" +description: "Learn how to export videos that contains a transcript as an alternate content stream." +ms.date: 06/30/2023 +ms.author: jhendr +author: JoanneHendrickson +manager: serdars +search.appverid: MET150 +ms.subservice: migration-tool +--- + +# How to export video transcripts using the SharePoint Important Migration API + +Transcripts of video files, like those in Teams meeting recordings, are stored in a format similar to a zip file. If you are migrating videos from one source to another, you must use a new flag to ensure the entire zip file is migrated to the destination. Otherwise, you will inadvertently leave behind the alternate content stream, the transcript. + +## Step 1: Check if the file contains alternate content streams + +1. Check to see if the SPFile object has the property **SPFile.HasAlternateContentStreams**. Use the [REST or CSOM API](/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest) to fetch this property value. +3. If set to **True**, the file contains alternate content streams. + + +***Example:*** + +```powershell + +GET https://{site_url}/_api/web/GetFileByServerRelativeUrl(‘/serverrelativeurl’)/HasAlternateContentStreams + +``` + +## Step 2: Download the file with alternate content streams + +A zip formatted stream including primary and alternate streams can be downloaded if the file request includes **SPOpenBinaryOptions.GetAsZipWithAltStreamsIfAvailable**. + +1. Use [REST or CSOM API](/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest) to download the zip formatted content stream. +2. You must include **SPOpenBinaryOptions.GetAsZipWithAltStreamsIfAvailable**. If this is not specified, only the primary file content stream is returned. + +***Example:*** + +```powershell + +GET https://{site_url}/_api/web/GetFileByServerRelativeUrl(‘/serverrelativeurl’)/OpenBinaryStreamWithOptions(openOptions=1048576) + +``` +Note: In the example above, "1048576" corresponds to the integer value of enum *SPOpenBinaryOptions.GetAsZipWithAltStreamsIfAvailable*. + +## Step 3: Import the file with alternate content streams + +Use the Migration API to import the zip formatted stream for a file with alternate content streams to SPO. The main steps involved are: + + +1. Upload the zip formatted stream downloaded with *SPOpenBinaryOptions.GetAsZipWithAltStreamsIfAvailable* as the primary file to the Azure location. +2. When preparing the migration Manifest .xml file, add the property **vti_hasAlternateContentStreams** to the SPFile object with the value of **TRUE**. +3. Call the Migration API as normal. Internally, SPO will unzip the provided content stream and set the primary file stream and associated alternate content streams correctly. +4. After the import, verify the property **SPFile.HasAlternateContentStreams** to confirm if it’s set to **True**. + +***Example:*** + +```powershell + + + + + + + +``` diff --git a/docs/apis/migration-api-whats-new.md b/docs/apis/migration-api-whats-new.md new file mode 100644 index 000000000..aec43a338 --- /dev/null +++ b/docs/apis/migration-api-whats-new.md @@ -0,0 +1,73 @@ +--- +title: "Migration API What's new" +description: "Learn about the new features and updates to the Migration API." +ms.date: 09/26/2023 +ms.reviewer: jhendr +author: JoanneHendrickson +ms.author: jhendr +manager: serdars +audience: ITPro +ms.topic: article +ms.subservice: migration-tool +localization_priority: Priority +ms.custom: admindeeplinkSPO +--- +# What's new in the Migration API + +Check here to see what features or updates have been added to the Migration API. Here's a summary of what's included. + +## Encoding invalid XML characters + +When invalid XML characters are detected in relevant fields, they're encoded. For any attribute that is XML encoded, decoding is needed for the value. Encoded fields are included in `EncodedAttributes`, in a comma-separated attribute list. + +**Example** + +In this example, these attributes are encoded: URL, ParentWebURL, Name, and Version. + +```xml + +``` + +>[!Warning] +>If XSD is replied on to parse manifest files, parsing may fail when **EncodedAttributes** is used. + + +## Updated reason code and descriptions + +We have updated Migration API to provide detailed reasons in case a job is postponed. We encourage ISVs take appropriate actions, based on the reasons. + +|Possible reasons |Code|Description| +|:-----|:-----|:-----| +|JobInQueue:Resource|1,2,3,4, 5, 6, 12|The job is now in a queue for resource allocation. It is expected to start in [P75] time.| +|JobInQueue:DBMaint|7|The destination tenant's database is currently in maintenance. The job is in a queue to be executed when the maintenance is completed. We expect the maintenance to be completed at [P75] time.| +|JobFailure:TenantBlock|10|Migration is blocked at the destination tenant. The job is cancelled. Please check tenant status before resubmitting.| +|JobCancelled:Unknown|11|The migration job is canceled for unknown reason.| + + +## New: Speed up small file migration + +The migration package includes multiple files, which are each uploaded/downloaded individually. If you have a large number of small-sized files, migration speed drops dramatically. By using the new **ArchivedFiles.XML** file in your prime package you can transfer files in batch resulting in a faster migration. [Learn more about using the ArchivedFiles.XML](/sharepoint/dev/apis/migration-api-overview#archivedfilessxml) + +## SourceType field required + +Beginning April 1, 2023, the SourceType field is mandatory when calling the Migration API. Starting October 1st, 2022, a warning message will be sent if the field is missing. + +To learn more, including examples, see: **[SharePoint Import Migration API - ExportSettings.xml](/sharepoint/dev/apis/migration-api-overview#exportsettingsxml)** + +## Fixes + +- **Changes to how Import API handles users**. As a response to issues arising from broken OneDrive scenarios when importing duplicate users, the API now blocks and detect duplicate user entries in UserGroup.xml. For details see: [Entering user identifiers in UserGroup.xml](/sharepoint/dev/apis/migration-api-overview#entering-user-identifiers-in-usergroup.xml). diff --git a/docs/apis/migration-azure.md b/docs/apis/migration-azure.md new file mode 100644 index 000000000..3dddc87b8 --- /dev/null +++ b/docs/apis/migration-azure.md @@ -0,0 +1,149 @@ +--- +title: "Use Azure Blob Storage Containers and Azure Queues with SharePoint Migration API" +description: "This article provides in-depth information on how to use the SharePoint Migration API with Azure Containers and Queues." +ms.date: 07/03/2024 +ms.author: ranren +author: underreview +manager: dapodean +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- + +# Use Azure Blob Storage Containers and Azure Queues with SharePoint Migration API + +Use Azure Blob Storage Containers to store contents, manifest files, and logs. Access migration status updates with Azure Queues. + +This guide provides provisioning, permission, and other requirements with SharePoint-provided Azure resources. + +## Azure Blob Storage Containers + +Migration API uses Azure Blob Storage Containers for temporary storage of content and manifest. SharePoint provides default containers for migration. Alternatively, you can provide your own containers. + +### Using SharePoint-provided containers + +SharePoint-provided containers have no extra cost to the customer. Provision SharePoint-provided containers with `ProvisionMigrationContainers` method, without the need to manually set up in the Azure admin console. + +Migration API provisions the containers in the same datacenter of the SharePoint instance. Migration API uses a container exclusively once for each request, to ensure security. + +Migration API destroys Used containers 30-90 days after completing migration jobs. + +#### Avoid throttling by decorating the traffic + +Avoid throttling by [decorating your HTTP traffic](/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online#how-to-decorate-your-http-traffic). + +#### Encryption + +The contents stored in SharePoint-provided containers are encrypted at rest with AES256CBC algorithm. This practice is mandatory. Migration API rejects migration jobs generated from unencrypted SharePoint-provided containers. + +This encryption requirement doesn't apply to user-provided containers. + +When using `CreateMigrationJobEncrypted` method, encrypt each file with AES CBC 256 standard as the encryption algorithm. + +Use the `AesCryptoServiceProvider.GenerateIV` method to generate a unique cryptographically random IV for each file, including the manifests in the package. Store the IV as a property on each file. + +##### Name + +IV + +##### Value + +A `BASE64` encoded **Byte Array** of the generated IV + +#### ProvisionMigrationContainers method + +Provisions new SharePoint-provided migration containers for content and manifest. + +##### Syntax + +```csharp +public SPProvisionedMigrationContainersInfo ProvisionMigrationContainers() +``` + +##### Return values + +An `SPProvisionedMigrationContainersInfo` object, containing the URI, access tokens, and encryption key of the provisioned containers. + +###### DataContainerUri value + +A **Uri** value containing the URI of the newly created container for storing migration **content**, along with the SAS access token. + +Pass this value to `CreateMigrationJob` method as `azureContainerSourceUri` parameter. + +The SAS access token contains `Read` and `Write` permissions only. It doesn't contain `List`. + +SharePoint enforces HTTPS connections to containers by setting `spr=https` field in SAS tokens. + +###### MetadataContainer value + +A **Uri** value containing the URI of the newly created container for storing **manifest** files, along with the SAS access token. + +Pass this value to `CreateMigrationJob` method as `azureContainerManifestUri` parameter. + +The SAS access token contains `Read` and `Write` permissions only. It doesn't contain `List`. + +SharePoint enforces HTTPS connections to containers by setting `spr=https` field in SAS tokens. + +###### EncryptionKey + +A **Byte Array** value containing the AES256CBC encryption key for both containers provisioned. + +### Use your own containers + +You can also provide your own Azure Blob Storage Containers. Provide the URI with SAS access tokens as required in the Migration API reference. + +## Azure Queues + +SharePoint-provided Azure Queues have no extra cost to the customer. Provision the queue with `ProvisionMigrationQueue` method, without the need to manually set up in Azure admin console. + +Migration API provisions Azure Queues in the same datacenter of the SharePoint instance. + +Alternatively, use user-provided Azure Queues if desired. Check the requirement in the Migration API Reference document. + +### Azure Queue Encryption + +`CreateMigrationJobEncrypted` method encrypts the messages written to the Azure Queue. + +To decrypt the messages, make sure you preserve `JobId` and the `IV` values returned by `CreateMigrationJobEncrypted` method. + +#### Encrypted message sample + +```json +{"Label": "Encrypted"}, +{"JobId": "[JobId value]"}, +{"IV": "[IV value, encoded in BASE64]"}, +{"Content": "[encrypted message, encoded in BASE64]"} +``` + +### ProvisionMigrationQueue method + +Provisions a new instance of Azure Queue for migration use. + +#### ProvisionMigrationQueue Syntax + +```csharp +public SPProvisionedMigrationQueueInfo ProvisionMigrationQueue() +``` + +#### Return value + +A `SPProvisionedMigrationQueueInfo` object containing the information of the newly created Azure Queue. + +##### JobQueueUri value + +A `Uri` value containing the URI and SAS access token of the newly created Azure Queue. + +Pass this value to `CreateMigrationJob` method's `azureQueueReportUri` parameter. + +## Use endpoints in Azure Government + +Use Azure Government endpoints for Microsoft 365 Government. + +### Required endpoints in Azure Government + +- `https://*.blob.core.usgovcloudapi.net` +- `https://*.queue.core.usgovcloudapi.net` diff --git a/docs/apis/migration-content-package.md b/docs/apis/migration-content-package.md new file mode 100644 index 000000000..6de44cbfe --- /dev/null +++ b/docs/apis/migration-content-package.md @@ -0,0 +1,113 @@ +--- +title: "Preparing the content for Migration API" +description: "This article provides in-depth information on how to use create and use content packages with SharePoint Migration API" +ms.date: 04/18/2024 +ms.author: ranren +author: underreview +manager: dapodean +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- + +# Preparing the content for Migration API + +Use this document to prepare the contents to migrate with SharePoint Migration API. + +## Files and folders + +### File and package size limits + +Migration API supports importing files with sizes up to 15 GB (the limit set by SharePoint). + +For the best performance, keep the package size under 250 MB or 250 items. + +For larger files, create a package for the individual file. + +### File versions + +Migration API supports importing multiple versions of a file, including major and minor, up to the limit set by SharePoint. + +Each version of the file counts against the file size limit and item count limit. + +Include each version of the file, even if some of the versions already exist in SharePoint. + +### File overwriting + +Migration API deletes the original file along with all the versions, then replaces it with all versions of the resubmitted file, when a file is resubmitted. + +### No decryption + +Migration API doesn't decrypt contents. It treats any encrypted content as opaque files. While SharePoint lists these files, it doesn't index them. This behavior is the same as when a user uploads encrypted files through the SharePoint UI. + +### File compression + +Migration API doesn't decompress packages by default. Don't compress content and manifest packages together. Make sure you store the content package and the manifest package in different Azure Storage Blob Containers. + +Migration API imports **\*.zip** files as compressed archive files if referenced in the import package as the archive itself. To import the individual files within the **\*.zip** file, see [Archive Small Files](#archive-small-files-for-performance). + +### Archive small files for performance + +Migrate small files in batches for improved performance. Migration API **optionally** uncompresses a compressed **\*.zip** archive to improve the performance, based on manifest in **ArchivedFiles.xml**. + +Include `QuickXorHash` value of the archive when using this feature. Compute it with [QuickXorHash Algorithm](/onedrive/developer/code-snippets/quickxorhash). + +Migration API processes non-archived files in **Manifest.xml** without manifest in **ArchiveFiles.xml** as usual. + +This feature requires all the following prerequisites: + +#### Archive file size limit + +10 MB maximum. + +#### Archive file per package + +Two maximum. + +#### Archive file encryption + +Required. + +#### Individual file size + +Less than 100 kb after encryption. + +#### Don't compress individual files + +**Don't compress** the individual files, only compress the archive. + +## SharePoint Events and Event Handlers + +Migration API allows referencing Event Handlers on List Items. However, Migration API doesn't support defining new Event Handlers at the List level. + +Migration API doesn't generate Events when importing items. Therefore, existing Event Handlers don't fire during import. + +## Azure Containers + +### Azure Blob Storage Security Model + +Migration API uses Azure Blob Storage security model. There's no special treatment for Azure Blob Storage Containers used for Migration API that would differentiate from a standard container. + +### Snapshot + +Each file in the container must have at least one snapshot created. Avoid modifying the file during the import. Any file without a snapshot fails to import with errors. Migration API uses the latest snapshot of the file available at the time of import. + +To create a snapshot of a file after uploading to the Azure Blob Storage, use the following code: + +```csharp +CloudBlockBlob blob = blobContainerObj.GetBlockBlobReference(file); +blob.UploadFromStream(stm); +blob.CreateSnapshot(); +``` + +### Permissions + +To ensure the immutability of source blobs, Migration API accepts an SAS key with only `Read` and `List` access flags set for the content package container. + +Likewise, Migration API accepts a SAS key with only `Read`, `List`, and `Write` access for the Manifest container. Migration API requires the `Write` access for writing backlog files at the end of the import. + +Migration API checks SAS keys for these required access flags. Migration API rejects attempts to create migration jobs with incorrect access flags on SAS keys. diff --git a/docs/apis/migration-events.md b/docs/apis/migration-events.md new file mode 100644 index 000000000..dcd8c2209 --- /dev/null +++ b/docs/apis/migration-events.md @@ -0,0 +1,269 @@ +--- +title: "Migration events in Azure Queue" +description: "This article provides in-depth information on how to use Azure Queue events in migration." +ms.date: 04/18/2024 +ms.author: ranren +author: underreview +manager: dapodean +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- +# Migration events in Azure Queue + +This document lists all types of events Migration API and AMR API written to the Azure Queue. Use these events to get status updates on migration jobs. + +## JobQueued + +```log +JobId:845daca4-5529-4b0e-85ab-a603efee5b12 +Time:09/29/2020 19:56:02.883 +SiteId:48917234-de43-474a-9f1b-8d98ffa08425 +DbId:8fd09323-b23f-430d-8957-213586ce3861 +TotalRetryCount:0 +MigrationType:None +MigrationDirection:Import +CorrelationId:c8d97e9f-802f-0000-ceac-44663834d510 +``` + +## JobPostponed + +```log +JobId:845daca4-5529-4b0e-85ab-a603efee5b12 +Time:09/29/2020 19:56:57.598 +NextPickupTime:09/29/2020 20:16:57.519 +SiteId:48917234-de43-474a-9f1b-8d98ffa08425 +DbId:8fd09323-b23f-430d-8957-213586ce3861 +JobsInQueue:TotalRetryCount:0 +MigrationType:None +MigrationDirection:Import +CorrelationId:d5d97e9f-702c-0000-ceb9-354fefa5e9f6 +``` + +## JobLogFileCreate + +```log +JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecdTime:09/29/2020 19:56:29053 +FileName:Import-071f9aad-36e6-4bef-9f09-40b5c7498ecd-1.log +CorrelationId:22ca20ec-23de-468b-add3-4e52e90d3a68 +JobStart +JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecdTime:09/29/2020 19:56:29:100 +SiteId:48917234-de43-474a-9f1b-8d98ffa08425 +WebId:36b66979-4a43-4b93-9b92-909c7186ff98 +DBId:8fd09323-b23f-430d-8957-213586ce3861 +FarmId:211e600c-f48d-4319-ba92-61150c8e8e8c +ServerId:cfd27448-822a-420b-bcc8-4f39629b01bc +SubscriptionId:51812136-3cba-482d-9696-532cddceab31 +TotalRetryCount:0 +MigrationType:None +MigrationDirection:Import +CorrelationId:c308c0ea-a7f5-4be9-acd4-1ebd39867434 +``` + +## JobProgress + +```log +JobId:845daca4-5529-4b0e-85ab-a603efee5b12 +Time:09/29/2020 19:56:32.265 +FilesCreated:15 +BytesProcessed:45 +ObjectsProcessed:217 +TotalExpectedSPObjects:403 +TotalErrors:0 +TotalWarnings:0 +TotalRetryCount:0 +MigrationType:None +MigrationDirection:Import +WaitTimeOnSqlThrottlingMilliseconds:0 +TotalDurationInMs:0 +CpuDurationInMs:0 +SqlDurationInMs:0 +SqlQueryCount:0 +CreatedOrUpdatedFileStatsBySize: +{ + "0-1K": { + "Count": 15, + "TotalSize": 45, + "TotalDownloadTime": 251, + "TotalCreationTime": 6754 + } +} +ObjectsStatsByType: +{ + "SPUser": { + "Count": 1, + "TotalTime": 289, + "AccumulatedVersions": 0, + "ObjectsWithVersions": 0 + }, + "SPFolder": { + "Count": 2, + "TotalTime": 144, + "AccumulatedVersions": 0, + "ObjectsWithVersions": 0 + }, + "SPDocumentLibrary": { + "Count": 1, + "TotalTime": 173, + "AccumulatedVersions": 0, + "ObjectsWithVersions": 0 + }, + "SPFile": { + "Count": 200, + "TotalTime": 6765, + "AccumulatedVersions": 0, + "ObjectsWithVersions": 0 + }, + "SPListItem": { + "Count": 14, + "TotalTime": 2111, + "AccumulatedVersions": 0, + "ObjectsWithVersions": 0 + } +} +TotalExpectedBytes:0 +CorrelationId:ccd97e9f-a0cc-0000-ceb9-37a900bec68d +``` + +## JobEnd (Import) + +```json +{ +"Event": "JobEnd", +"JobId": "aed28dcc-efc3-46c3-89f2-b5df71ccfe85", +"Time": "04/11/2024 14:51:53.531", +"FilesCreated": "5", +"BytesProcessed": "260999", +"ObjectsProcessed": "6", +"TotalErrors": "2", +"TotalWarnings": "0", +"FilesCreatedIrrespectiveOfVersions": "1", +"BytesProcessedOnlyCurrentVersion": "111001" +} +``` + +### **FilesCreatedIrrespectiveOfVersions** property + +An integer. + +The number of files created, exclusive of file versions. If a file has multiple versions, this count increases by 1 only when all the versions are migrated. + +List items aren't counted in this property. + +### **BytesProcessedOnlyCurrentVersion** property + +An integer. The bytes are processed with the last version of the file. If a file has multiple versions, this byte count increases only when all the versions are migrated. + +List items aren't counted in this property. + +## JobEnd (AMR) + +AMR API generates `JobEnd` event with estimation of item counts in `TotalExpectedSPObjects` field: + +```log +Event:JobEnd +JobId:e915f93a-b377-476e-995c-952fd28c0a12 +Time:11/28/2023 13:41:06.109 +FilesCreated:182 +BytesProcessed:441084014 +ObjectsProcessed:425 +TotalExpectedSPObjects:425 +TotalErrors:2 +TotalWarnings:0 +TotalRetryCount:0 +MigrationType:AsyncRead +MigrationDirection:Export +``` + +## JobDeleted + +```log +JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecd +Time:09/29/2020 19:56:29.053 +CorrelationId:22ca20ec-23de-468b-add3-4e52e90d3a68 +``` + +### JobCancelled + +```log +JobId:071f9aad-36e6-4bef-9f09-40b5c7498ecd +Time:09/29/2020 19:58:29053 +TotalRetryCount:0 +CancelledByUser:false +MigrationType:None +MigrationDirection:Import +CorrelationId:22ca20ec-23de-468b-add3-4e52e90d3a68 +``` + +## JobError + +```log +JobId:b427d8d7-2b91-4da0-aee5-4b5a5a5d867e +Time: 02/05/2019 06:56:09.732 +TotalRetryCount:0 +MigrationType:None +MigrationDirection:Import +ObjectType:File +Url:Shared Documents/file.pdf +Id:fae7b4b0-2912-11e9-b0f3-7b554a52d6ab +ErrorCode:-2147024816 +ErrorType:Microsoft.SharePoint.SPException +Message:ErrorMessage +CorrelationId:d8e9bc9e-20e2-8000-aa83-48a62fc5ce75 +``` + +## JobFatalError + +```log +JobId:8f728c13-95d0-4d54-96bc-4ee912bd32ce +Time: 02/05/2019 06:57:20.523 +TotalRetryCount:0 +MigrationType:None +MigrationDirection:Import +ObjectType: +Url: +Id: +ErrorCode:-2147213196 +ErrorType:Microsoft.SharePoint.SPException +Message:ErrorMessage +CorrelationId:b370d5a0-105d-4000-241f-9b2d70449d7b +``` + +## JobWarning + +```log +JobId:b427d8d7-2b91-4da0-aee5-4b5a5a5d867e +Time: 02/05/2019 06:56:09.732 +TotalRetryCount:0 +MigrationType:None +MigrationDirection:Import +ObjectType:File +Url:Shared Documents/file.pdf +Id:fae7b4b0-2912-11e9-b0f3-7b554a52d6ab +ErrorCode:-2147024816 +ErrorType:Microsoft.SharePointSPException +Message:ErrorMessage +CorrelationId:d8e9bc9e-20e2-8000-aa83-48a62fc5ce75 +FinishManifestFileUpload +JobId:b427d8d7-2b91-4da0-aee5-4b5a5a5d867e +Time:02/05/2019 06:56:09.732 +ManifestFileName:Filename +CorrelationId:d8e9bc9e-20e2-8000-aa83-48a62fc5ce75 +``` + +## FinishManifestFileUpload + +Indicates that AMR API exported metadata. Find exported manifest files in the Azure Blob Storage Container supplied. The event also contains the location and file names of the exported files. + +### Example + +```json +{"Event", "FinishManifestFileUpload"}, +{"JobId", “f8d7d577-676e-47ce-ab69-ae7803979883”}, +{"Time", “2019-09-03T19:11:33.903”}, +{"ManifestFileName", “f8d7d577-676e-47ce-ab69-ae7803979883/ExportSettings.xml”} +``` diff --git a/docs/apis/migration-isv-guidance.md b/docs/apis/migration-isv-guidance.md index 70476b2a4..142300d3b 100644 --- a/docs/apis/migration-isv-guidance.md +++ b/docs/apis/migration-isv-guidance.md @@ -1,14 +1,14 @@ --- title: "Migration guide for ISVs" description: "Learn about using the SharePoint Migration API." -ms.date: 02/04/2021 +ms.date: 06/28/2021 ms.author: jhendr author: JoanneHendrickson manager: pamgreen audience: Dev ms.topic: article -ms.prod: sharepoint-server-itpro -localization_priority: Priority +ms.subservice: migration-tool +ms.localizationpriority: high ms.collection: - SPMigration - M365-collaboration @@ -26,7 +26,7 @@ To provide a stable platform and more reliable service, Microsoft is requesting Migration is a background task application and should **not** be run in user mode. By transitioning to app-based authentication, you will benefit from the elastic capability of off-peak time to have more resources. -> [!Note] +> [!NOTE] > Microsoft will start enforcing the proper usage roles in Q1 2020. Vendors who continue to run migration in user roles can expect to experience increasing throttling and poor performance. To learn more on how to register an app ID and how to implement app-based authentication see: diff --git a/docs/apis/migration-job-progress-api-reference.md b/docs/apis/migration-job-progress-api-reference.md new file mode 100644 index 000000000..d6f6eff66 --- /dev/null +++ b/docs/apis/migration-job-progress-api-reference.md @@ -0,0 +1,171 @@ +--- +title: "SharePoint Migration Job Progress API" +description: "This article explains how to retrieve migration job status with GetMigrationJobProgress API." +ms.date: 06/15/2025 +ms.author: jihongzuo +author: shiongzuo +manager: dapodean +audience: ISV +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- +# SharePoint GetMigrationJobProgress API + +After submitting a migration job—whether an import job or an Asynchronous Metadata Read (AMR) job—you can use the GetMigrationJobProgress API to track its progress. The API is available via both SDK and REST interfaces. + +It returns a sequence of job status events, including: JobQueued, JobStart, JobProgress, JobError, and JobEnd. + +## Permissions + +Use application-based authentication when submitting a migration job. Ensure the application is granted the Sites.Read.All permission or higher. + +## GetMigrationJobProgress Method (SDK) + +### Syntax + +```csharp +public ClientResult Site.GetMigrationJobProgress( + Guid jobId, + String nextToken +) +``` + +### Method Parameters + +| Name | Type | Required | Description | +| :--------- | :------- | :------- | :----------------------------------------------------- | +| jobId | Guid | Yes | Unique identifier of the migration job | +| nextToken | String | Yes | Token for paging position. Use "0" for initial request | + +For a completed job, requests using nextToken are idempotent—repeating the same request will consistently return the same result. + +### Return Values + +| Name | Type | Description | +| :--------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------ | +| Logs | IList | Returns a collection of job status events when new progress is available, or an empty collection if there are no updates. | +| NextToken | String | Returns an updated string value when new progress is available, or the same value as the nextToken parameter if there are no updates. | + +### Method Usage Example + +```csharp +ClientResult result = context.Site.GetMigrationJobProgress(jobId, nextToken ?? "0"); +context.ExecuteQuery(); +IList logs = result.Value.Logs; +string newNextToken = result.Value.NextToken; +``` + +## GetMigrationJobProgress REST API + +### HTTP Request + +```http +GET https://{site_url}/_api/site/GetMigrationJobProgress(jobId='{jobId}',nextToken=0) +``` + +### URI Parameters + +| Name | Type | Required | Description | +| :--------- | :------- | :------- | :----------------------------------------------------- | +| jobId | Guid | Yes | Unique identifier of the migration job | +| nextToken | String | Yes | Token for paging position. Use "0" for initial request | + +### Request Headers + +| Header | Required | +| :------------------------------------- | :------- | +| Authorization: Bearer {token} | Yes | +| Accept: application/json;odata=verbose | Yes | + +### Response + +A JSON object when the HTTP status code is 200. + +An empty JSON object when the HTTP status code is other than 200. + +### Error Handling + +| Status Code | Meaning | Action | +| :---------- | :------------- | :---------------------------------------------------------------------- | +| 403 | Unauthorized | Ensure the app/user has at least Sites.Read.All permissions. | +| 429 | Too Many Requests | Parse Retry-After header and retry after the specified delay. | +| 500 | Internal Server Error | Parse error responses to identify internal errors. Do Not Retry. | +| 503 | Service Unavailable | Parse Retry-After header and retry after the specified delay. | + +| Internal Error Code | Meaning | +| :------------------ | :---------------------------------------------- | +| -2147213145 | Job not found | +| -2147213146 | Job status expired (valid for less than 5 days) | + +### API Usage Example + +#### Request Sample + +```http +GET https://contoso.sharepoint.com/_api/site/GetMigrationJobProgress(jobId=' 3e280efa-78a3-4ba1-bac6-e447aa538ca5', nextToken=0) +``` + +#### Successful Response Sample + +Status code: 200 +Response body: + +```json +{ + "d": { + "GetMigrationJobProgress": { + "Logs": { + "__metadata": { + "type": "Collection(Edm.String)" + }, + "results": [ + "{\"MigrationType\":\"None\",\"MigrationDirection\":\"Import\",\"SiteId\":\"48f1898f-77d9-4a1b-bddc-1f49bb6dc134\",\"DbId\":\"de6b85cd-726e-4b13-ae04-629798fddbf3\",\"TotalRetryCount\":\"0\",\"JobId\":\"3e280efa-78a3-4ba1-bac6-e447aa538ca5\",\"Time\":\"05/20/2025 09:18:48.132\",\"CorrelationId\":\"91884a0c-5ee8-4e1f-a23f-e4f7ec170182\",\"Event\":\"JobQueued\"}", + "{\"MigrationType\":\"None\",\"MigrationDirection\":\"Import\",\"SiteId\":\"48f1898f-77d9-4a1b-bddc-1f49bb6dc134\",\"WebId\":\"7206fc09-e4af-48b3-8730-ed7321396d7a\",\"DbId\":\"de6b85cd-726e-4b13-ae04-629798fddbf3\",\"FarmId\":\"f77d7b6c-ef43-4609-8fce-0e93142ce8a0\",\"ServerId\":\"44af885c-393b-4236-9417-bae7a9edc44e\",\"SubscriptionId\":\"82abb045-250e-4186-ba83-b9295930f272\",\"TotalRetryCount\":\"0\",\"JobId\":\"3e280efa-78a3-4ba1-bac6-e447aa538ca5\",\"Time\":\"05/20/2025 09:20:51.129\",\"CorrelationId\":\"7d3e7a8e-4445-4ce0-adb1-078e78cbf686\",\"Event\":\"JobStart\"}", + "{\"MigrationType\":\"None\",\"MigrationDirection\":\"Import\",\"TotalRetryCount\":\"0\",\"ObjectType\":\"ListItem\",\"Url\":\"\",\"Id\":\"cb471d5f-593f-4a63-b59e-8eae3e35b08a\",\"SourceListItemIntId\":\"3\",\"TargetListItemIntId\":\"3\",\"ErrorCode\":\"-2147286782\",\"ErrorType\":\"Microsoft.SharePoint.SPException\",\"Message\":\"Attempted to use an object that has ceased to exist. (Exception from HRESULT: 0x80030102 (STG_E_REVERTED)) \",\"JobId\":\"3e280efa-78a3-4ba1-bac6-e447aa538ca5\",\"Time\":\"05/20/2025 09:20:55.490\",\"CorrelationId\":\"7d3e7a8e-4445-4ce0-adb1-078e78cbf686\",\"Event\":\"JobError\"}", + "{\"MigrationType\":\"None\",\"MigrationDirection\":\"Import\",\"TotalRetryCount\":\"0\",\"FilesCreated\":\"0\",\"BytesProcessed\":\"0\",\"ObjectsProcessed\":\"4\",\"TotalExpectedSPObjects\":\"15\",\"TotalErrors\":\"3\",\"TotalWarnings\":\"0\",\"WaitTimeOnSqlThrottlingMilliseconds\":\"0\",\"TotalDurationInMs\":\"0\",\"CpuDurationInMs\":\"0\",\"SqlDurationInMs\":\"0\",\"SqlQueryCount\":\"0\",\"IsShallowCopy\":\"False\",\"CreatedOrUpdatedFileStatsBySize\":\"{}\",\"ObjectsStatsByType\":\"{\\\"SPUser\\\":{\\\"Count\\\":1,\\\"TotalTime\\\":124,\\\"AccumulatedVersions\\\":0,\\\"ObjectsWithVersions\\\":0},\\\"SPFolder\\\":{\\\"Count\\\":1,\\\"TotalTime\\\":153,\\\"AccumulatedVersions\\\":0,\\\"ObjectsWithVersions\\\":0},\\\"SPDocumentLibrary\\\":{\\\"Count\\\":1,\\\"TotalTime\\\":404,\\\"AccumulatedVersions\\\":0,\\\"ObjectsWithVersions\\\":0},\\\"SPFile\\\":{\\\"Count\\\":1,\\\"TotalTime\\\":0,\\\"AccumulatedVersions\\\":0,\\\"ObjectsWithVersions\\\":0},\\\"SPListItem\\\":{\\\"Count\\\":1,\\\"TotalTime\\\":1880,\\\"AccumulatedVersions\\\":0,\\\"ObjectsWithVersions\\\":0}}\",\"TotalExpectedBytes\":\"0\",\"FilesCreatedIrrespectiveOfVersions\":\"0\",\"BytesProcessedOnlyCurrentVersion\":\"0\",\"JobId\":\"3e280efa-78a3-4ba1-bac6-e447aa538ca5\",\"Time\":\"05/20/2025 09:20:57.380\",\"CorrelationId\":\"7d3e7a8e-4445-4ce0-adb1-078e78cbf686\",\"Event\":\"JobEnd\"}" + ] + }, + "NextToken": "1764", + "__metadata": { + "type": "SP.MigrationJobProgress" + } + } + } +} +``` + +#### Error Response Sample + +Status code: 500 +Response body: + +```json +{ + "error": { + "code": "-2147213145, Microsoft.SharePoint.SPException", + "innererror": { + "message": "Job not found", + "stacktrace": "STACK_TRACE" + }, + "message": { + "lang": "en-US", + "value": "Job not found" + } + } +} +``` + +## Best Practice + +Begin with `nextToken=0`, store the returned token, and poll at certain intervals. This method is well-suited for long-running jobs and helps ensure no updates are missed. + +Since migration jobs typically take several minutes or more, polling every minute is advised, while adhering to the [guideline](https://aka.ms/spo429) to avoid throttling. + +## See Also + +- [SharePoint Migration API](migration-api-overview.md) +- [Migration Events](migration-events.md) diff --git a/docs/apis/migration-manifest.md b/docs/apis/migration-manifest.md new file mode 100644 index 000000000..770fd670b --- /dev/null +++ b/docs/apis/migration-manifest.md @@ -0,0 +1,405 @@ +--- +title: "Preparing the manifest for Migration API" +description: "This article provides in-depth information on how to use create and use manifest packages with SharePoint Migration API" +ms.date: 04/18/2024 +ms.author: ranren +author: underreview +manager: dapodean +audience: ITPro +ms.subservice: migration-tool +ms.topic: article +ms.localizationpriority: high +ms.collection: + - SPMigration + - m365-collaboration +--- + +# XML manifest files + +Migration API relies on XML manifest files to process the content import correctly. Create manifest files in a well-defined format. AMR API also exports metadata in this format. + +## XML Validation + +The package structure for Manifest files is based on a constrained version of [SharePoint Content Migration Schemas](/sharepoint/dev/schema/content-migration-schemas). + +## Encoding invalid XML characters + +AMR API encodes invalid XML characters in fields. Decode the attributes listed in `EncodedAttributes`. + +Migration API doesn't support invalid XML character encoding. + +### Example + +In this example, these attributes are encoded: URL, ParentWebURL, Name, and Version. + +```xml + +``` + +## Location + +Placed all manifest files at the root level of the Azure Blob Storage Container for manifest files. + +## ArchivedFiles.xml + +Optional. + +Used to process archived small files in batch. + +### ArchivedFiles.xml Example + +```xml + + + + + + + + + + + + + + + + + + + +``` + +## ExportSettings.xml + +Required. + +An XML file contains the export settings specified with the `SPExportSettings` and other classes. It also specifies the export settings, used in the subsequent import process at the migration target site. It also maintains a catalog of all objects exported to the migration package. + +### Ignore Web Parts + +Migration API checks and processes SharePoint Web Parts in certain types of files. For sources other than SharePoint Server and SharePoint Online, bypass these checks by setting `IgnoreWebParts` to `true`. This practice improves the performance of migration tasks when not migrating Web Parts. + +### Specify content source + +Migration API requires a `SourceType` value, containing the source of the content. It should contain a value from the following list: + +#### Accepted `SourceType` values + +- `AmazonS3` +- `AzureStorage` +- `Box` +- `Dropbox` +- `Egnyte` +- `FileShare` +- `GoogleCloudStorage` +- `GoogleDrive` +- `MicrosoftStream` +- `OneDrive` +- `SharePointOnline` +- `SharePointOnPremServer` +- `Other` + +When declaring to `Other`, include an extra `DetailedSource` value to provide more detail on the content source information. + +### ExportSettings.xml Example + +```xml + + + + + +``` + +## LookupListMap.xml + +Optional. + +An XML manifest file that maintains a simple lookup list, which records all SharePoint List Item references. Place it at the root of the Azure Blob Store Container defined by the `CreateMigrationJob`’s `azureContainerManifestUri` parameter. + +Not required if the import package doesn't contain Defining Fields or Views on a List or Document Library. The omission of this file generates a warning message in the log. Include a file with a childless `root` node to avoid this warning message. + +## Manifest.xml + +Required. + +An XML manifest file that contains the complete list of both the contents and the structure of the content package. Migration API uses this manifest file to reconstitute the source and its components. + +Place all instances of the **Manifest.xml** file for a package at the root of the Azure Blob Store Container. + +This manifest file is also the primary descriptor for metadata within the package, and provides the List, Folder, and Item hierarchy, along with metadata for the items including references back to users and groups defined in **UserGroupMap.xml** file. + +Use more than one **Manifest.xml** if needed. The manifests are identified with different file names. Migration API locates all manifests through references in **SystemData.xml** file’s `ManifestFile` entries. + +### Document Library/List ID consistency + +Use consistent Web ID and Document Library ID/List ID at the source and the target location. Inconsistent Web IDs generate errors as Migration API can't find the parent web for the import operation. + +Likewise, Migration API can't import items with incorrect Document Library IDs and List IDs into the target Document Library or List. Don't reuse IDs within the same site collection, to avoid Migration API importing packages to the same target site collection, regardless of the destination web. + +### GUID consistency + +To avoid GUID conflicts and import errors, use the same package for the same target. Importing a new package with the same content will cause problems. The package from a file share assigns GUIDs to files, folders, and list items. Keep the package from the file share as a record of the original GUIDs. Use the same GUIDs for later packages to avoid conflicts and track changes. + +### Preserve content identifiers + +The identifiers in the Import Packages are **explicitly** used during import to identify content. This practice preserves existing identifiers for Document Library contents. + +Reference the target Web and List identifiers **explicitly**. + +Migration API preserves content type identifiers, file/folder item GUIDs, and List Item integer identifiers during import. Import fails when Migration API encounters incorrect identifiers in the package. + +This preservation enables successive import iterations with different packages, allowing items to move locations. + +### Permission Roles + +Manifest.xml contains the following Roles-related objects: + +#### Roles object + +Contains the list of all defined Roles on the Web. + +#### Role object + +Defines a Role with ID, internal permissions rights mask flags, and display information. + +##### RoleId value + +Defines the identifiers of the Role object. + +##### PermMask value + +Contains the rights mask flags. + +#### RoleAssignments object + +Contains the list of all unique permissions (RoleAssignment objects). + +#### RoleAssignment object + +Includes the list of distinct Assignment objects (if any). + +##### Assignment object + +Contains the actual membership of one distinct User or Group and their actual Role, where + +- RoleId values map to the RoleId values of the Role objects. +- PrincipalId values map to ID values of User or Group objects respectively in **UserGroups.xml**. + +#### Permissions Example + +```xml + + … + + + + + + + + + + + + + + … + + + … + +``` + +## Requirements.xml + +Optional. + +SharePoint Server usually generates this XML manifest file. It contains a list of deployment requirements in the form of installation requirements on the migration target, such as + +- feature definitions +- template versions +- Web Part assemblies +- language packs +- and so forth. + +Include no child node under the root for file shares. The omission of this file generates a warning message in the log. + +## RootObjectMap.xml + +Optional. + +Maintains a list of mappings of secondary (dependent) objects. Migration API uses this manifest file to correctly place dependent objects. + +The most common `RootObject` included is a single object of type List. The `ID` of this item should be the List `ID` of the target list, and the `ParentWebID` should match the `ID` of the parent target web containing this list in order for migration to be successful. The `ID`, `WebUrl`, and `Url` values of this object must also match the related structure laid out in the **Manifest.xml** file. + +## SystemData.xml + +Required. + +Contains various low-level system data. It also records the number and paths of **Manifest.xml** files in the manifest package, when there are multiple manifests. + +### Versions + +`SchemaVersion` references to the current `Build` and `DatabaseVersion` of the target farm, currently “15.0.0.0”. + +`SiteVersion` should match the target site collection `UIVersion`, currently `15`. + +### Multiple Manifests + +List all **Manifest.xml** files in the package in **SystemData.xml**, as `ManifestFile` entries. + +### Immutable SystemObjects + +List all `SystemObjects` defining dependent objects that remain immutable by Migration API. + +### SystemData.xml example + +This example **SystemData.xml** file shows the common objects from a file share import. Use different `ID`s for each package, and the `URL`s may be different. + +```xml + + + + + + + + + + + + + + +``` + +## UserGroupMap.xml + +Required. + +Records Users and User Security Groups for managing permissions. Migration API uses the manifest to ascertain the membership of Users and Groups, along with their roles and specific assignments. These assignments include unique permissions set at the level of the object and its offspring, unless a deeper child object overrides them. + +User or Group entries aren't mandatory, but omission prevents author or security information from the population during import. Migration API generates warnings in such cases. + +### User identifiers + +Identify a User only once in a single package. + +Manifest all Users and Groups within the exported Web(s). + +#### User object + +Includes the information about specific Users, including identification of a specific security principle as a domain group or not, sign-in, and the base64 encoded SystemId (SID) of the security principle. + +#### Group object + +Includes the information about specific Groups and the direct membership list of that Group. + +Owner values on Group objects and UserId values on member objects within group objects map to other ID values of other User or Group objects respectively. + +The following example shows how to manifest Users and Groups. + +```xml + + + + + … + + + + + + + + + + … + + +``` + +Make sure the Sign-in and SystemId values of users match the values in SharePoint. + +### Deleted Users + +Include an `IsDeleted` value as `true` for deleted accounts. This practice prevents lookup failures in the import process, which negatively impacts performance. + +### Unresolved User identifiers + +If Migration API is unable to resolve a User with the Sign-in information, and SystemId **is not** provided, Migration API replaces this User with `System Account` in the associated metadata (such as Author or Editor) in the package and generates a warning in the import logs: + +```text +Failed to ensure user 'user@contoso.com' +``` + +If Migration API is unable to resolve a User with the Sign-in while the SystemId **is** provided, Migration API creates a new deleted User with the provided Sign-in and SystemId. Migration API uses this User with associated metadata within the package. Migration API generates a warning in the import logs: + +```text +Failed to retrieve user 'user@contoso.com' attributes from the SiteUsers; falling back to passed in values +``` + +### Avoid non-UPN email addresses in User identifiers + +The `Login` attribute of the User identifier requires a UPN. **Do not use** non-UPN email addresses. Using non-UPN email addresses causes unexpected behavior in SharePoint Online. + +### Examples + +The following examples show the correct and incorrect ways of using the User identifiers. + +In this case, the user has the following identifiers: + +- UPN: +- Email: . + +#### Correct example + +This example manifests the User only once, with a UPN email address. + +```xml + +``` + +#### Incorrect example + +This example **incorrectly** uses a non-UPN email address and **incorrectly** includes more than one identifier for a single user. + +```xml + + +``` + +This example **incorrectly** uses a non-UPN email address. + +```xml + +``` + +## ViewFormsList.xml + +Optional. + +This XML manifest file maintains a list of Web Parts and tracks whether each is a view or form. + +This file is optional if the Import Package doesn't contain Web Parts. The omission of this file generates a warning message in the log. Alternatively, include a manifest file with a childless `root` node to avoid the warning message. diff --git a/docs/apis/migration-perm-guidance.md b/docs/apis/migration-perm-guidance.md index 2d608dd83..f46fb025c 100644 --- a/docs/apis/migration-perm-guidance.md +++ b/docs/apis/migration-perm-guidance.md @@ -1,7 +1,8 @@ --- title: Migration permission guidance -ms.prod: sharepoint -ms.date: 02/01/2021 +description: "Migration permission guidance" +ms.date: 03/30/2023 +ms.subservice: migration-tool ms.author: jhendr author: JoanneHendrickson manager: serdars @@ -9,12 +10,11 @@ audience: ITPro f1.keywords: - NOCSH ms.topic: conceptual -localization_priority: Priority +ms.localizationpriority: high ms.collection: - SPMigration - M365-collaboration search.appverid: MET150 -description: "Migration permission guidance" --- # Migration permission guidance @@ -22,9 +22,9 @@ You need to be aware of three key numbers as you plan your migration to OneDrive ## Permissions: Inherited and unique -Inherited permissions are set as the default at the root site collection level and are applied to the other locations and objects within that site collection. Unique permissions are all other permissions that differ (or “break”) from what is set at the root. In SharePoint, you can set unique permissions all the way down to the item level. +Inherited permissions are set as the default at the root site collection level and are applied to the other locations and objects within that site collection. Unique permissions are all other permissions that differ (or "break") from what is set at the root. In SharePoint, you can set unique permissions all the way down to the item level. -Each time you break inheritance by granting access to a new user account or group at any level in a site, even on a single item, you are creating a new unique security “scope” ID. That scope is counted as a unique permission towards the total limit. A library (or list) cannot have greater than 50,000 unique security scopes. +Each time you break inheritance by granting access to a new user account or group at any level in a site, even on a single item, you create a new unique security "scope" ID. That scope is counted as a unique permission towards the total limit. A library (or list) can't have greater than 50,000 unique security scopes. ![Site hierarchy](../images/hierarchy-perms.png) @@ -33,22 +33,23 @@ When migrating, we recommend that you have less than 5,000 unique scopes per lib ## Role assignments -A role assignment is a mapping between a user, a SharePoint object (Web, list, file) and a role (Design, Full Control, Contribute, etc.). The role assignment ties together the role definition (permission level) with the specific user or group, and the scope that that permission level will be applied to (such as list, folder, item). +A role assignment is a mapping between a user, a SharePoint object (web, list, file) and a role (for example, Design, Full Control, or Contribute). The role assignment ties together the role definition (permission level) with the specific user or group, and the scope that that permission level will be applied to (such as list, folder, item). -There is a role assignment limit of 5,000 per security scope. +The maximum number of role assignments allowed per security scope is 5,000. ## Item limits -When a library (or list) contains more than 100,000 items (files and folders or list items), you cannot break permissions inheritance on the list itself. There is a limit of 100,000 items that can be updated or removed as a part of creating a new SharePoint security scope. +When a library (or list) contains more than 100,000 items (files and folders or list items), you can't break permissions inheritance on the list itself. There's a limit of 100,000 items that can be updated or removed as a part of creating a new SharePoint security scope. + +If you're migrating a structure that has more than 100,000 children (such as files, folders, lists, or other object types), you need to restructure the migration by importing security in multiple phases to avoid exceeding this limit. Any VROOM invite, REST share link, or any other permission-modifying function call will trigger an HTTP 429 throttle if the threshold is reached. Permissions won't be updated. Unlike other throttles, waiting and trying again won't resolve the situation as you've reached a hard limit of 100,000. -If you are migrating a structure that has more than 100,000 children (such as files, folders, lists, or other object types), you need to restructure the migration by importing security in multiple phases to avoid exceeding this limit. Any VROOM invite, REST share link, or any other permission-modifying function call will trigger an HTTP 429 throttle if the threshold is reached. Permissions will not be updated. Unlike other throttles, waiting and trying again will not resolve the situation as you have reached a hard limit of 100,000. To learn more about the service limits in SharePoint for Microsoft 365, see [SharePoint Limits](/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits#items-in-lists-and-libraries). -## Folders containing fewer than 100,000 items +## Folders with less than 100,000 items -If your library (or list) has fewer than 100,000 items, and you have less than 50,000 unique scopes, you can migrate using the migration API and apply unique scopes to create folders with less 100K items to break inheritance as needed. +If your library (or list) has fewer than 100,000 items, and you have less than 50,000 unique scopes, you can migrate using the Migration API and apply unique scopes to create folders with fewer 100-K items to break inheritance as needed. -## Folders containing more than 100,000 items +## Folders with more than 100,000 items If you have a folder with more than 100,000 items, we recommend one of the following approaches. Determine how many items are in your source or root folder, including lists or other object types. Scan and determine which folder structures have greater than 100,000 items. @@ -56,30 +57,30 @@ If you have a folder with more than 100,000 items, we recommend one of the follo The first option is to restructure your *source* layout. -For example, divide a single folder of 250,000 items into four folders at the root so each folder has less than 100,000 items. There is still “room to grow”, presuming users will continue to add content and make changes here. +For example, divide a single folder of 250,000 items into four folders at the root so each folder has less than 100,000 items. There's still "room to grow", presuming users will continue to add content and make changes here. Make sure that there are no more than 50,000 unique scopes in the structure: ideally less than 5,000. -In this example, at the source, break up the structure into four folders, A, B, C, and D, each having less than 100,000 items. Then perform the migration. See the illustration below. +In this example, at the source, break up the structure into four folders, A, B, C, and D, each having less than 100,000 items. Then perform the migration. For details, see the following illustration. ![Hierarchy ABCD](../images/hierarchy-ABCD.png) ->[!NOTE] ->There are other limits that must be considered during migration. See [SharePoint Limits](/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits#items-in-lists-and-libraries) for details. +> [!NOTE] +> There are other limits that must be considered during migration. For details, see [SharePoint Limits](/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits#items-in-lists-and-libraries). ### Method 2: Create your destination layout to avoid exceeding limits The alternate approach is to keep your source layout, applying unique scopes at the destination before migration. **Example:** Your source folder has 250,000 items within it. At your target location, create folders A, B, C, and D and apply the unique scopes and scope ID. This will break inheritance. Then proceed with your content migration. -If you do not want your end users to share items until migration is completed, use the Migration API to migrate the content & scopes, but set the scope to NULL to prevent any use. +If you don't want your end users to share items until migration is completed, use the Migration API to migrate the content and scopes, but set the scope to NULL to prevent any use. After all the content and incremental migrations are completed, apply the proper scope. After the incremental migration has completed, and only if you previously set the scope to NULL, you can reapply the unique scope for folders A, B, C, D separately. When you reapply the scope, evaluate your folder size starting at the lowest level of hierarchy. -## Other Sharing/Permission related considerations +## Other sharing/permission-related considerations -The REST share link or any other permission-modifying function will not take effect if you attempt to update the permission on a file that is checked out by a user. +The REST share link or any other permission-modifying function won't take effect if you attempt to update the permission on a file that is checked out by a user. Finally, if a SharePoint site or OneDrive location is being actively used during migration, the existing permissions applied on that site, user or document will be enforced. -**Example:** If you attempt to modify the permission on a site that only allows access to existing users already defined on the site, and the user you are trying to add to a file or folder does not already have permissions on the site itself, the permission call (e.g. VROOM Invite) will not be able to make the modification. +**Example:** If you attempt to modify the permission on a site that only allows access to existing users already defined on the site, and the user you're trying to add to a file or folder doesn't already have permissions on the site itself, the permission call (for example, VROOM Invite) won't be able to make the modification. diff --git a/docs/apis/onenote-migration-service.md b/docs/apis/onenote-migration-service.md index e063540f3..5b8f9b616 100644 --- a/docs/apis/onenote-migration-service.md +++ b/docs/apis/onenote-migration-service.md @@ -1,18 +1,18 @@ --- title: Migrating OneNote folders -ms.date: 12/05/2020 +description: "Migrating OneNote folders using the SPO OneNote converting service" +ms.date: 06/28/2022 ms.author: jhendr author: JoanneHendrickson manager: pamgreen audience: Dev ms.topic: article -ms.service: sharepoint-online -localization_priority: Priority +ms.subservice: migration-tool +ms.localizationpriority: high ms.collection: - SPMigration - M365-collaboration search.appverid: MET150 -description: "Migrating OneNote folders using the SPO OneNote converting service" --- # Migrating OneNote folders diff --git a/docs/apis/sharepoint-rest-graph.md b/docs/apis/sharepoint-rest-graph.md index 14741a7c6..ac203275b 100644 --- a/docs/apis/sharepoint-rest-graph.md +++ b/docs/apis/sharepoint-rest-graph.md @@ -2,8 +2,7 @@ title: Operations using SharePoint REST v2 (Microsoft Graph) endpoints description: Perform basic create, read, update, and delete (CRUD) operations with the SharePoint v2 REST interface. ms.date: 12/05/2020 -ms.service: sharepoint-online -localization_priority: Priority +ms.localizationpriority: high --- # SharePoint REST operations via the Microsoft Graph REST API diff --git a/docs/apis/site-creation-rest.md b/docs/apis/site-creation-rest.md index 1e1011b6a..530ad6137 100644 --- a/docs/apis/site-creation-rest.md +++ b/docs/apis/site-creation-rest.md @@ -1,9 +1,8 @@ --- title: Create Modern SharePoint Sites using REST description: Create and get the status of a new modern SharePoint site by using the REST interface. -ms.date: 03/30/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 12/07/2022 +ms.localizationpriority: high --- # Manage modern SharePoint sites using REST @@ -45,6 +44,7 @@ body: "Lcid": 1033, "ShareByEmailEnabled":false, "Classification":"Low Business Impact", + "SensitivityLabel": "", "Description":"Description", "WebTemplate":"SITEPAGEPUBLISHING#0", "SiteDesignId":"6142d2a0-63a5-4ba0-aede-d9fefca2c767", @@ -57,15 +57,17 @@ body: > [!IMPORTANT] > If you use an app-only context to create the site collection the **Owner property is required**. In other cases this is an optional property and if not present will default to the user calling the REST endpoint. +> [!NOTE] +> The "Classification" parameter only sets the value visible on the site, but doesn't apply the label on the site. Use the new parameter "SensitivityLabel" to actually apply the label on your site collection. -The site design id can be retrieved by using the [Get-SPOSiteDesign](/powershell/module/sharepoint-online/get-spositedesign) (Microsoft SharePoint Online Management Shell) or [Get-PnPSiteDesign](/powershell/module/sharepoint-pnp/get-pnpsitedesign) (PnP PowerShell) cmdlets. If you want to apply an out-of-the-box available site design, use the following values: +The site design id can be retrieved by using the [Get-SPOSiteDesign](/powershell/module/sharepoint-online/get-spositedesign) (Microsoft SharePoint Online Management Shell) or [Get-PnPSiteDesign](/sharepoint/dev/declarative-customization/site-design-pnppowershell) (PnP PowerShell) cmdlets. If you want to apply an out-of-the-box available site design, use the following values: -- Topic: `96c933ac-3698-44c7-9f4a-5fd17d71af9e` or null +- Standard communication: `96c933ac-3698-44c7-9f4a-5fd17d71af9e` or null - Showcase: `6142d2a0-63a5-4ba0-aede-d9fefca2c767` - Blank: `f6cc5403-0d63-442e-96c0-285923709ffc` > [!IMPORTANT] -> To apply your custom site designs as retrieved with [Get-SPOSiteDesign](/powershell/module/sharepoint-online/get-spositedesign) (Microsoft SharePoint Online Management Shell) or [Get-PnPSiteDesign](/powershell/module/sharepoint-pnp/get-pnpsitedesign) (PnP PowerShell) you will have to change the JSON as follows: +> To apply your custom site designs as retrieved with [Get-SPOSiteDesign](/powershell/module/sharepoint-online/get-spositedesign) (Microsoft SharePoint Online Management Shell) or [Get-PnPSiteDesign](/sharepoint/dev/declarative-customization/site-design-pnppowershell) (PnP PowerShell) you will have to change the JSON as follows: ```json ... "SiteDesignId":"00000000-0000-0000-0000-000000000000", @@ -98,7 +100,7 @@ accept: application/json;odata.metadata=none odata-version: 4.0 body: { - "SiteId":"d11e59ca-1465-424c-be90-c847ba849af5" + "siteId":"d11e59ca-1465-424c-be90-c847ba849af5" } ``` ### Response @@ -148,6 +150,7 @@ The full set of values for `SiteStatus` are as follows: + `1` - Provisioning. The site is currently being provisioned. + `2` - Ready. The site has been created. + `3` - Error. An error occurred while provisioning the site. ++ `4` - Site with requested URL already exist. ## See also diff --git a/docs/apis/sp-migration-api-and-sensitivity-labels.md b/docs/apis/sp-migration-api-and-sensitivity-labels.md index a045ce794..c14fa0f53 100644 --- a/docs/apis/sp-migration-api-and-sensitivity-labels.md +++ b/docs/apis/sp-migration-api-and-sensitivity-labels.md @@ -1,33 +1,37 @@ --- title: "Sensitivity labels and the SharePoint Migration API" description: Learn how to have sensitivity labels applied to content before migration with the SharePoint Migration API. -ms.date: 02/01/2021 +ms.date: 06/28/2022 ms.author: jhendr author: JoanneHendrickson manager: serdars search.appverid: MET150 -localization_priority: Priority -ms.prod: sharepoint +ms.localizationpriority: high +ms.subservice: migration-tool --- # Sensitivity Labels and the SharePoint Migration API -Sensitivity labels cannot be applied to files and folders using the SharePoint Migration API. If you want to have sensitivity labels applied to your content being migrated to Microsoft 365, we recommend using the Microsoft Information Protection (MIP) SDK. There currently isn't a parameter in the API to apply sensitivity labels to files. +Sensitivity labels cannot be applied to files and folders using the SharePoint Migration API. If you want to have sensitivity labels applied to your content being migrated to Microsoft 365, we recommend using the Microsoft Information Protection SDK. There currently isn't a parameter in the API to apply sensitivity labels to files. **Step 1:** -Before you migrate your content with the Migration API, become familiar with how sensitivity labels work in Microsoft 365 and learn about the Microsoft Information Protection (MIP) SDK: +Before you migrate your content with the Migration API, become familiar with how sensitivity labels work in Microsoft 365 and learn about the Microsoft Information Protection SDK: - [Enable sensitivity labels for Offices files in SharePoint and OneDrive](/microsoft-365/compliance/sensitivity-labels-sharepoint-onedrive-files) - [Microsoft Information Protection SDK](/information-protection/develop/overview) **Step 2:** -Download and configure the Microsoft Information Protection (MIP) SDK. The article listed here shows you how to set up and configure your Microsoft 365 subscription and client workstation, in preparation for using the SDK. + +Download and configure the Microsoft Information Protection SDK. The article listed here shows you how to set up and configure your Microsoft 365 subscription and client workstation, in preparation for using the SDK. - [Microsoft Information Projection (MIP) SDK setup and configuration](/information-protection/develop/setup-configure-mip) **Step 3:** + Apply sensitivity labels using the MIP SDK. -If you're currently using Azure Information Protection, you must migrate your labels to Office 365 Security and Compliance Center. For more information on the process, see [How to migrate Azure Information Protection labels to the Office 365 Security & Compliance Center](/azure/information-protection/configure-policy-migrate-labels). +If you're currently using Azure Information Protection, you must migrate your labels to the Microsoft Purview compliance portal. For more information on the process, see [How to migrate Azure Information Protection labels to unified sensitivity labels](/azure/information-protection/configure-policy-migrate-labels). + +**Step 4:** -**Step 4:** Migrate content using the [SharePoint Import Migration API (CreationMigrationJob)](migration-api-overview.md) +Migrate content using the [SharePoint Import Migration API (CreationMigrationJob)](migration-api-overview.md) diff --git a/docs/apis/spod-copy-move-api.md b/docs/apis/spod-copy-move-api.md index 3482f27b5..202977581 100644 --- a/docs/apis/spod-copy-move-api.md +++ b/docs/apis/spod-copy-move-api.md @@ -1,32 +1,32 @@ --- title: Microsoft 365 Copy and Move API (CreateCopyJobs) -ms.date: 12/05/2020 +description: "Microsoft 365 Copy and Move API (CreateCopyJobs)" +ms.date: 10/05/2023 ms.author: jhendr author: JoanneHendrickson -manager: pamgreen +manager: serdars audience: ITPro f1.keywords: - NOCSH ms.topic: article -ms.service: sharepoint-online -localization_priority: Priority +ms.subservice: migration-tool +ms.localizationpriority: high ms.collection: - SPMigration - M365-collaboration search.appverid: MET150 -description: "Microsoft 365 Copy and Move API (CreateCopyJobs)" --- # Microsoft 365 Copy and Move API (CreateCopyJobs) ->[!IMPORTANT] ->SharePoint & OneDrive Copy and Move API replaces the CreateCopyJob API. The CreateCopyJob API has been deprecated. +> [!IMPORTANT] +> SharePoint & OneDrive Copy and Move API replaces the CreateCopyJob API. The CreateCopyJob API has been deprecated. The following API is based on the use of the SharePoint Client Side Object Model (CSOM). We recommend using [NuGet](https://www.nuget.org/) packages when you reference CSOM in your solution. You can find the latest version of the SharePoint Online CSOM package from the [NuGet library](https://www.nuget.org/) using the ID *Microsoft.SharePointOnline.CSOM*. ->[!IMPORTANT] ->Learn more about [limitations](#limitations) of this API before you begin. +> [!IMPORTANT] +> Learn more about [limitations](#limitations) of this API before you begin. ## Method @@ -53,8 +53,8 @@ public List CreateCopyJobs(Uri[] exportObjectUris, Uri dest public bool IsMoveMode { get; set; } ``` ->[!IMPORTANT] ->By default, this is set to copy. For a move operation, set this parameter to true. +> [!IMPORTANT] +> By default, this is set to copy. For a move operation, set this parameter to true. ```csharp public bool IgnoreVersionHistory { get; set; } @@ -110,8 +110,8 @@ public bool MoveButKeepSource { get; set; } Once set, this move operation is similar to copy. The file will move to destination, but the source content will not be deleted. If set, this will make a copy with the version history and preserve the original metadata. No source item deletions occurs at the end. ->[!NOTE] ->This is not like the normal copy, which only copies the most recent major version and doesn't maintain all the metadata. +> [!NOTE] +> This is not like the normal copy, which only copies the most recent major version and doesn't maintain all the metadata. ```csharp public bool ExcludeChildren { get; set; } @@ -121,12 +121,12 @@ For this operation, only the root level folder of the URL is copied. The sub-fol ### Output -|Output parameter|Description| -|:-----|:-----| -|JobID/GUID|Return a unique Job ID associated with this asynchronous read| -|SourceListItemUniqueIds|Return the source | -|JobQueueUri|URL for accessing Azure queue used for returning notification of copy and move process| -|EncryptionKey| AES256CBC encryption key used to decrypt messages from job/manifest queue| +| Output parameter | Description | +| :---------------------- | :------------------------------------------------------------------------------------- | +| JobID/GUID | Return a unique Job ID associated with this asynchronous read | +| SourceListItemUniqueIds | Return the source | +| JobQueueUri | URL for accessing Azure queue used for returning notification of copy and move process | +| EncryptionKey | AES256CBC encryption key used to decrypt messages from job/manifest queue | ```csharp public Uri JobQueueUri { get; set; } @@ -138,8 +138,8 @@ The reporting features are the same as they are for CreateMigrationJob. Logging Currently, the following limitations are: -|What|Limitation| -|:-----|:-----| -|File size| A file must be less than 2 GB.| -|Number of items| No more than 30,000 items in a job.| -|Total size of job| Job size not to exceed 100 GB.| +| What | Limitation | +| :---------------- | :---------------------------------- | +| File size | [SharePoint Limits](/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits#moving-and-copying-across-sites) | +| Number of items | [SharePoint Limits](/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits#moving-and-copying-across-sites) | +| Total size of job | [SharePoint Limits](/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits#moving-and-copying-across-sites) | diff --git a/docs/apis/syntex/rest-applymodel-method.md b/docs/apis/syntex/rest-applymodel-method.md new file mode 100644 index 000000000..d366409ba --- /dev/null +++ b/docs/apis/syntex/rest-applymodel-method.md @@ -0,0 +1,140 @@ +--- +title: Batch apply model +description: Use REST API to apply a document understanding model to one or more libraries. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- +# Batch Apply model + +Applies (or syncs) a trained document understanding model to one or more libraries (see [example](rest-applymodel-method.md#examples)). + +## HTTP request + +```HTTP +POST /_api/machinelearning/publications HTTP/1.1 +``` + +## URI parameters + +None + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| +|Content-Type|application/json;odata=verbose;charset=utf-8| +|x-requestdigest|The appropriate digest for current site.| + +## Request body + +| Name | Required | Type | Description | +|--------|-------|--------|------------| +|__metadata|yes|string|Set the object meta on the SPO. Always use the value: {"type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningPublicationsEntityData"}.| +|Publications|yes|MachineLearningPublicationEntityData[]|The collection of MachineLearningPublicationEntityData each of which specifies the model and target document library.| + +### MachineLearningPublicationEntityData + +| Name | Required | Type | Description | +|--------|-------|--------|------------| +|ModelUniqueId|yes|string|The unique ID of the model file.| +|TargetSiteUrl|yes|string|The full URL of the target library site.| +|TargetWebServerRelativeUrl|yes|string|The server relative URL of the web for the target library.| +|TargetLibraryServerRelativeUrl|yes|string|The server relative URL of the target library.| +|ViewOption|no|string|Specifies whether to set new model view as the library default.| + +## Response + +| Name | Type | Description| +|--------|-------|------------| +|201 Created||This is a customized API to support applying a model to multi document libraries. In the case of partial success, 201 created could still be returned and the caller needs to inspect the response body to understand if the model has been successfully applied to a document library.| + +## Response Body + +| Name | Type | Description| +|--------|-------|------------| +|TotalSuccesses|int|The total number of a model being successfully applied to a document library.| +|TotalFailures|int|The total number of a model failing to be applied to a document library.| +|Details|MachineLearningPublicationResult[]|The collection of MachineLearningPublicationResult each of which specifies the detailed result of applying the model to the document library.| + +### MachineLearningPublicationResult + +| Name | Type | Description| +|--------|-------|------------| +|StatusCode|int|The HTTP status code.| +|ErrorMessage|string|The error message which tells what's wrong when apply the model to the document library.| +|Publication|MachineLearningPublicationEntityData|It specifies the model info and the target document library.| + +### MachineLearningPublicationEntityData + +| Name | Type | Description | +|--------|--------|------------| +|ModelUniqueId|string|The unique ID of the model file.| +|TargetSiteUrl|string|The full URL of the target library site.| +|TargetWebServerRelativeUrl|string|The server relative URL of the web for the target library.| +|TargetLibraryServerRelativeUrl|string|The server relative URL of the target library.| + +## Examples + +### Apply a model to the contracts document library in the repository site + +In this sample, the ID of the Contoso Contract document understanding model is `7645e69d-21fb-4a24-a17a-9bdfa7cb63dc`. + +#### Sample request + +```HTTP +{ + "__metadata": { + "type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningPublicationsEntityData" + }, + "Publications": { + "results": [ + { + "ModelUniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "TargetSiteUrl": "https://contoso.sharepoint.com/sites/repository/", + "TargetWebServerRelativeUrl": "/sites/repository", + "TargetLibraryServerRelativeUrl": "/sites/repository/contracts", + "ViewOption": "NewViewAsDefault" + } + ] + } +} +``` + + +#### Sample response + +In the response, TotalFailures and TotalSuccesses refers to the number of failures and successes of the model being applies to the specified libraries. + +**Status code:** 201 + +```JSON +{ + "Details": [ + { + "ErrorMessage": null, + "Publication": { + "ModelUniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "TargetSiteUrl": "https://contoso.sharepoint.com/sites/repository/", + "TargetWebServerRelativeUrl": "/sites/repository", + "TargetLibraryServerRelativeUrl": "/sites/repository/contracts", + "ViewOption": "NewViewAsDefault" + }, + "StatusCode": 201 + } + ], + "TotalFailures": 0, + "TotalSuccesses": 1 +} +``` + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-batchdelete-method.md b/docs/apis/syntex/rest-batchdelete-method.md new file mode 100644 index 000000000..546a3ca51 --- /dev/null +++ b/docs/apis/syntex/rest-batchdelete-method.md @@ -0,0 +1,132 @@ +--- +title: BatchDelete +description: Use REST API to remove an applied document understanding model from one or more libraries. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# BatchDelete + +Removes an applied document understanding model from one or more libraries. Note that a model must be removed from all libraries before it can be deleted (see [example](rest-batchdelete-method.md#examples)). + +## HTTP request + +```HTTP +POST /_api/machinelearning/publications/batchdelete HTTP/1.1 +``` + +## URI parameters + +None + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| +|Content-Type|application/json;odata=verbose;charset=utf-8| +|x-requestdigest|The appropriate digest for current site.| + +## Request body + +| Name | Required | Type | Description | +|--------|-------|--------|------------| +|Publications|yes|MachineLearningPublicationEntityData[]|The collection of MachineLearningPublicationEntityData each of which specifies the model and target document library.| + +### MachineLearningPublicationEntityData + +| Name | Required | Type | Description | +|--------|-------|--------|------------| +|ModelUniqueId|yes|string|The unique ID of the model file.| +|TargetSiteUrl|yes|string|The full URL of the target library site.| +|TargetWebServerRelativeUrl|yes|string|The server relative URL of the web for the target library.| +|TargetLibraryServerRelativeUrl|yes|string|The server relative URL of the target library.| + +## Response + +| Name | Type | Description| +|--------|-------|------------| +|200 OK||This is a customized API to support removing a model from multi document libraries. In the case of partial success, 200 OK could still be returned and the caller needs to inspect the response body to understand if the model has been successfully removed from a document library.| + +## Response Body + +| Name | Type | Description| +|--------|-------|------------| +|TotalSuccesses|int|The total number of a model being successfully removed from a document library.| +|TotalFailures|int|The total number of a model failing to be removed from a document library.| +|Details|MachineLearningPublicationResult[]|The collection of MachineLearningPublicationResult each of which specifies the detailed result of removing the model from a document library.| + +### MachineLearningPublicationResult + +| Name | Type | Description| +|--------|-------|------------| +|StatusCode|int|The HTTP status code.| +|ErrorMessage|string|The error message which tells what's wrong when apply the model to the document library.| +|Publication|MachineLearningPublicationEntityData|It specifies the model info and the target document library.| + +### MachineLearningPublicationEntityData + +| Name | Type | Description | +|--------|--------|------------| +|ModelUniqueId|string|The unique ID of the model file.| +|TargetSiteUrl|string|The full URL of the target library site.| +|TargetWebServerRelativeUrl|string|The server relative URL of the web for the target library.| +|TargetLibraryServerRelativeUrl|string|The server relative URL of the target library.| + +## Examples + +### Remove a model from the contracts document library in the repository site + +In this sample, the ID of the Contoso Contract document understanding model is `7645e69d-21fb-4a24-a17a-9bdfa7cb63dc`. + +#### Sample request + +```HTTP +{ + "publications": [ + { + "ModelUniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "TargetSiteUrl": "https://constco.sharepoint-df.com/sites/docsite", + "TargetWebServerRelativeUrl": "/sites/docsite ", + "TargetLibraryServerRelativeUrl": "/sites/dcocsite/joedcos" + } + ] +} +``` + +#### Sample response + +In the response, TotalFailures and TotalSuccesses refer to the number of failures and successes of the model being removed from the specified libraries. + +**Status code:** 200 + +```JSON +{ + "Details": [ + { + "ErrorMessage": null, + "Publication": { + "ModelUniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "TargetSiteUrl": "https://contoso.sharepoint.com/sites/repository/", + "TargetWebServerRelativeUrl": "/sites/repository", + "TargetLibraryServerRelativeUrl": "/sites/repository/contracts", + "ViewOption": "NewViewAsDefault" + }, + "StatusCode": 200 + } + ], + "TotalFailures": 0, + "TotalSuccesses": 1 +} +``` + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-createclassificationrequest.md b/docs/apis/syntex/rest-createclassificationrequest.md new file mode 100644 index 000000000..c4321f606 --- /dev/null +++ b/docs/apis/syntex/rest-createclassificationrequest.md @@ -0,0 +1,93 @@ +--- +title: Create file classification request +description: Use REST API to create a request to classify one or more files using a trained document understanding model. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# Create file classification request + +Creates a request to classify one or more files using the applied document understanding model. (For more information, see [example](rest-createclassificationrequest.md#examples).) + +The REST service of SharePoint Online (and SharePoint 2016 and later on-premises) supports the combining of multiple requests. Requests are combined into a single call to the service by using the OData $batch query option. This method can be used to enqueue classification work items for hundreds of documents at one time. + +## HTTP request + +```http +POST /_api/machinelearning/workItems HTTP/1.1 +``` + +## URI Parameters + +None + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| +|Content-Type|application/json;odata=verbose;charset=utf-8| +|x-requestdigest|The appropriate digest for current site| + +## Request body + +|Name |Type |Description | +|--------|-------|------------| +|_metadata|string |Set the object meta on the SPO. Always use the value: {"type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningWorkItemEntityData"}. | +|TargetSiteId|guid|The ID of the site where the file to classify is located. This can be omitted when TargetSiteUrl has a value. | +|TargetSiteUrl|string|The full URL of the site where the file to classify is located. This can be omitted when TargeSiteId has a value.| +|TargetWebId|guid|The ID of the web where the file to classify is located. This can be omitted when TargetWebServerRelativeUrl has a value. | +|TargetWebServerRelativeUrl|string|The server relative URL of the web where the file to classify is located. This can be omitted when TargetWebId has a value. | +|TargetUniqueId|guid|The ID of the folder to classify. This can be omitted when TargetServerRelativeUrl has a value. | +|TargetServerRelativeUrl|string|The server relative URL of the file to classify is located. This can be omitted when TargetUniqueId has a value.| + +## Responses + +| Name | Type | Description| +|--------|-------|------------| +|201 Created| |The response is customized. In there is failure, it could still return 201 Created. The caller should further check the response body to determine the exact result.| + +## Examples + +### Enqueue a request to classify a file of ID "e6cff8b7-c90c-4564-b5b8-033449090932" + +#### Sample request + +```JSON +{ + "__metadata": { + "type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningWorkItemEntityData" + }, + "TargetSiteId": "f686e63b-aba7-48e5-97c7-68c4c1df292f", + "TargetWebId": "66d6b64d-6f88-4dd9-b3db-47e6f00c53e8", + "TargetUniqueId": "e6cff8b7-c90c-4564-b5b8-033449090932" +} +``` + +#### Sample response + +**Status code:** 201 +```JSON +{ + "ErrorMessage": null, + "StatusCode": 201 +} +``` + +```JSON +{ + "ErrorMessage": null, + "StatusCode": 201 +} +``` + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-createfolderclassificationrequest.md b/docs/apis/syntex/rest-createfolderclassificationrequest.md new file mode 100644 index 000000000..4e6a04e17 --- /dev/null +++ b/docs/apis/syntex/rest-createfolderclassificationrequest.md @@ -0,0 +1,97 @@ +--- +title: Create folder classification request +description: Use REST API to create a request to classify an entire folder using a trained document understanding model. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# Create folder classification request + +Creates a request to classify a whole folder during off-peak hours by using the applied document understanding model. (For more information, see [example](rest-createfolderclassificationrequest.md#examples).) +This API can be used to classify a whole document library by creating a work item for its root folder. + +## HTTP request + +```http +POST /_api/machinelearning/workItems HTTP/1.1 +``` + +## URI Parameters + +None + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| +|Content-Type|application/json;odata=verbose;charset=utf-8| +|x-requestdigest|The appropriate digest for current site| + +## Request body + +|Name |Type |Description | +|--------|-------|------------| +|_metadata|string |Set the object meta on the SPO. Always use the value: {"type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningWorkItemEntityData"}. | +|TargetSiteId|guid|The ID of the site where the folder to classify is located. This can be omitted when TargetSiteUrl has a value. | +|TargetSiteUrl|string|The full URL of the site where the folder to classify is located. This can be omitted when TargeSiteId has a value.| +|TargetWebId|guid|The ID of the web where the folder to classify is located. This can be omitted when TargetWebServerRelativeUrl has a value. | +|TargetWebServerRelativeUrl|string|The server relative URL of the web where the folder to classify is located. This can be omitted when TargetWebId has a value. | +|TargetUniqueId|guid|The ID of the folder to classify. This can be omitted when TargetServerRelativeUrl has a value. | +|TargetServerRelativeUrl|string|The server relative URL of the folder to classify is located. This can be omitted when TargetUniqueId has a value.| +|IsFolder|boolean|The flag that indicates if what will be classified is a folder. Always set this to true for creating a folder classification work item. | + + +## Responses + +| Name | Type | Description| +|--------|-------|------------| +|201 Created| |The response is customized. If there is failure, it could still return 201 Created. The caller should further check the response body to determine the exact result.| + +## Response body + +| Name | Type | Description| +|--------|-------|------------| +|StatusCode |int |The HTTP status code. If it’s not 200 or 201, the API should have failed.| +|ErrorMessage |string |The error message that tells what's wrong when apply the model to the document library.| + +## Examples + +### Enqueue a request to classify a whole folder of ID "e6cff8b7-c90c-4564-b5b8-033449090932" + + +#### Sample request + +```JSON +{ + "__metadata": { + "type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningWorkItemEntityData" + }, + "TargetSiteId": "f686e63b-aba7-48e5-97c7-68c4c1df292f", + "TargetWebId": "66d6b64d-6f88-4dd9-b3db-47e6f00c53e8", + "TargetUniqueId": "e6cff8b7-c90c-4564-b5b8-033449090932", + "IsFolder": true +} +``` + +#### Sample response + +**Status code:** 201 + +```JSON +{ + "ErrorMessage": null, + "StatusCode": 201 +} +``` + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-createmodel-method.md b/docs/apis/syntex/rest-createmodel-method.md new file mode 100644 index 000000000..7bdc5f0c8 --- /dev/null +++ b/docs/apis/syntex/rest-createmodel-method.md @@ -0,0 +1,72 @@ +--- +title: Create model +description: Use REST API to create a model and its associated content type. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# Create model + +Creates a model and its associated content type. Note that this only creates the model. It will still need to be trained in the content center (see [example](rest-createmodel-method.md#examples)). + +## HTTP request + +```http +POST /_api/machinelearning/models HTTP/1.1 +``` +## URI Parameters + +None + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| +|Content-Type|application/json;odata=verbose;charset=utf-8| +|x-requestdigest|The appropriate digest for current site| + +## Request body + +|Name |Type |Description | +|--------|-------|------------| +|_metadata| |Set the object meta on the SPO. Always use the value: {"type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningModelEntityData"}. | +|ContentTypeGroup|string|The associated content type group associated with the model. Defaulted to "Intelligent Document Content Types".| +|ContentTypeName|string|The associated content type name. The created model file will have the same name.| + +## Responses + +| Name | Type | Description| +|--------|-------|------------| +|201 Created| |Success| + +## Examples + +### Create a new document understanding model called "Contoso Contract" + +#### Sample request + +```json +{ + "__metadata": { + "type": "Microsoft.Office.Server.ContentCenter.SPMachineLearningModelEntityData" + }, + "ContentTypeGroup": "Intelligent Document Content Types", + "ContentTypeName": "Contoso Contract" +} +``` + +#### Sample response + +**Status code:** 201 + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-getbytitle-method.md b/docs/apis/syntex/rest-getbytitle-method.md new file mode 100644 index 000000000..eb185e33c --- /dev/null +++ b/docs/apis/syntex/rest-getbytitle-method.md @@ -0,0 +1,111 @@ +--- +title: GetByTitle +description: Use REST API to get or update information about a Microsoft Syntex document understanding model using the model title. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: article +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# GetByTitle + +Gets or updates information about a Microsoft Syntex document understanding model using the model title (see [example](rest-getbytitle-method.md#examples)). + +## HTTP request + +```HTTP +GET /_api/machinelearning/models/getbytitle('{modelFileName}') HTTP/1.1 +``` + +This same method can be used for deleting a model, too. + +```HTTP +DELETE /_api/machinelearning/models/getbytitle('{modelFileName}') HTTP/1.1 +``` + +## URI parameters + +|Name |In |Required|Type|Description| +|-----|---|--------|----|-----------| +|modelFileName|query|True|string|Name of the Syntex model file.| + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| + +## Request body + +For GET, no request body is needed. + +## Responses + +| Name | Type | Description| +|--------|-------|------------| +|200 OK| |Success| + +## Examples + +### Get information about the Contoso Contract model + +In this sample, the name of the Syntex document understanding model is `Contoso Contract`. + +#### Sample request + +```HTTP +GET /_api/machinelearning/models/getbytitle('Contoso Contract') HTTP/1.1 +``` + +#### Sample response + +**Status code:** 200 + +```HTTP +{ + "@odata.context": "https://contoso.sharepoint.com/sites/filerepository/_api/$metadata#models/$entity", + "@odata.type": "#Microsoft.Office.Server.ContentCenter.SPMachineLearningModel", + "@odata.id": "https://contoso.sharepoint.com/sites/filerepository/_api/machinelearning/models/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "@odata.etag": "\"7645e69d-21fb-4a24-a17a-9bdfa7cb63dc,111\"", + "@odata.editLink": " https://contoso.sharepoint.com/sites/filerepository /_api/machinelearning/models/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "ConfidenceScore": "{\"trainingStatus\":{\"kind\":\"original\",\"ClassifierStatus\":{\"TrainingStatus\":\"success\",\"TimeStamp\":1611716640535},\"ExtractorsStatus\":[{\"TimeStamp\":1585175746775,\"ExtractorName\":\"Contract Name\",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1586905975794,\"ExtractorName\":\"Client \",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1586906061099,\"ExtractorName\":\"Contract Date\",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1586907912388,\"ExtractorName\":\"Fee\",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1611716640115,\"ExtractorName\":\"ServiceType\",\"TrainingStatus\":\"success\"}]},\"modelAccuracy\":{\"Classifier\":1,\"Extractors\":{\"Contract Name\":1,\"Client \":1,\"Contract Date\":1,\"Fee\":1,\"ServiceType\":1}},\"perSampleAccuracy\":{\"133\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"249\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"252\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"253\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"254\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"255\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"256\":{\"Extractors\":{\"ServiceType\":1}},\"257\":{\"Extractors\":{\"ServiceType\":1}}},\"perSamplePrediction\":{\"133\":{\"Extractors\":{\"ServiceType\":[]}},\"249\":{\"Extractors\":{\"ServiceType\":[\"Writing\"]}},\"252\":{\"Extractors\":{\"ServiceType\":[\"Catering\"]}},\"253\":{\"Extractors\":{\"ServiceType\":[\"Design\"]}},\"254\":{\"Extractors\":{\"ServiceType\":[\"Marketing\"]}},\"255\":{\"Extractors\":{\"ServiceType\":[\"Financial Planning\"]}},\"256\":{\"Extractors\":{\"ServiceType\":[\"Writing\"]}},\"257\":{\"Extractors\":{\"ServiceType\":[\"Writing\"]}}},\"trainingFailures\":{}}", + "ContentTypeGroup": "Intelligent Document Content Types", + "ContentTypeId": "0x01010083DF84D4F59BBD4CB06F075AA81F58AA", + "ContentTypeName": "Contoso Contract", + "Created": "2020-03-25T22:04:04Z", + "CreatedBy": "i:0#.f|membership|meganb@contoso.com", + "DriveId": "b!O-aG9qer5UiXx2jEwd8pL0221maIb9lNs9tH5vAMU-h2NuHxlYUiTJyiwKQHZobK", + "Explanations": "{\"Classifier\":[{\"id\":\"8122ac1d-8fcb-4705-8872-2825cbf05bfe\",\"kind\":\"dictionaryFeature\",\"name\":\"agreement\",\"active\":true,\"nGrams\":[\"CONSULTING AGREEMENT\",\"SERVICES AGREEMENT\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"af83bea8-bc53-4e93-a3da-f1e697eb6bef\",\"kind\":\"modelFeature\",\"name\":\"Contract Name\",\"active\":true,\"modelReference\":\"Contract Name\",\"conceptId\":\"841d0dcf-7f1d-4a39-931c-53923d10c346\"},{\"id\":\"e3734994-9e34-40e3-82c7-bb6c7bc5a0c3\",\"kind\":\"modelFeature\",\"name\":\"Client \",\"active\":true,\"modelReference\":\"Client \",\"conceptId\":\"8b8490d0-9a09-4c16-bcff-59ce62e05c28\"},{\"id\":\"7c93e7fe-cbfb-47ee-8cca-46ecdf5f628f\",\"kind\":\"modelFeature\",\"name\":\"Contract Date\",\"active\":true,\"modelReference\":\"Contract Date\",\"conceptId\":\"6ba58918-e2f0-4685-9080-98ec4c3adc7c\"},{\"id\":\"5cc85b62-148a-4b07-9155-d9fb7cebb6d0\",\"kind\":\"modelFeature\",\"name\":\"Fee\",\"active\":true,\"modelReference\":\"Fee\",\"conceptId\":\"9c7f764d-afd2-49cd-aaa2-e9407156bfb3\"},{\"id\":\"0f8a23a6-c744-4cae-82bd-d836332ceb56\",\"kind\":\"modelFeature\",\"name\":\"ServiceType\",\"active\":true,\"modelReference\":\"ServiceType\",\"conceptId\":\"4aa9f2fe-cfab-49f8-86b1-11646c79cdbf\"}],\"Extractors\":{\"Contract Name\":[{\"id\":\"8804fbeb-bcf8-44c0-8ade-3fc65496037f\",\"kind\":\"dictionaryFeature\",\"name\":\"before\",\"active\":true,\"nGrams\":[\"- AND -\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}],\"Client \":[{\"id\":\"606c56de-9e71-42ef-8ec6-f0bbf351d673\",\"kind\":\"dictionaryFeature\",\"name\":\"start\",\"active\":true,\"nGrams\":[\"BETWEEN:\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"334e6df5-e076-40db-a47b-f11ceec7af9a\",\"kind\":\"dictionaryFeature\",\"name\":\"after\",\"active\":true,\"nGrams\":[\"of\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"bccefd2e-88a4-406c-aa9d-81d508bbafb3\",\"kind\":\"proximityFeature\",\"name\":\"prox\",\"active\":true,\"patterns\":[[{\"id\":\"606c56de-9e71-42ef-8ec6-f0bbf351d673\",\"kind\":\"proximityFeatureReference\"},{\"kind\":\"proximityTokenRange\",\"minCount\":1,\"maxCount\":6},{\"id\":\"334e6df5-e076-40db-a47b-f11ceec7af9a\",\"kind\":\"proximityFeatureReference\"}]]}],\"Contract Date\":[{\"id\":\"fabe1ed3-07af-4dc6-852d-fe9521c64801\",\"kind\":\"dictionaryFeature\",\"name\":\"dated\",\"active\":true,\"nGrams\":[\"dated\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"983da7b8-51d7-4a85-9644-007b488fce0b\",\"kind\":\"dictionaryFeature\",\"name\":\"betw\",\"active\":true,\"nGrams\":[\"between\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}],\"Fee\":[{\"id\":\"f4cf89dc-64d1-49a1-9be4-41debda251b6\",\"kind\":\"dictionaryFeature\",\"name\":\"flat fee of \",\"active\":true,\"nGrams\":[\"flat fee of $\",\"flat fee of $$\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}],\"ServiceType\":[{\"id\":\"c04408f5-ce14-4eb0-81d0-f72ea9fa7e83\",\"kind\":\"dictionaryFeature\",\"name\":\"Before label\",\"active\":true,\"nGrams\":[\"will provide \"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"ea94fa7f-e41b-4e09-a484-355912bfbdff\",\"kind\":\"dictionaryFeature\",\"name\":\"After label\",\"active\":true,\"nGrams\":[\"services for \"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}]}}", + "ID": 16, + "LastTrained": "2021-01-27T03:04:00Z", + "ListID": "f1e13676-8595-4c22-9ca2-c0a4076686ca", + "ModelSettings": null, + "ModelType": 2, + "Modified": "2021-01-27T03:05:04Z", + "ModifiedBy": "i:0#.f|membership|kevinche@contoso.com", + "ObjectId": "01ZBWEM5E54ZCXN6ZBERFKC6U336T4WY64", + "PublicationType": 0, + "Schemas": "{\"Extractors\":{\"Contract Name\":{\"concepts\":{\"841d0dcf-7f1d-4a39-931c-53923d10c346\":{\"name\":\"Contract Name\"}},\"relationships\":[]},\"Client \":{\"concepts\":{\"8b8490d0-9a09-4c16-bcff-59ce62e05c28\":{\"name\":\"Client \"}},\"relationships\":[]},\"Contract Date\":{\"concepts\":{\"6ba58918-e2f0-4685-9080-98ec4c3adc7c\":{\"name\":\"Contract Date\"}},\"relationships\":[]},\"Fee\":{\"concepts\":{\"9c7f764d-afd2-49cd-aaa2-e9407156bfb3\":{\"name\":\"Fee\"}},\"relationships\":[]},\"ServiceType\":{\"concepts\":{\"4aa9f2fe-cfab-49f8-86b1-11646c79cdbf\":{\"name\":\"ServiceType\",\"termSetId\":\"76c12efb-5173-4982-ae9b-5f9e37187171\"}},\"relationships\":[]}}}", + "SourceUrl": null, + "UniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc" +} +``` + +### Get and delete the Contoso Contract model by name + +In this sample, the name of the Contoso Contract document understanding model is `Contoso Contract`. + +##### Sample request + +```HTTP +DELETE /_api/machinelearning/models/getbytitle('Contoso Contract') HTTP/1.1 +``` + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-getbyuniqueid-method.md b/docs/apis/syntex/rest-getbyuniqueid-method.md new file mode 100644 index 000000000..a22cb154e --- /dev/null +++ b/docs/apis/syntex/rest-getbyuniqueid-method.md @@ -0,0 +1,110 @@ +--- +title: GetByUniqueId +description: Use REST API to get or update information about a Microsoft Syntex document understanding model. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# GetByUniqueId + +Gets or updates information about a Microsoft Syntex document understanding model (see [example](rest-getbyuniqueid-method.md#examples)). + +## HTTP request + +```HTTP +GET /_api/machinelearning/models/getbyuniqueid('{modelUniqueId}') HTTP/1.1 +``` + +This same method can be used for deleting a model, too. + +```HTTP +DELETE /_api/machinelearning/models/getbyuniqueid('{modelUniqueId}') HTTP/1.1 +``` +## URI parameters + +|Name |In |Required|Type|Description| +|-----|---|--------|----|-----------| +|modelUniqueId|query|True|string|ID of the Syntex model file.| + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| + +## Request body + +For GET, no request body is needed. + +## Responses + +| Name | Type | Description| +|--------|-------|------------| +|200 OK| |Success| + +## Examples + +### Get the Contoso Contract model by ID + +In this sample, the ID of the Contoso Contract document understanding model is `7645e69d-21fb-4a24-a17a-9bdfa7cb63dc`. + +#### Sample request + +```HTTP +GET /_api/machinelearning/models/getbyuniqueid('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc') HTTP/1.1 +``` + +#### Sample response + +**Status code:** 200 + +```HTTP +{ + "@odata.context": "https://contoso.sharepoint.com/sites/filerepository/_api/$metadata#models/$entity", + "@odata.type": "#Microsoft.Office.Server.ContentCenter.SPMachineLearningModel", + "@odata.id": "https://contoso.sharepoint.com/sites/filerepository/_api/machinelearning/models/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "@odata.etag": "\"7645e69d-21fb-4a24-a17a-9bdfa7cb63dc,111\"", + "@odata.editLink": " https://contoso.sharepoint.com/sites/filerepository /_api/machinelearning/models/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "ConfidenceScore": "{\"trainingStatus\":{\"kind\":\"original\",\"ClassifierStatus\":{\"TrainingStatus\":\"success\",\"TimeStamp\":1611716640535},\"ExtractorsStatus\":[{\"TimeStamp\":1585175746775,\"ExtractorName\":\"Contract Name\",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1586905975794,\"ExtractorName\":\"Client \",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1586906061099,\"ExtractorName\":\"Contract Date\",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1586907912388,\"ExtractorName\":\"Fee\",\"TrainingStatus\":\"success\"},{\"TimeStamp\":1611716640115,\"ExtractorName\":\"ServiceType\",\"TrainingStatus\":\"success\"}]},\"modelAccuracy\":{\"Classifier\":1,\"Extractors\":{\"Contract Name\":1,\"Client \":1,\"Contract Date\":1,\"Fee\":1,\"ServiceType\":1}},\"perSampleAccuracy\":{\"133\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"249\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"252\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"253\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"254\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"255\":{\"Classifier\":1,\"Extractors\":{\"ServiceType\":1}},\"256\":{\"Extractors\":{\"ServiceType\":1}},\"257\":{\"Extractors\":{\"ServiceType\":1}}},\"perSamplePrediction\":{\"133\":{\"Extractors\":{\"ServiceType\":[]}},\"249\":{\"Extractors\":{\"ServiceType\":[\"Writing\"]}},\"252\":{\"Extractors\":{\"ServiceType\":[\"Catering\"]}},\"253\":{\"Extractors\":{\"ServiceType\":[\"Design\"]}},\"254\":{\"Extractors\":{\"ServiceType\":[\"Marketing\"]}},\"255\":{\"Extractors\":{\"ServiceType\":[\"Financial Planning\"]}},\"256\":{\"Extractors\":{\"ServiceType\":[\"Writing\"]}},\"257\":{\"Extractors\":{\"ServiceType\":[\"Writing\"]}}},\"trainingFailures\":{}}", + "ContentTypeGroup": "Intelligent Document Content Types", + "ContentTypeId": "0x01010083DF84D4F59BBD4CB06F075AA81F58AA", + "ContentTypeName": "Contoso Contract", + "Created": "2020-03-25T22:04:04Z", + "CreatedBy": "i:0#.f|membership|meganb@contoso.com", + "DriveId": "b!O-aG9qer5UiXx2jEwd8pL0221maIb9lNs9tH5vAMU-h2NuHxlYUiTJyiwKQHZobK", + "Explanations": "{\"Classifier\":[{\"id\":\"8122ac1d-8fcb-4705-8872-2825cbf05bfe\",\"kind\":\"dictionaryFeature\",\"name\":\"agreement\",\"active\":true,\"nGrams\":[\"CONSULTING AGREEMENT\",\"SERVICES AGREEMENT\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"af83bea8-bc53-4e93-a3da-f1e697eb6bef\",\"kind\":\"modelFeature\",\"name\":\"Contract Name\",\"active\":true,\"modelReference\":\"Contract Name\",\"conceptId\":\"841d0dcf-7f1d-4a39-931c-53923d10c346\"},{\"id\":\"e3734994-9e34-40e3-82c7-bb6c7bc5a0c3\",\"kind\":\"modelFeature\",\"name\":\"Client \",\"active\":true,\"modelReference\":\"Client \",\"conceptId\":\"8b8490d0-9a09-4c16-bcff-59ce62e05c28\"},{\"id\":\"7c93e7fe-cbfb-47ee-8cca-46ecdf5f628f\",\"kind\":\"modelFeature\",\"name\":\"Contract Date\",\"active\":true,\"modelReference\":\"Contract Date\",\"conceptId\":\"6ba58918-e2f0-4685-9080-98ec4c3adc7c\"},{\"id\":\"5cc85b62-148a-4b07-9155-d9fb7cebb6d0\",\"kind\":\"modelFeature\",\"name\":\"Fee\",\"active\":true,\"modelReference\":\"Fee\",\"conceptId\":\"9c7f764d-afd2-49cd-aaa2-e9407156bfb3\"},{\"id\":\"0f8a23a6-c744-4cae-82bd-d836332ceb56\",\"kind\":\"modelFeature\",\"name\":\"ServiceType\",\"active\":true,\"modelReference\":\"ServiceType\",\"conceptId\":\"4aa9f2fe-cfab-49f8-86b1-11646c79cdbf\"}],\"Extractors\":{\"Contract Name\":[{\"id\":\"8804fbeb-bcf8-44c0-8ade-3fc65496037f\",\"kind\":\"dictionaryFeature\",\"name\":\"before\",\"active\":true,\"nGrams\":[\"- AND -\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}],\"Client \":[{\"id\":\"606c56de-9e71-42ef-8ec6-f0bbf351d673\",\"kind\":\"dictionaryFeature\",\"name\":\"start\",\"active\":true,\"nGrams\":[\"BETWEEN:\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"334e6df5-e076-40db-a47b-f11ceec7af9a\",\"kind\":\"dictionaryFeature\",\"name\":\"after\",\"active\":true,\"nGrams\":[\"of\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"bccefd2e-88a4-406c-aa9d-81d508bbafb3\",\"kind\":\"proximityFeature\",\"name\":\"prox\",\"active\":true,\"patterns\":[[{\"id\":\"606c56de-9e71-42ef-8ec6-f0bbf351d673\",\"kind\":\"proximityFeatureReference\"},{\"kind\":\"proximityTokenRange\",\"minCount\":1,\"maxCount\":6},{\"id\":\"334e6df5-e076-40db-a47b-f11ceec7af9a\",\"kind\":\"proximityFeatureReference\"}]]}],\"Contract Date\":[{\"id\":\"fabe1ed3-07af-4dc6-852d-fe9521c64801\",\"kind\":\"dictionaryFeature\",\"name\":\"dated\",\"active\":true,\"nGrams\":[\"dated\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"983da7b8-51d7-4a85-9644-007b488fce0b\",\"kind\":\"dictionaryFeature\",\"name\":\"betw\",\"active\":true,\"nGrams\":[\"between\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}],\"Fee\":[{\"id\":\"f4cf89dc-64d1-49a1-9be4-41debda251b6\",\"kind\":\"dictionaryFeature\",\"name\":\"flat fee of \",\"active\":true,\"nGrams\":[\"flat fee of $\",\"flat fee of $$\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}],\"ServiceType\":[{\"id\":\"c04408f5-ce14-4eb0-81d0-f72ea9fa7e83\",\"kind\":\"dictionaryFeature\",\"name\":\"Before label\",\"active\":true,\"nGrams\":[\"will provide \"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"ea94fa7f-e41b-4e09-a484-355912bfbdff\",\"kind\":\"dictionaryFeature\",\"name\":\"After label\",\"active\":true,\"nGrams\":[\"services for \"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}]}}", + "ID": 16, + "LastTrained": "2021-01-27T03:04:00Z", + "ListID": "f1e13676-8595-4c22-9ca2-c0a4076686ca", + "ModelSettings": null, + "ModelType": 2, + "Modified": "2021-01-27T03:05:04Z", + "ModifiedBy": "i:0#.f|membership|kevinche@contoso.com", + "ObjectId": "01ZBWEM5E54ZCXN6ZBERFKC6U336T4WY64", + "PublicationType": 0, + "Schemas": "{\"Extractors\":{\"Contract Name\":{\"concepts\":{\"841d0dcf-7f1d-4a39-931c-53923d10c346\":{\"name\":\"Contract Name\"}},\"relationships\":[]},\"Client \":{\"concepts\":{\"8b8490d0-9a09-4c16-bcff-59ce62e05c28\":{\"name\":\"Client \"}},\"relationships\":[]},\"Contract Date\":{\"concepts\":{\"6ba58918-e2f0-4685-9080-98ec4c3adc7c\":{\"name\":\"Contract Date\"}},\"relationships\":[]},\"Fee\":{\"concepts\":{\"9c7f764d-afd2-49cd-aaa2-e9407156bfb3\":{\"name\":\"Fee\"}},\"relationships\":[]},\"ServiceType\":{\"concepts\":{\"4aa9f2fe-cfab-49f8-86b1-11646c79cdbf\":{\"name\":\"ServiceType\",\"termSetId\":\"76c12efb-5173-4982-ae9b-5f9e37187171\"}},\"relationships\":[]}}}", + "SourceUrl": null, + "UniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc" +} +``` + +### Get and delete the Contoso Contract model by ID + +In this sample, the ID of the Contoso Contract document understanding model is `7645e69d-21fb-4a24-a17a-9bdfa7cb63dc`. + +#### Sample request + +```HTTP +DELETE /_api/machinelearning/models/getbyuniqueid('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc') HTTP/1.1 +``` + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-getmodelandlibraryinfo.md b/docs/apis/syntex/rest-getmodelandlibraryinfo.md new file mode 100644 index 000000000..2ae731fe7 --- /dev/null +++ b/docs/apis/syntex/rest-getmodelandlibraryinfo.md @@ -0,0 +1,122 @@ +--- +title: Get model and library info +description: Use REST API to get information about a model and the library where it has been applied. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# Get model and library information + +Gets information about a model and the library where it has been applied (see [example](rest-getmodelandlibraryinfo.md#examples)). + +## HTTP request + +```HTTP +GET /_api/machinelearning/publications/getbymodeluniqueid('{modelUniqueId}') HTTP/1.1 +``` + +## URI parameters + +| Name | In | Required | Type | Description | +|--------|-------|--------|------------|-----------| +|ModelUniqueId|query|True|GUID|The unique id of the model file.| + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| + + +## Response + +| Name | Type | Description| +|--------|-------|------------| +|200 OK| |Success| + +## Examples + +### Get information about the contracts model and primed document library in the repository site + +In this sample, the ID of the Contoso Contract document understanding model is `7645e69d-21fb-4a24-a17a-9bdfa7cb63dc`. + +#### Sample request + +```HTTP +GET /sites/TestCC/_api/machinelearning/publications/getbymodeluniqueid('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc') HTTP/1.1 +``` + +#### Sample response + +**Status code:** 200 + +```JSON +{ + "@odata.context": "https://contoso.sharepoint.com/sites/TestCC/_api/$metadata#publications", + "value": [ + { + "@odata.type": "#Microsoft.Office.Server.ContentCenter.SPMachineLearningPublication", + "@odata.id": "https://contoso.sharepoint.com/sites/repository /_api/machinelearning/publications/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "@odata.etag": "\"7645e69d-21fb-4a24-a17a-9bdfa7cb63dc,94\"", + "@odata.editLink": " https://contoso.sharepoint.com/sites/TestCC /_api/machinelearning/publications/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "Created": "2021-04-27T03:05:25Z", + "CreatedBy": "i:0#.f|membership|meganb@contoso.com", + "DriveId": "b!O-aG9qer5UiXx2jEwd8pL0221maIb9lNs9tH5vAMU-gPy9BrxT7GTrtXtdtv1Uzb", + "ID": 26, + "ModelId": 16, + "ModelName": "contosocontract.classifier", + "ModelType": 0, + "ModelUniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "ModelVersion": "8.0", + "Modified": "2021-03-17T17:56:42Z", + "ModifiedBy": "i:0#.f|membership|joedoe@contoso.com", + "ObjectId": "01ZBWEM5FZRILGLXTEB5CZ2NNNSCTWBJMQ", + "PublicationType": 1, + "TargetLibraryRemoved": false, + "TargetLibraryServerRelativeUrl": "/sites/repository/contracts", + "TargetLibraryUrl": " https://contoso.sharepoint.com/sites/repository/contracts", + "TargetSiteUrl": "https://contoso.sharepoint.com/sites/repository", + "TargetWebServerRelativeUrl": "/sites/repository", + "UniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "ViewOption": "NewViewAsDefault" + }, + { + "@odata.type": "#Microsoft.Office.Server.ContentCenter.SPMachineLearningPublication", + "@odata.id": "https://contoso.sharepoint.com /sites/legal/_api/machinelearning/publications/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "@odata.etag": "\"7645e69d-21fb-4a24-a17a-9bdfa7cb63dc,101\"", + "@odata.editLink": "https://contoso.sharepoint.com /sites/legal/_api/machinelearning/publications/getbyuniqueId('7645e69d-21fb-4a24-a17a-9bdfa7cb63dc')", + "Created": "2021-01-27T03:17:44Z", + "CreatedBy": "i:0#.f|membership|esherman@contoso.com ", + "DriveId": "b!O-aG9qer5UiXx2jEwd8pL0221maIb9lNs9tH5vAMU-gPy9BrxT7GTrtXtdtv1Uzb", + "ID": 27, + "ModelId": 16, + "ModelName": "dispositions.classifier", + "ModelType": 0, + "ModelUniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "ModelVersion": "8.0", + "Modified": "2021-03-17T23:17:46Z", + "ModifiedBy": "i:0#.f|membership|esherman@contoso.com ", + "ObjectId": "01ZBWEM5B3ERSZK4PAARGLFZ7JP6GMXG2R", + "PublicationType": 1, + "TargetLibraryRemoved": false, + "TargetLibraryServerRelativeUrl": "/sites/legal/dispositions", + "TargetLibraryUrl": "https://contoso.sharepoint.com/sites/legal/dispositions", + "TargetSiteUrl": " https://contoso.sharepoint.com/sites/legal", + "TargetWebServerRelativeUrl": "/sites/legal", + "UniqueId": "7645e69d-21fb-4a24-a17a-9bdfa7cb63dc", + "ViewOption": "NewViewAsDefault" + } + ] +} +``` + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/rest-updatemodelsettings-method.md b/docs/apis/syntex/rest-updatemodelsettings-method.md new file mode 100644 index 000000000..904565c66 --- /dev/null +++ b/docs/apis/syntex/rest-updatemodelsettings-method.md @@ -0,0 +1,74 @@ +--- +title: UpdateModelSettings +description: Use REST API to update available models settings for a Microsoft Syntex document understanding model. +ms.date: 09/23/2022 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: high +--- + +# UpdateModelSettings + +Updates available models settings (associated retention label and model description) for a Microsoft Syntex document understanding model (see [example](rest-updatemodelsettings-method.md#examples)). + +## HTTP request + +```HTTP +POST /_api/machinelearning/models/getbytitle('{modelFileName}')/updatemodelsettings HTTP/1.1 +``` + +## URI parameters + +|Name |In |Required|Type|Description| +|-----|---|--------|----|-----------| +|modelFileName|query|True|string|Name of the Syntex model file.| + +## Request headers + +| Header | Value | +|--------|-------| +|Accept|application/json;odata=verbose| +|Content-Type|application/json;odata=verbose;charset=utf-8| +|x-requestdigest|The appropriate digest for the current site.| + +## Request body + +|Name |Type |Description | +|--------|-------|-------| +|ModelSettings|string|JSON of model settings.| +|Description|string|The model description.| +|RetentionLabel| |Info for the associated label (label ID and name).| + +## Responses + +| Name | Type | Description| +|--------|-------|------------| +|200 OK| |Success| + +## Examples + +### Update model settings for Contoso Contract + +In this example, the model description and "Standard Hold" retention label are updated. The ID of the retention label is `27c5fcba-abfd-4c34-823d-0b4a48f7ffe6`. + +#### Sample request + +```HTTP +{ + "ModelSettings": "{\"Description\":\"This model is used to set files classified as Contoso Contracts with a standard hold retention.\", \"RetentionLabel\":{\"Id\":\"27c5fcba-abfd-4c34-823d-0b4a48f7ffe6\",\"Name\":\"Standard Hold\"}}" +} + +``` + +#### Sample response + +**Status code:** 200 + +## See also + +[Syntex document understanding model REST API](syntex-model-rest-api.md) diff --git a/docs/apis/syntex/syntex-model-rest-api.md b/docs/apis/syntex/syntex-model-rest-api.md new file mode 100644 index 000000000..277c633dd --- /dev/null +++ b/docs/apis/syntex/syntex-model-rest-api.md @@ -0,0 +1,57 @@ +--- +title: Unstructured document understanding model REST API +description: Overview of the document understanding model REST API. +ms.date: 07/21/2025 +ms.author: chucked +author: chuckedmonson +manager: pamgreen +ms.reviewer: ssquires +audience: admin +ms.topic: reference +ms.collection: m365initiative-syntex +ms.localizationpriority: medium +--- + +# Unstructured document processing model REST API + +You can use the SharePoint REST interface to create an unstructured document processing model, apply or remove the model to one or more libraries, and obtain or update information about the model. + +The SharePoint Online (and SharePoint 2016 and later on-premises) REST service supports combining multiple requests into a single call to the service by using the OData $batch query option. + +For details and links to code samples, see [Make batch requests with the REST APIs](/sharepoint/dev/sp-add-ins/make-batch-requests-with-the-rest-apis). + +## Prerequisites + +Before you get started, make sure that you're familiar with the following: + +- [Get to know the SharePoint REST service](/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service) +- [Complete basic operations using SharePoint REST endpoints](/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints) + +## REST commands + +The following REST commands are available for working with unstructured document processing models: + +- [Create model](rest-createmodel-method.md) – Creates a model and its associated content type. +- [GetByUniqueId](rest-getbyuniqueid-method.md) – Gets or updates information about an unstructured document processing model. +- [GetByTitle](rest-getbytitle-method.md) – Gets or updates information about an unstructured document processing model using the model title. +- [Apply model](rest-applymodel-method.md) – Applies (or syncs) a trained unstructured document processing model to one or more libraries. +- [Get model and library information](rest-getmodelandlibraryinfo.md) – Gets information about a model and the library where it has been applied. +- [UpdateModelSettings](rest-updatemodelsettings-method.md) – Updates available models settings (associated retention label and model description) for an unstructured document processing model. +- [BatchDelete](rest-batchdelete-method.md) – Removes an applied unstructured document processing model from one or more libraries. +- [Create file classification request](rest-createclassificationrequest.md) – Creates a request to classify a specified file or files using the applied model. +- [Create folder classification request](rest-createclassificationrequest.md) – Creates a request to classify an entire folder using the applied model. + +## Scenarios + +Note the following scenario examples that aren't intuitive from the method name. For more information, see each article. + +The create model method only creates the model object and its associated content type. You'll need to first train the model in the content center before it can be applied to a library. + +The apply model method is used to configure the model on the target library to classify documents and optionally extract additional information. This API also supports batch applying the model to multiple libraries. + +The remove model method just removes the model from one or more libraries where it was previously applied. If you want to delete the model, it must first be removed from all the libraries where it was applied. + + +## See also + +[Unstructured document processing overview](/microsoft-365/contentunderstanding/document-understanding-overview) diff --git a/docs/apis/webhooks/get-started-webhooks.md b/docs/apis/webhooks/get-started-webhooks.md index c04f63d55..c3b73e38a 100644 --- a/docs/apis/webhooks/get-started-webhooks.md +++ b/docs/apis/webhooks/get-started-webhooks.md @@ -1,17 +1,14 @@ --- title: Get started with SharePoint webhooks description: Build an application that adds and handles SharePoint webhook requests. -ms.date: 03/14/2018 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 09/23/2022 +ms.localizationpriority: high --- - - # Get started with SharePoint webhooks This article describes how to build an application that adds and handles SharePoint webhook requests. You will learn how to use [Postman client](https://www.getpostman.com/) to construct and execute SharePoint webhook requests quickly while interacting with a simple ASP.NET Web API as the webhook receiver. -You will use plain HTTP requests, which is useful for helping you understand how webhooks work. +You will use plain HTTP requests, which is useful for helping you understand how webhooks work. To complete the step-by-step instructions in this article, download and install the following tools: @@ -23,27 +20,25 @@ To complete the step-by-step instructions in this article, download and install ## Step 1: Register an Azure AD application for Postman client -In order for the Postman client to communicate with SharePoint, you need to register a Microsoft Azure Active Directory (Azure AD) app in your Azure AD tenant associated with your Office 365 tenant. +In order for the Postman client to communicate with SharePoint, you need to register a Microsoft Azure Active Directory (Azure AD) app in your Azure AD tenant associated with your Office 365 tenant. 1. Ensure that you register the application as a **Web Application**. +1. To access SharePoint Online, it's important to grant the Azure AD app permissions to the **Office 365 SharePoint Online** application and select the **read and write items and lists in all site collections** permission. -2. To access SharePoint Online, it's important to grant the Azure AD app permissions to the **Office 365 SharePoint Online** application and select the **read and write items and lists in all site collections** permission. - - > [!NOTE] - > For more information about adding an Azure AD application and granting permissions to applications, see [Adding an application](/azure/active-directory/develop/active-directory-integrating-applications#adding-an-application). + > [!NOTE] + > For more information about adding an Azure AD application and granting permissions to applications, see [Adding an application](/azure/active-directory/develop/active-directory-integrating-applications#adding-an-application). -3. Enter the following endpoint as the Reply (Redirect) URL for the app. This is the endpoint to which Azure AD will send the authentication response, including the access token, if authentication was successful. +1. Enter the following endpoint as the Reply (Redirect) URL for the app. This is the endpoint to which Azure AD will send the authentication response, including the access token, if authentication was successful. - ```html - https://www.getpostman.com/oauth2/callback - ``` + ```html + https://www.getpostman.com/oauth2/callback + ``` -4. Generate a **Key**, which will be the client secret. +1. Generate a **Key**, which will be the client secret. +1. The following properties are required in later steps, so copy them to a safe place: -5. The following properties are required in later steps, so copy them to a safe place: - - * Client Id - * Client Secret + * Client Id + * Client Secret ## Step 2: Build a webhook receiver @@ -52,22 +47,14 @@ For this project, use the Visual Studio Web API project to build the webhook rec ### Create a new ASP.NET Web API project 1. Open Visual Studio. - -2. Select **File** > **New** > **Project**. - -3. In the **Templates** pane, select **Installed Templates**, and expand the **Visual C#** node. - -4. Under **Visual C#**, select **Web**. - -5. In the list of project templates, select **ASP.NET Web Application**. - -6. Name the project **SPWebhooksReceiver**, and select **OK**. - -7. In the **New ASP.NET Project** dialog, select the **Web API** template from the **ASP.NET 4.5.** group. - -8. Change the authentication to **No Authentication** by selecting the **Change Authentication** button. - -9. Select **OK** to create the Web API project. +1. Select **File** > **New** > **Project**. +1. In the **Templates** pane, select **Installed Templates**, and expand the **Visual C#** node. +1. Under **Visual C#**, select **Web**. +1. In the list of project templates, select **ASP.NET Web Application**. +1. Name the project **SPWebhooksReceiver**, and select **OK**. +1. In the **New ASP.NET Project** dialog, select the **Web API** template from the **ASP.NET 4.5.** group. +1. Change the authentication to **No Authentication** by selecting the **Change Authentication** button. +1. Select **OK** to create the Web API project. > [!NOTE] > You can clear the **Host in the cloud** check box because this project will not be deployed to the cloud. @@ -81,70 +68,54 @@ Visual Studio creates your project. Use ASP.NET Web API Tracing to log the requests coming from SharePoint. The following steps install the tracing package: 1. Go to **Solution Explorer** in Visual Studio. - -2. Open the context menu (right-click) for the project, and select **Manage NuGet Packages**. - -3. In the search box, enter **Microsoft.AspNet.WebApi.Tracing**. - -4. In the search results, select the **Microsoft.AspNet.WebApi.Tracing** package, and then select **Install** to install the package. +1. Open the context menu (right-click) for the project, and select **Manage NuGet Packages**. +1. In the search box, enter **Microsoft.AspNet.WebApi.Tracing**. +1. In the search results, select the **Microsoft.AspNet.WebApi.Tracing** package, and then select **Install** to install the package. #### Build SPWebhookNotification model Each notification generated by the service is serialized into a **webhookNotification** instance. You need to build a simple model that represents this notification instance. 1. Go to **Solution Explorer** in Visual Studio. - -2. Open the context menu (right-click) for the **Models** folder, and select **Add** > **Class**. - -3. Enter **SPWebhookNotification** as the class name and select **Add** to add the class to your project. - -4. Add the following code to the body of the **SPWebhookNotification** class: - - ```cs - public string SubscriptionId { get; set; } - - public string ClientState { get; set; } - - public string ExpirationDateTime { get; set; } - - public string Resource { get; set; } - - public string TenantId { get; set; } - - public string SiteUrl { get; set; } - - public string WebId { get; set; } - ``` +1. Open the context menu (right-click) for the **Models** folder, and select **Add** > **Class**. +1. Enter **SPWebhookNotification** as the class name and select **Add** to add the class to your project. +1. Add the following code to the body of the **SPWebhookNotification** class: + + ```csharp + public string SubscriptionId { get; set; } + public string ClientState { get; set; } + public string ExpirationDateTime { get; set; } + public string Resource { get; set; } + public string TenantId { get; set; } + public string SiteUrl { get; set; } + public string WebId { get; set; } + ``` #### Build SPWebhookContent model Because multiple notifications can be submitted to your webhook receiver in a single request, they are combined together in an object with a single array value. Build a simple model that represents the array. 1. Go to **Solution Explorer** in Visual Studio. +1. Open the context menu (right-click) for the **Models** folder, and select **Add** > **Class**. +1. Enter **SPWebhookContent** as the class name, and select **Add** to add the class to your project. +1. Add the following code to the body of the **SPWebhookContent** class: -2. Open the context menu (right-click) for the **Models** folder, and select **Add** > **Class**. - -3. Enter **SPWebhookContent** as the class name, and select **Add** to add the class to your project. - -4. Add the following code to the body of the **SPWebhookContent** class: - - ```cs - public List Value { get; set; } - ``` + ```csharp + public List Value { get; set; } + ``` #### Add SharePoint webhook client state -Webhooks provide the ability to use an optional string value that is passed back in the notification message for your subscription. This can be used to verify that the request is indeed coming from the source you trust, which in this case is SharePoint. +Webhooks provide the ability to use an optional string value that is passed back in the notification message for your subscription. This can be used to verify that the request is indeed coming from the source you trust, which in this case is SharePoint. Add a client state value with which the application can verify the incoming requests. 1. Go to **Solution Explorer** in Visual Studio. +1. Open the **web.config** file, and add the following key as the client state to the `` section: -2. Open the **web.config** file, and add the following key as the client state to the `` section: - - ```xml - - ``` + ```xml + + ``` #### Enable tracing @@ -157,162 +128,152 @@ In the **web.config** file, enable tracing by adding the following key inside th A trace writer is required, so you must add a trace writer to the controller configuration (in this case use the one from **System.Diagnostics**). 1. Go to **Solution Explorer** in Visual Studio. +1. Open **WebApiConfig.cs** in the **App_Start** folder. +1. Add the following line inside the **Register** method: -2. Open **WebApiConfig.cs** in the **App_Start** folder. - -3. Add the following line inside the **Register** method: - - ```cs - config.EnableSystemDiagnosticsTracing(); - ``` + ```csharp + config.EnableSystemDiagnosticsTracing(); + ``` #### Build SharePoint webhook controller Now build the webhook receiver controller that handles the incoming requests from SharePoint and take action accordingly. 1. Go to **Solution Explorer** in Visual Studio. - -2. Open the context menu (right-click) for the **Controllers** folder, and select **Add** > **Controller**. - -3. In the **Add Scaffold** dialog, select **Web API 2 Controller - Empty**. - -4. Select **Add**. - -5. Name the controller **SPWebhookController**, and select **Add** to add the API controller to your project. - -6. Replace the `using` statements with the following code: - - ```cs - using Newtonsoft.Json; - using SPWebhooksReceiver.Models; - using System.Collections.Generic; - using System.Configuration; - using System.Linq; - using System.Net; - using System.Net.Http; - using System.Threading.Tasks; - using System.Web; - using System.Web.Http; - using System.Web.Http.Tracing; - ``` - -7. Replace the code in the **SPWebhookController** class with the following code: - - ```cs - [HttpPost] - public HttpResponseMessage HandleRequest() - { - HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.BadRequest); - var traceWriter = Configuration.Services.GetTraceWriter(); - string validationToken = string.Empty; - IEnumerable clientStateHeader = new List(); - string webhookClientState = ConfigurationManager.AppSettings["webhookclientstate"].ToString(); - - if (Request.Headers.TryGetValues("ClientState", out clientStateHeader)) - { - string clientStateHeaderValue = clientStateHeader.FirstOrDefault() ?? string.Empty; - - if (!string.IsNullOrEmpty(clientStateHeaderValue) && clientStateHeaderValue.Equals(webhookClientState)) - { - traceWriter.Trace(Request, "SPWebhooks", - TraceLevel.Info, - string.Format("Received client state: {0}", clientStateHeaderValue)); - - var queryStringParams = HttpUtility.ParseQueryString(Request.RequestUri.Query); - - if (queryStringParams.AllKeys.Contains("validationtoken")) - { - httpResponse = new HttpResponseMessage(HttpStatusCode.OK); - validationToken = queryStringParams.GetValues("validationtoken")[0].ToString(); - httpResponse.Content = new StringContent(validationToken); - - traceWriter.Trace(Request, "SPWebhooks", - TraceLevel.Info, - string.Format("Received validation token: {0}", validationToken)); - return httpResponse; - } - else - { - var requestContent = Request.Content.ReadAsStringAsync().Result; - - if (!string.IsNullOrEmpty(requestContent)) - { - SPWebhookNotification notification = null; - - try - { - var objNotification = JsonConvert.DeserializeObject(requestContent); - notification = objNotification.Value[0]; - } - catch (JsonException ex) - { - traceWriter.Trace(Request, "SPWebhooks", - TraceLevel.Error, - string.Format("JSON deserialization error: {0}", ex.InnerException)); - return httpResponse; - } - - if (notification != null) - { - Task.Factory.StartNew(() => - { - //handle the notification here - //you can send this to an Azure queue to be processed later - //for this sample, we just log to the trace - - traceWriter.Trace(Request, "SPWebhook Notification", - TraceLevel.Info, string.Format("Resource: {0}", notification.Resource)); - traceWriter.Trace(Request, "SPWebhook Notification", - TraceLevel.Info, string.Format("SubscriptionId: {0}", notification.SubscriptionId)); - traceWriter.Trace(Request, "SPWebhook Notification", - TraceLevel.Info, string.Format("TenantId: {0}", notification.TenantId)); - traceWriter.Trace(Request, "SPWebhook Notification", - TraceLevel.Info, string.Format("SiteUrl: {0}", notification.SiteUrl)); - traceWriter.Trace(Request, "SPWebhook Notification", - TraceLevel.Info, string.Format("WebId: {0}", notification.WebId)); - traceWriter.Trace(Request, "SPWebhook Notification", - TraceLevel.Info, string.Format("ExpirationDateTime: {0}", notification.ExpirationDateTime)); - - }); - - httpResponse = new HttpResponseMessage(HttpStatusCode.OK); - } - } - } - } - else - { - httpResponse = new HttpResponseMessage(HttpStatusCode.Forbidden); - } - } - - return httpResponse; - } - ``` - -8. Save the file. +1. Open the context menu (right-click) for the **Controllers** folder, and select **Add** > **Controller**. +1. In the **Add Scaffold** dialog, select **Web API 2 Controller - Empty**. +1. Select **Add**. +1. Name the controller **SPWebhookController**, and select **Add** to add the API controller to your project. +1. Replace the `using` statements with the following code: + + ```csharp + using Newtonsoft.Json; + using SPWebhooksReceiver.Models; + using System.Collections.Generic; + using System.Configuration; + using System.Linq; + using System.Net; + using System.Net.Http; + using System.Threading.Tasks; + using System.Web; + using System.Web.Http; + using System.Web.Http.Tracing; + ``` + +1. Replace the code in the **SPWebhookController** class with the following code: + + ```csharp + [HttpPost] + public HttpResponseMessage HandleRequest() + { + HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.BadRequest); + var traceWriter = Configuration.Services.GetTraceWriter(); + string validationToken = string.Empty; + IEnumerable clientStateHeader = new List(); + string webhookClientState = ConfigurationManager.AppSettings["webhookclientstate"].ToString(); + + if (Request.Headers.TryGetValues("ClientState", out clientStateHeader)) + { + string clientStateHeaderValue = clientStateHeader.FirstOrDefault() ?? string.Empty; + + if (!string.IsNullOrEmpty(clientStateHeaderValue) && clientStateHeaderValue.Equals(webhookClientState)) + { + traceWriter.Trace(Request, "SPWebhooks", + TraceLevel.Info, + string.Format("Received client state: {0}", clientStateHeaderValue)); + + var queryStringParams = HttpUtility.ParseQueryString(Request.RequestUri.Query); + + if (queryStringParams.AllKeys.Contains("validationtoken")) + { + httpResponse = new HttpResponseMessage(HttpStatusCode.OK); + validationToken = queryStringParams.GetValues("validationtoken")[0].ToString(); + httpResponse.Content = new StringContent(validationToken); + + traceWriter.Trace(Request, "SPWebhooks", + TraceLevel.Info, + string.Format("Received validation token: {0}", validationToken)); + return httpResponse; + } + else + { + var requestContent = Request.Content.ReadAsStringAsync().Result; + + if (!string.IsNullOrEmpty(requestContent)) + { + SPWebhookNotification notification = null; + + try + { + var objNotification = JsonConvert.DeserializeObject(requestContent); + notification = objNotification.Value[0]; + } + catch (JsonException ex) + { + traceWriter.Trace(Request, "SPWebhooks", + TraceLevel.Error, + string.Format("JSON deserialization error: {0}", ex.InnerException)); + return httpResponse; + } + + if (notification != null) + { + Task.Factory.StartNew(() => + { + //handle the notification here + //you can send this to an Azure queue to be processed later + //for this sample, we just log to the trace + + traceWriter.Trace(Request, "SPWebhook Notification", + TraceLevel.Info, string.Format("Resource: {0}", notification.Resource)); + traceWriter.Trace(Request, "SPWebhook Notification", + TraceLevel.Info, string.Format("SubscriptionId: {0}", notification.SubscriptionId)); + traceWriter.Trace(Request, "SPWebhook Notification", + TraceLevel.Info, string.Format("TenantId: {0}", notification.TenantId)); + traceWriter.Trace(Request, "SPWebhook Notification", + TraceLevel.Info, string.Format("SiteUrl: {0}", notification.SiteUrl)); + traceWriter.Trace(Request, "SPWebhook Notification", + TraceLevel.Info, string.Format("WebId: {0}", notification.WebId)); + traceWriter.Trace(Request, "SPWebhook Notification", + TraceLevel.Info, string.Format("ExpirationDateTime: {0}", notification.ExpirationDateTime)); + + }); + + httpResponse = new HttpResponseMessage(HttpStatusCode.OK); + } + } + } + } + else + { + httpResponse = new HttpResponseMessage(HttpStatusCode.Forbidden); + } + } + + return httpResponse; + } + ``` + +1. Save the file. ## Step 3: Debug the webhook receiver 1. Select **F5** to debug the webhook receiver. - -2. When you have the browser open, copy the port number from the address bar. For example: `http://localhost:<_port-number_>` +1. When you have the browser open, copy the port number from the address bar. For example: `http://localhost:<_port-number_>` ## Step 4: Run ngrok proxy 1. Open a console terminal. +1. Go to the extracted ngrok folder. +1. Enter the following with the port number URL from the previous step to start ngrok: -2. Go to the extracted ngrok folder. - -3. Enter the following with the port number URL from the previous step to start ngrok: + ``` + ./ngrok http port-number --host-header=localhost:port-number + ``` - ``` - ./ngrok http port-number --host-header=localhost:port-number - ``` + You should see ngrok running. - You should see ngrok running. - -4. Copy the **Forwarding** HTTPS address. You will use this address as the service proxy for SharePoint to send requests. +1. Copy the **Forwarding** HTTPS address. You will use this address as the service proxy for SharePoint to send requests. ## Step 5: Add webhook subscription using Postman @@ -321,15 +282,12 @@ Now build the webhook receiver controller that handles the incoming requests fro Postman makes it really simple to work with APIs. The first step is to configure Postman to authenticate with Azure AD so you can send API requests to SharePoint. You will use the Azure AD app that you registered in Step 1. 1. Open Postman. You are presented with a **Sidebar** and **Request Editor**. +1. Select the **Authorization** tab in the **Request Editor**. +1. Select **OAuth 2.0** in the **Type** list. +1. Select the **Get New Access Token** button. +1. In the dialog window, enter the following: -2. Select the **Authorization** tab in the **Request Editor**. - -3. Select **OAuth 2.0** in the **Type** list. - -4. Select the **Get New Access Token** button. - -5. In the dialog window, enter the following: - * **Auth URL**: + * **Auth URL**: * `https://login.microsoftonline.com/common/oauth2/authorize?resource=https%3A%2F%2F<_your-sharepoint-tenant-url-without-https_>` * Replace `your-sharepoint-tenant-url-without-https` with your tenant url without the **https** prefix. * **Access Token URL**: `https://login.microsoftonline.com/common/oauth2/token` @@ -338,15 +296,12 @@ Postman makes it really simple to work with APIs. The first step is to configure * **Token name**: sp_webhooks_token * **Grant type**: Authorization Code -6. Select the **Request Token** to sign in, consent, and get the token for the session. - -7. When the token is successfully retrieved, you should see **access\_token** variable added to the **Authorization** tab. - -8. Select the option to **Add token to header**. - -9. Double-click the **access\_token** variable to add the token to the header for the request. +1. Select the **Request Token** to sign in, consent, and get the token for the session. +1. When the token is successfully retrieved, you should see **access\_token** variable added to the **Authorization** tab. +1. Select the option to **Add token to header**. +1. Double-click the **access\_token** variable to add the token to the header for the request. - ![Postman get new access token](../../images/postman-get-new-access-token.png) + ![Postman get new access token](../../images/postman-get-new-access-token.png) ### Get Documents list Id @@ -354,174 +309,158 @@ You need to manage webhooks for the default document library, which is provision 1. Enter the following request URL: - ``` - https://site-collection/_api/web/lists/getbytitle('Documents')?$select=Title,Id - ``` + ```http + https://site-collection/_api/web/lists/getbytitle('Documents')?$select=Title,Id + ``` -2. Replace _site-collection_ with your site collection. - - Postman executes your request and if successful, you should see the result. +1. Replace _site-collection_ with your site collection. -3. Copy the **Id** from the results. Later you will use the **Id** to make webhook requests. + Postman executes your request and if successful, you should see the result. + +1. Copy the **Id** from the results. Later you will use the **Id** to make webhook requests. ### Add webhook subscription Now that you have the required information, construct the query and the request to add a webhook subscription. Use the request editor for the following steps: 1. Change the request to **POST** from **GET**. - -2. Enter the following as the request URL: - - ``` - https://site-collection/_api/web/lists('list-id')/subscriptions - ``` - -3. Replace _site-collection_ with your site collection. - -4. Go to the **Headers** tab. - -5. Make sure you still have the **Authorization** header. If not, you need to request a new access token. - -6. Add the following header **key** > **value** pairs: - * Accept > application/json;odata=nometadata - * Content-Type > application/json - -7. Go to the **Body** tab and select **raw** format. - -8. Paste the following JSON as the body: - - ```json - { - "resource": "https://site-collection/_api/web/lists('list-id')", - "notificationUrl": "https://ngrok-forwarding-address/api/spwebhook/handlerequest", - "expirationDateTime": "2016-10-27T16:17:57+00:00", - "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449" - } - ``` - -
- - ![postman add webhook body](../../images/postman-add-webhook-body.png) - -9. Make sure the **expirationDateTime** is at most 6 months from today. - -10. Make sure you are debugging the webhook receiver as in Step 4. - -11. Select **Send** to execute the request. - - If the request is successful, you should see the response from SharePoint that provides the subscription details. The following example shows a response for a newly created subscription: - - ```json - { - "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449", - "expirationDateTime": "2016-10-27T16:17:57Z", - "id": "32b95d9-4d20-4a17-bfa3-2957cb38ead8", - "notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest", - "resource": "c34420f9-2ad7-4e54-94c9-b67798d2299b" - } - ``` - -12. Copy the subscription **id**. You will need it for the next set of requests. - -13. Go to the webhook receiver project in Visual Studio and examine the **Output** window. You should see the trace logs that look similar to the following trace, along with other messages: - - ``` - iisexpress.exe Information: 0 : Message='Received client state: A0A354EC-97D4-4D83-9DDB-144077ADB449' - iisexpress.exe Information: 0 : Message='Received validation token: daf2803c-43cf-44c7-8dff-7066eaa40f13' - ``` - - The trace indicates that the webhook received initially received a validation request. If you look at the code, you'll see that it returns the validation token immediately so that SharePoint can validate the request: - - ```cs - if (queryStringParams.AllKeys.Contains("validationtoken")) - { - httpResponse = new HttpResponseMessage(HttpStatusCode.OK); - validationToken = queryStringParams.GetValues("validationtoken")[0].ToString(); - httpResponse.Content = new StringContent(validationToken); - - traceWriter.Trace(Request, "SPWebhooks", - TraceLevel.Info, - string.Format("Received validation token: {0}", validationToken)); - return httpResponse; - } - ``` +1. Enter the following as the request URL: + + ```http + https://site-collection/_api/web/lists('list-id')/subscriptions + ``` + +1. Replace _site-collection_ with your site collection. +1. Go to the **Headers** tab. +1. Make sure you still have the **Authorization** header. If not, you need to request a new access token. +1. Add the following header **key** > **value** pairs: + + * **Accept**: `application/json;odata=nometadata` + * **Content-Type**: `application/json` + +1. Go to the **Body** tab and select **raw** format. +1. Paste the following JSON as the body: + + ```json + { + "resource": "https://site-collection/_api/web/lists('list-id')", + "notificationUrl": "https://ngrok-forwarding-address/api/spwebhook/handlerequest", + "expirationDateTime": "2016-10-27T16:17:57+00:00", + "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449" + } + ``` + + ![postman add webhook body](../../images/postman-add-webhook-body.png) + +1. Make sure the **expirationDateTime** is at most 6 months from today. +1. Make sure you are debugging the webhook receiver as in Step 4. +1. Select **Send** to execute the request. + + If the request is successful, you should see the response from SharePoint that provides the subscription details. The following example shows a response for a newly created subscription: + + ```json + { + "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449", + "expirationDateTime": "2016-10-27T16:17:57Z", + "id": "32b95d9-4d20-4a17-bfa3-2957cb38ead8", + "notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest", + "resource": "c34420f9-2ad7-4e54-94c9-b67798d2299b" + } + ``` + +1. Copy the subscription **id**. You will need it for the next set of requests. +1. Go to the webhook receiver project in Visual Studio and examine the **Output** window. You should see the trace logs that look similar to the following trace, along with other messages: + + ```console + iisexpress.exe Information: 0 : Message='Received client state: A0A354EC-97D4-4D83-9DDB-144077ADB449' + iisexpress.exe Information: 0 : Message='Received validation token: daf2803c-43cf-44c7-8dff-7066eaa40f13' + ``` + + The trace indicates that the webhook received initially received a validation request. If you look at the code, you'll see that it returns the validation token immediately so that SharePoint can validate the request: + + ```csharp + if (queryStringParams.AllKeys.Contains("validationtoken")) + { + httpResponse = new HttpResponseMessage(HttpStatusCode.OK); + validationToken = queryStringParams.GetValues("validationtoken")[0].ToString(); + httpResponse.Content = new StringContent(validationToken); + + traceWriter.Trace(Request, "SPWebhooks", + TraceLevel.Info, + string.Format("Received validation token: {0}", validationToken)); + return httpResponse; + } + ``` ## Step 6: Get subscription details Now you'll run queries in Postman to get the subscription details. 1. Open the Postman client. +1. Change the request to **GET** from **POST**. +1. Enter the following as the request: -2. Change the request to **GET** from **POST**. - -3. Enter the following as the request: - - ``` - https://site-collection/_api/web/lists('list-id')/subscriptions - ``` - -4. Replace _site-collection_ with your site collection. + ```http + https://site-collection/_api/web/lists('list-id')/subscriptions + ``` -5. Select **Send** to execute the request. +1. Replace _site-collection_ with your site collection. +1. Select **Send** to execute the request. - If successful, you should see SharePoint return the subscriptions for this list resource. Because we just added one, you should at least see one subscription returned. The following example shows a response with one subscription: + If successful, you should see SharePoint return the subscriptions for this list resource. Because we just added one, you should at least see one subscription returned. The following example shows a response with one subscription: - ```json - { - "value": [ - { - "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449", - "expirationDateTime": "2016-10-27T16:17:57Z", - "id": "32b95add-4d20-4a17-bfa3-2957cb38ead8", - "notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest", - "resource": "c34420f9-2a67-4e54-94c9-b67798229f9b" - } - ] - } - ``` + ```json + { + "value": [ + { + "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449", + "expirationDateTime": "2016-10-27T16:17:57Z", + "id": "32b95add-4d20-4a17-bfa3-2957cb38ead8", + "notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest", + "resource": "c34420f9-2a67-4e54-94c9-b67798229f9b" + } + ] + } + ``` -6. Run the following query to get details of the specific subscription: +1. Run the following query to get details of the specific subscription: - ``` - https://site-collection/_api/web/lists('list-id')/subscriptions('subscription-id') - ``` + ```http + https://site-collection/_api/web/lists('list-id')/subscriptions('subscription-id') + ``` -7. Replace `subscription-id` with your subscription id. +1. Replace `subscription-id` with your subscription id. ## Step 7: Test webhook notification Now add a file to the Documents library and test if you get a notification from SharePoint in the webhook receiver. 1. Go to Visual Studio. +1. In the **SPWebhookController**, place a breakpoint on the following line of code: -2. In the **SPWebhookController**, place a breakpoint on the following line of code: - - ```cs - var requestContent = Request.Content.ReadAsStringAsync().Result; - ``` - -3. Go to the **Documents** library. It is named **Shared Documents** library in your default site collection. - -4. Add a new file. - -5. Go to Visual Studio and wait for the breakpoint to be hit. + ```csharp + var requestContent = Request.Content.ReadAsStringAsync().Result; + ``` - The wait time may vary from a few seconds to up to five minutes. When the breakpoint is hit, the webhook receiver has just received a notification from SharePoint. +1. Go to the **Documents** library. It is named **Shared Documents** library in your default site collection. +1. Add a new file. +1. Go to Visual Studio and wait for the breakpoint to be hit. -6. Select **F5** to continue. + The wait time may vary from a few seconds to up to five minutes. When the breakpoint is hit, the webhook receiver has just received a notification from SharePoint. -7. To see the notification data, look in the **Output** window for the following entries, since you added the notification data into the trace log: +1. Select **F5** to continue. +1. To see the notification data, look in the **Output** window for the following entries, since you added the notification data into the trace log: - ``` - iisexpress.exe Information: 0 : Message='Resource: c34420f9-2a67-4e54-94c9-b6770892299b' - iisexpress.exe Information: 0 : Message='SubscriptionId: 32b95ad9-4d20-4a17-bfa3-2957cb38ead8' - iisexpress.exe Information: 0 : Message='TenantId: 7a17cb7d-6898-423f-8839-45f363076f06' - iisexpress.exe Information: 0 : Message='SiteUrl: /' - iisexpress.exe Information: 0 : Message='WebId: 62b80e0b-f889-4974-a519-cc138413be40' - iisexpress.exe Information: 0 : Message='ExpirationDateTime: 2016-10-27T16:17:57.0000000Z' - ``` + ```console + iisexpress.exe Information: 0 : Message='Resource: c34420f9-2a67-4e54-94c9-b6770892299b' + iisexpress.exe Information: 0 : Message='SubscriptionId: 32b95ad9-4d20-4a17-bfa3-2957cb38ead8' + iisexpress.exe Information: 0 : Message='TenantId: 7a17cb7d-6898-423f-8839-45f363076f06' + iisexpress.exe Information: 0 : Message='SiteUrl: /' + iisexpress.exe Information: 0 : Message='WebId: 62b80e0b-f889-4974-a519-cc138413be40' + iisexpress.exe Information: 0 : Message='ExpirationDateTime: 2016-10-27T16:17:57.0000000Z' + ``` -This project only writes the information to the trace log. However, in your receiver, you send this information into a table or a queue that can process the received data to get information from SharePoint. +This project only writes the information to the trace log. However, in your receiver, you send this information into a table or a queue that can process the received data to get information from SharePoint. With this data, you can construct the URL and use the [GetChanges](https://msdn.microsoft.com/library/office/dn531433.aspx#bk_ListGetChanges) API to get the latest changes. diff --git a/docs/apis/webhooks/lists/create-subscription.md b/docs/apis/webhooks/lists/create-subscription.md index 065537129..bab6f9320 100644 --- a/docs/apis/webhooks/lists/create-subscription.md +++ b/docs/apis/webhooks/lists/create-subscription.md @@ -1,15 +1,12 @@ --- title: Create a new subscription description: Creates a new webhook subscription on a SharePoint list. -ms.date: 02/08/2018 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 10/20/2020 +ms.localizationpriority: high --- +# Create a new subscription - -# Create a new subscription - -Creates a new webhook subscription on a SharePoint list. +Creates a new webhook subscription on a SharePoint list. ## Permissions @@ -19,7 +16,7 @@ The application must have at least edit permissions to the SharePoint list where You must grant the Azure AD app the permissions specified in the following table: -Application | Permission +Application | Permission ------------|------------ Office 365 SharePoint Online|Read and write items and lists in all site collections. @@ -27,13 +24,13 @@ Office 365 SharePoint Online|Read and write items and lists in all site collecti You must grant the SharePoint Add-in the following permission(s) or higher: -Scope | Permission rights +Scope | Permission rights ------|------------ List|Manage ## HTTP request -``` +```http POST /_api/web/lists('list-id')/subscriptions ``` @@ -41,7 +38,7 @@ POST /_api/web/lists('list-id')/subscriptions Include the following properties in the request body. -Name | Type | Description +Name | Type | Description -----|------|------------ resource|string|The URL of the list to receive notifications from. notificationUrl|string|The service URL to send notifications to. @@ -75,7 +72,7 @@ Content-Type: application/json { "id": "a8e6d5e6-9f7f-497a-b97f-8ffe8f559dc7", - "expirationDateTime": "2016-04-27T16:17:57Z", + "expirationDateTime": "2016-04-27T16:17:57Z", "notificationUrl": "https://91e383a5.ngrok.io/api/webhook/handlerequest", "resource": "5c77031a-9621-4dfc-bb5d-57803a94e91d" } @@ -83,9 +80,16 @@ Content-Type: application/json ## URL validation -Before a new subscription is created, SharePoint sends a request with a validation token in the body of the request to the service URL provided. Your service must respond to this request by returning the validation token. +> [!IMPORTANT] +> Before a new subscription is created, SharePoint sends a request with a validation token in the querystring of the request to the notification URL provided. Your service must respond to this request by returning the validation token. If your service fails to validate the request in this way, the subscription is not created.** -If your service fails to validate the request in this way, the subscription is not created. +### Example + +```csharp +{ + return new OkObjectResult(req.Query["validationtoken"].ToString()); +} +``` ## See also diff --git a/docs/apis/webhooks/lists/delete-subscription.md b/docs/apis/webhooks/lists/delete-subscription.md index 5d60d8a5b..397d90237 100644 --- a/docs/apis/webhooks/lists/delete-subscription.md +++ b/docs/apis/webhooks/lists/delete-subscription.md @@ -1,12 +1,9 @@ --- title: Delete a subscription description: Deletes a webhook subscription from a SharePoint list. After deleting the subscription, notifications are no longer delivered. -ms.date: 02/08/2018 -ms.prod: sharepoint -localization_priority: Normal +ms.date: 09/23/2022 +ms.localizationpriority: medium --- - - # Delete a subscription Deletes a webhook subscription from a SharePoint list. After deleting the subscription, notifications are no longer delivered. @@ -19,7 +16,7 @@ The application must have at least edit permissions to the SharePoint list where You must grant the Azure AD app the permissions specified in the following table. A subscription can only be deleted by the Azure AD application that created it. -Application | Permission +Application | Permission ------------|------------ Office 365 SharePoint Online|Read and write items and lists in all site collections. @@ -27,7 +24,7 @@ Office 365 SharePoint Online|Read and write items and lists in all site collecti You must grant the SharePoint Add-in the following permission(s) or higher. A subscription can only be deleted by the SharePoint Add-in that created it. -Scope | Permission rights +Scope | Permission rights ------|------------ List|Manage diff --git a/docs/apis/webhooks/lists/get-subscription.md b/docs/apis/webhooks/lists/get-subscription.md index bb0f36b52..661e9076e 100644 --- a/docs/apis/webhooks/lists/get-subscription.md +++ b/docs/apis/webhooks/lists/get-subscription.md @@ -1,12 +1,9 @@ --- title: Get subscriptions description: Gets one or more webhook subscriptions on a SharePoint list. -ms.date: 02/08/2018 -ms.prod: sharepoint -localization_priority: Normal +ms.date: 09/23/2022 +ms.localizationpriority: medium --- - - # Get subscriptions Gets one or more webhook subscriptions on a SharePoint list. @@ -19,17 +16,17 @@ The application must have at least edit permissions to the SharePoint list where #### If your application is a Microsoft Azure Active Directory (Azure AD) application -You must grant the Azure AD application the permissions specified in the following table. A subscription can only be retrieved by the Azure AD application that created it. +You must grant the Azure AD application the permissions specified in the following table. A subscription can only be retrieved by the Azure AD application that created it. -Application | Permission +Application | Permission ------------|------------ Office 365 SharePoint Online|Read and write items and lists in all site collections. #### If your application is a SharePoint Add-in -You must grant the SharePoint Add-in the following permission(s) or higher. A subscription can only be retrieved by the SharePoint Add-in that created it. +You must grant the SharePoint Add-in the following permission(s) or higher. A subscription can only be retrieved by the SharePoint Add-in that created it. -Scope | Permission rights +Scope | Permission rights ------|------------ List|Manage @@ -39,17 +36,17 @@ The application must have manage list permissions to the SharePoint list where t #### If your application is an Azure AD application -You must grant the Azure AD app the permissions specified in the following table. +You must grant the Azure AD app the permissions specified in the following table. -Application | Permission +Application | Permission ------------|------------ Office 365 SharePoint Online|Have full control of all site collections. #### If your application is a SharePoint Add-in -You must grant the SharePoint Add-in the following permission(s) or higher. +You must grant the SharePoint Add-in the following permission(s) or higher. -Scope | Permission rights +Scope | Permission rights ------|------------ List|Full control @@ -111,7 +108,7 @@ Do not supply a request body for this method. #### Response -This returns a collection of all subscriptions on a SharePoint resource. +This returns a collection of all subscriptions on a SharePoint resource. ```http HTTP/1.1 200 OK diff --git a/docs/apis/webhooks/lists/overview-sharepoint-list-webhooks.md b/docs/apis/webhooks/lists/overview-sharepoint-list-webhooks.md index 0aeab4115..f8d775112 100644 --- a/docs/apis/webhooks/lists/overview-sharepoint-list-webhooks.md +++ b/docs/apis/webhooks/lists/overview-sharepoint-list-webhooks.md @@ -1,19 +1,16 @@ --- title: SharePoint list webhooks description: List webhooks cover the events corresponding to list item changes for a given SharePoint list or a document library. -ms.date: 02/08/2018 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 09/23/2022 +ms.localizationpriority: high --- - - # SharePoint list webhooks The SharePoint list webhooks cover the events corresponding to list item changes for a given SharePoint list or a document library. SharePoint webhooks provide a simple notification pipeline so your application can be aware of changes to a SharePoint list without polling the service. ## Tasks -| Task | HTTP method | +| Task | HTTP method | |-----------------------------------------------------|--------------------------------------------------------| | [Create a new subscription](./create-subscription.md) | `POST /_api/web/lists('list-guid')/subscriptions` | | [Get subscriptions](./get-subscription.md) | `GET /_api/web/lists('list-guid')/subscriptions` | diff --git a/docs/apis/webhooks/lists/update-subscription.md b/docs/apis/webhooks/lists/update-subscription.md index 2b1673568..6ba4aa7a7 100644 --- a/docs/apis/webhooks/lists/update-subscription.md +++ b/docs/apis/webhooks/lists/update-subscription.md @@ -1,33 +1,30 @@ --- title: Update a subscription description: Updates a webhook subscription on a SharePoint list. -ms.date: 02/08/2018 -ms.prod: sharepoint -localization_priority: Normal +ms.date: 09/23/2022 +ms.localizationpriority: medium --- - - # Update a subscription Updates a webhook subscription on a SharePoint list. ## Permissions -The application must have at least edit permissions to the SharePoint list where the subscription will be updated. +The application must have at least edit permissions to the SharePoint list where the subscription will be updated. ### If your application is a Microsoft Azure Active Directory (Azure AD) application You must grant the Azure AD application the permissions specified in the following table. A subscription can only be updated by the Azure AD application that created it. -Application | Permission +Application | Permission ------------|------------ -Office 365 SharePoint Online|Read and write items and lists in all site collections. +Office 365 SharePoint Online|Read and write items and lists in all site collections. ### If your application is a SharePoint Add-in You must grant the SharePoint Add-in the following permission(s) or higher. A subscription can only be updated by the SharePoint Add-in that created it. -Scope | Permission rights +Scope | Permission rights ------|------------ List|Manage @@ -53,11 +50,11 @@ Content-Type: application/json Include the following properties in the request body. -Name | Type | Description +Name | Type | Description -----|------|------------ notificationUrl|string|The service URL to send notifications to. expirationDateTime|date|The date the notification will expire and be deleted. -client-clientState|string|Optional. Opaque string passed back to the client on all notifications.
You can use this for validating notifications or tagging different subscriptions. +clientState|string|Optional. Opaque string passed back to the client on all notifications.
You can use this for validating notifications or tagging different subscriptions. ## Response diff --git a/docs/apis/webhooks/overview-sharepoint-webhooks.md b/docs/apis/webhooks/overview-sharepoint-webhooks.md index ef2ba04a2..190a3a4ea 100644 --- a/docs/apis/webhooks/overview-sharepoint-webhooks.md +++ b/docs/apis/webhooks/overview-sharepoint-webhooks.md @@ -1,27 +1,24 @@ --- title: Overview of SharePoint webhooks description: Build applications that subscribe to receive notifications on specific events that occur in SharePoint. -ms.date: 02/08/2018 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 09/23/2022 +ms.localizationpriority: high --- - - # Overview of SharePoint webhooks SharePoint webhooks enable developers to build applications that subscribe to receive notifications on specific events that occur in SharePoint. When an event is triggered, SharePoint sends an HTTP POST payload to the subscriber. Webhooks are easier to develop and consume than Windows Communication Foundation (WCF) services used by SharePoint Add-in remote event receivers because webhooks are regular HTTP services (web API). -Currently webhooks are only enabled for SharePoint list items. SharePoint list item webhooks cover the events corresponding to list item changes for a given SharePoint list or a document library. SharePoint webhooks provide a simple notification pipeline so that your application can be aware of changes to a SharePoint list without polling the service. For more information, see [SharePoint list webhooks](./lists/overview-sharepoint-list-webhooks.md). +Currently webhooks are only enabled for SharePoint list items. SharePoint list item webhooks cover the events corresponding to list item changes for a given SharePoint list or a document library. SharePoint webhooks provide a simple notification pipeline so that your application can be aware of changes to a SharePoint list without polling the service. For more information, see [SharePoint list webhooks](./lists/overview-sharepoint-list-webhooks.md). ## Creating webhooks -To create a new SharePoint webhook, you add a new subscription to the specific SharePoint resource, such as a SharePoint list. +To create a new SharePoint webhook, you add a new subscription to the specific SharePoint resource, such as a SharePoint list. The following information is required for creating a new subscription: - **Resource**. The resource endpoint URL you are creating the subscription for. For example, a SharePoint List API URL. - **Server notification URL**. Your service endpoint URL. SharePoint sends an HTTP POST to this endpoint when events occur in the specified resource. -- **Expiration date**. The expiration date for your subscription. The expiration date should not be more than 180 days. By default, subscriptions are set to expire 180 days from when they are created. +- **Expiration date**. The expiration date for your subscription. The expiration date should not be more than 180 days. By default, subscriptions are set to expire 180 days from when they are created. You can also include the following information if needed: @@ -145,9 +142,9 @@ If an error occurs while sending the notification to your application, SharePoin ## Expiration -Webhook subscriptions are set to expire after 180 days by default if an **expirationDateTime** value is not specified. +Webhook subscriptions are set to expire after 180 days by default if an **expirationDateTime** value is not specified. -You need to set an expiration date when creating the subscription. The expiration date should be less than 180 days. Your application is expected to handle the expiration date according to your application's needs by updating the subscription periodically. +You need to set an expiration date when creating the subscription. The expiration date should be less than 180 days. Your application is expected to handle the expiration date according to your application's needs by updating the subscription periodically. ## Retry mechanism diff --git a/docs/apis/webhooks/sharepoint-webhooks-using-azd-template.md b/docs/apis/webhooks/sharepoint-webhooks-using-azd-template.md new file mode 100644 index 000000000..1de5d665e --- /dev/null +++ b/docs/apis/webhooks/sharepoint-webhooks-using-azd-template.md @@ -0,0 +1,178 @@ +--- +title: Create Azure Functions for SharePoint webhooks using an azd template +description: Use Azure Developer cli (azd) to deploy an Azure function app that connects to your SharePoint Online + tenant, to register and manage webhooks, and process the notifications from SharePoint. +ms.date: 07/07/2025 +ms.localizationpriority: low +--- +# Azure Functions for SharePoint webhooks using azd + +[Azure Developer CLI (azd)](https://aka.ms/azd) is an open-source tool that accelerates provisioning and deploying app resources in Azure. + +This article uses the [Azure function app for SharePoint webhooks public template](https://github.com/Azure-Samples/azd-functions-sharepoint-webhooks) to deploy an Azure function app that connects to your SharePoint Online tenant, to register and manage [webhooks](overview-sharepoint-webhooks.md), and process the notifications from SharePoint. + +## Prerequisites + +- [Node.js 22](https://www.nodejs.org/) +- [Azure Functions Core Tools](/azure/azure-functions/functions-run-local) +- [Azure Developer CLI (azd)](/azure/developer/azure-developer-cli/install-azd) +- An Azure subscription that trusts the same Microsoft Entra ID directory as the SharePoint tenant + +## Permissions required to provision the resources in Azure + +The account running **azd** must have at least the following roles to successfully provision the resources: + +- Azure role **[Contributor](/azure/role-based-access-control/built-in-roles/privileged#contributor)**: To create all the resources needed +- Azure role **[Role Based Access Control Administrator](/azure/role-based-access-control/built-in-roles/privileged#role-based-access-control-administrator)**: To assign roles (to access the storage account and Application Insights) to the managed identity of the function app + +## Deploy the function app in Azure + +1. Run **azd init** from an empty local (root) folder: + + ```console + azd init --template azd-functions-sharepoint-webhooks + ``` + + Enter an environment name, such as **spofuncs-quickstart** when prompted. In **azd**, the environment is used to maintain a unique deployment context for your app. + +1. Open the file **infra/main.parameters.json**, and set the variables `TenantPrefix` and `siteRelativePath` to match your SharePoint tenant. + + Review the article on [Manage environment variables](/azure/developer/azure-developer-cli/manage-environment-variables) to manage the azd's environment variables. + +1. Finally, run the command **azd up** to build the app, provision the resources in Azure and deploy the app package. + +## Grant the function app access to SharePoint Online + +The authentication to SharePoint is done using `DefaultAzureCredential`, so the credential used depends on whether the function app runs locally, or in Azure. + +If you never heard about `DefaultAzureCredential`, you should familiarize yourself with its concept by referring to the section **Use DefaultAzureCredential for flexibility** in [Credential chains in the Azure Identity client library for JavaScript](/azure/developer/javascript/sdk/authentication/credential-chains). + +### Using its managed identity + +`DefaultAzureCredential` will use a managed identity to authenticate to SharePoint. This may be the existing, system-assigned managed identity of the function app service or a user-assigned managed identity. + +This tutorial assumes the system-assigned managed identity is used. + +#### Grant the SharePoint API permission Sites.Selected to the managed identity + +Navigate to your function app in the [Azure portal](https://portal.azure.com/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.Web%2Fsites/kind/functionapp) > select **Identity** and note the **Object (principal) ID** of the system-assigned managed identity. + +> [!NOTE] +> In this tutorial, it is **d3e8dc41-94f2-4b0f-82ff-ed03c363f0f8**. + +Then, use one of the scripts below to grant this identity the app-only permission **Sites.Selected** on the SharePoint API: + +> [!IMPORTANT] +> The scripts below require at least the delegated permission [`AppRoleAssignment.ReadWrite.All`](/graph/permissions-reference#approleassignmentreadwriteall) (requires admin consent) + +
+ Using the Microsoft Graph PowerShell SDK + +```powershell +# This script requires the modules Microsoft.Graph.Authentication, Microsoft.Graph.Applications, Microsoft.Graph.Identity.SignIns, which can be installed with the cmdlet Install-Module below: +# Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Applications, Microsoft.Graph.Identity.SignIns -Scope CurrentUser -Repository PSGallery -Force +Connect-MgGraph -Scope "Application.Read.All", "AppRoleAssignment.ReadWrite.All" +$managedIdentityObjectId = "d3e8dc41-94f2-4b0f-82ff-ed03c363f0f8" # 'Object (principal) ID' of the managed identity +$scopeName = "Sites.Selected" +$resourceAppPrincipalObj = Get-MgServicePrincipal -Filter "displayName eq 'Office 365 SharePoint Online'" # SPO +$targetAppPrincipalAppRole = $resourceAppPrincipalObj.AppRoles | ? Value -eq $scopeName + +$appRoleAssignment = @{ + "principalId" = $managedIdentityObjectId + "resourceId" = $resourceAppPrincipalObj.Id + "appRoleId" = $targetAppPrincipalAppRole.Id +} +New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $managedIdentityObjectId -BodyParameter $appRoleAssignment | Format-List +``` +
+ +
+ Using az cli in Bash + +```bash +managedIdentityObjectId="d3e8dc41-94f2-4b0f-82ff-ed03c363f0f8" # 'Object (principal) ID' of the managed identity +resourceServicePrincipalId=$(az ad sp list --query '[].[id]' --filter "displayName eq 'Office 365 SharePoint Online'" -o tsv) +resourceServicePrincipalAppRoleId="$(az ad sp show --id $resourceServicePrincipalId --query "appRoles[?starts_with(value, 'Sites.Selected')].[id]" -o tsv)" + +az rest --method POST --uri "https://graph.microsoft.com/v1.0/servicePrincipals/${managedIdentityObjectId}/appRoleAssignments" --headers 'Content-Type=application/json' --body "{ 'principalId': '${managedIdentityObjectId}', 'resourceId': '${resourceServicePrincipalId}', 'appRoleId': '${resourceServicePrincipalAppRoleId}' }" +``` +
+ +#### Grant the managed identity effective access to a SharePoint site + +Navigate to the [Enterprise applications](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/StartboardApplicationsMenuBlade/) > Set the **Application type** filter to **Managed Identities** > select your managed identity and note its **Application ID**. + +> [!NOTE] +> In this tutorial, it is **3150363e-afbe-421f-9785-9d5404c5ae34**. + +Then, use one of the scripts below to grant it the app-only permission **manage** (minimum required to register a webhook) on a specific SharePoint site: + +> [!IMPORTANT] +> The app registration used to run those scripts must have at least the following permissions: +> +> - Delegated permission **Application.ReadWrite.All** in the Graph API (requires admin consent) +> - Delegated permission **AllSites.FullControl** in the SharePoint API (requires admin consent) + +
+ Using PnP PowerShell + +[PnP PowerShell](https://pnp.github.io/powershell/cmdlets/Grant-PnPAzureADAppSitePermission.html) + +```powershell +Connect-PnPOnline -Url "https://YOUR_SHAREPOINT_TENANT_PREFIX.sharepoint.com/sites/YOUR_SHAREPOINT_SITE_NAME" -Interactive -ClientId "YOUR_PNP_APP_CLIENT_ID" +Grant-PnPAzureADAppSitePermission -AppId "3150363e-afbe-421f-9785-9d5404c5ae34" -DisplayName "YOUR_FUNC_APP_NAME" -Permissions Manage +``` +
+ +
+ Using m365 cli in Bash + +[m365 cli](https://pnp.github.io/cli-microsoft365/cmd/spo/site/site-apppermission-add/) + +```bash +targetapp="3150363e-afbe-421f-9785-9d5404c5ae34" +siteUrl="https://YOUR_SHAREPOINT_TENANT_PREFIX.sharepoint.com/sites/YOUR_SHAREPOINT_SITE_NAME" +m365 spo site apppermission add --appId $targetapp --permission manage --siteUrl $siteUrl +``` +
+ +## Call the function app + +For security reasons, when running in Azure, the function app requires an app key to pass in the query string parameter **code**. The app keys are found in the function app service's **App Keys** keys page. + +Most HTTP functions take optional parameters `TenantPrefix` and `siteRelativePath`. If they are not specified, the values in the app's environment variables are used. + +Below is a sample script in PowerShell to call the function app: + +```powershell +# Edit those variables to match your environment +$funchost = "YOUR_FUNC_APP_NAME" +$code = "YOUR_HOST_KEY" +$listTitle = "YOUR_SHAREPOINT_LIST" +$notificationUrl = "https://${funchost}.azurewebsites.net/api/webhooks/service?code=${code}" + +# List all the webhooks registered on a list +Invoke-RestMethod -Method GET -Uri "https://${funchost}.azurewebsites.net/api/webhooks/list?code=${code}&listTitle=${listTitle}" + +# Register a webhook in a list +Invoke-RestMethod -Method POST -Uri "https://${funchost}.azurewebsites.net/api/webhooks/register?code=${code}&listTitle=${listTitle}¬ificationUrl=${notificationUrl}" + +# Show this webhook registered on a list +Invoke-RestMethod -Method GET -Uri "https://${funchost}.azurewebsites.net/api/webhooks/show?code=${code}&listTitle=${listTitle}¬ificationUrl=${notificationUrl}" + +# Remove the webhook from a list +# Step 1: Call the function /webhooks/show to get the webhook id +$webhookId = $(Invoke-RestMethod -Method GET -Uri "https://${funchost}.azurewebsites.net/api/webhooks/show?code=${code}&listTitle=${listTitle}¬ificationUrl=${notificationUrl}").Id +# Step 2: Call the function /webhooks/remove and pass the webhook id +Invoke-RestMethod -Method POST -Uri "https://${funchost}.azurewebsites.net/api/webhooks/remove?code=${code}&listTitle=${listTitle}&webhookId=${webhookId}" +``` + +## Cleanup the resources in Azure + +You can delete all the resources this project created in Azure, by running the command **azd down**. + +Alternatively, you can delete the resource group, that has the azd environment's name by default. + +## See also + +- [Overview of SharePoint webhooks](overview-sharepoint-webhooks.md) diff --git a/docs/apis/webhooks/sharepoint-webhooks-using-azure-functions.md b/docs/apis/webhooks/sharepoint-webhooks-using-azure-functions.md index fc2be4e5b..967d0e43d 100644 --- a/docs/apis/webhooks/sharepoint-webhooks-using-azure-functions.md +++ b/docs/apis/webhooks/sharepoint-webhooks-using-azure-functions.md @@ -1,19 +1,18 @@ --- title: Using Azure Functions with SharePoint webhooks description: Set up and use Azure Functions for your webhooks to take care of the hosting and scaling of your function. -ms.date: 05/09/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 09/23/2022 +ms.localizationpriority: high --- - - # Using Azure Functions with SharePoint webhooks -[Azure Functions](/azure/azure-functions/functions-overview) offers an easy way to host your SharePoint webhooks: you can add your webhook C# or JavaScript code via the browser, and Azure takes care of the hosting and scaling of your function. This guide shows how to set up and use Azure Functions for your webhooks. +[Azure Functions](/azure/azure-functions/functions-overview) offers an easy way to host your SharePoint webhooks: you can add your webhook C# or JavaScript code via the browser, and Azure takes care of the hosting and scaling of your function. + +This guide shows how to set up and use Azure Functions for your webhooks using the Azure portal. Alternatively, you can refer to article [Create Azure Functions for SharePoint webhooks using an azd template](sharepoint-webhooks-using-azd-template.md), to automate the whole process using an **azd** template. ## Create an Azure Function App -The first step you need to do is create an Azure Function App, which is a special Azure Web App focused on hosting Azure Functions. +The first step you need to do is to create an Azure Function App, which is a special Azure Web App focused on hosting Azure Functions. 1. Navigate to [https://portal.azure.com](https://portal.azure.com), search for **function app**. Select **Function App** from the search results. @@ -63,7 +62,7 @@ In our case, we want this Azure Function to behave as a SharePoint webhook servi You can achieve this by replacing the default code with the following code: -```cs +```csharp #r "Newtonsoft.Json" using System.Net; diff --git a/docs/apis/webhooks/webhooks-reference-implementation.md b/docs/apis/webhooks/webhooks-reference-implementation.md index c69946a02..f6285aaf7 100644 --- a/docs/apis/webhooks/webhooks-reference-implementation.md +++ b/docs/apis/webhooks/webhooks-reference-implementation.md @@ -1,46 +1,38 @@ --- title: SharePoint webhooks sample reference implementation -description: This SharePoint Patterns and Practices (PnP) reference implementation shows how you can use SharePoint webhooks in your application. -ms.date: 02/08/2018 -ms.prod: sharepoint -localization_priority: Priority +description: This SharePoint Patterns and Practices (PnP) reference implementation shows how you can use SharePoint webhooks in your application. +ms.date: 06/05/2024 +ms.localizationpriority: high --- - - # SharePoint webhooks sample reference implementation The SharePoint Patterns and Practices (PnP) reference implementation shows how you can use SharePoint webhooks in your application. The webhooks are implemented in an enterprise ready manner using various Microsoft Azure components such as Azure Web Jobs, Azure SQL Server, and Azure Storage Queues for asynchronous web job notification handling. -The reference implementation only works with [SharePoint list webhooks](./lists/overview-sharepoint-list-webhooks.md). +The reference implementation only works with [SharePoint list webhooks](./lists/overview-sharepoint-list-webhooks.md). -You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel: - -
+You can also follow these steps by watching the video on the Microsoft 365 Platform Community (PnP) YouTube Channel: > [!Video https://www.youtube.com/embed/P4a1_EWokwM] -
- **Applies to** Office 365 Multi Tenant (MT). -Microsoft Azure is used to host the various components needed to implement Azure webhooks. +Microsoft Azure is used to host the various components needed to implement SharePoint webhooks. + +Source code and other materials for the reference implementation are available in two flavors: -Source code and other materials for the reference implementation are available in two flavors: - A SharePoint provider-hosted application version -- An Office 365 Azure AD application, which can be found in the [SharePoint developer samples GitHub repository](https://aka.ms/sp-webhooks-sample-reference). +- An Office 365 Azure AD application, which can be found in the [SharePoint developer samples GitHub repository](https://aka.ms/sp-webhooks-sample-reference). ## Deploy the reference implementation -The application shows you how to manage webhooks, specifically for a SharePoint list. It also contains a reference implementation of a webhook service endpoint that you can reuse in your webhook projects. +The application shows you how to manage webhooks, specifically for a SharePoint list. It also contains a reference implementation of a webhook service endpoint that you can reuse in your webhook projects. ![SharePoint webhook reference implementation application](../../images/webhook-sample-application.png) ### Deployment guides -- The [SharePoint web hooks reference implementation deployment guide](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List/Deployment%20guide.md) lists the deployment steps used to deploy the SharePoint provider-hosted reference implementation. - -- To deploy the Office 365 Azure AD application, use the steps described at [SharePoint web hooks Azure AD reference implementation deployment guide](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List.AzureAD/Deployment%20guide.md), which shows you how to use a Web API function as webhook service. - +- The [SharePoint webhooks reference implementation deployment guide](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List/Deployment%20guide.md) lists the deployment steps used to deploy the SharePoint provider-hosted reference implementation. +- To deploy the Office 365 Azure AD application, use the steps described at [SharePoint webhooks Azure AD reference implementation deployment guide](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List.AzureAD/Deployment%20guide.md), which shows you how to use a Web API function as webhook service. - If you're more interested in using Azure Functions, see the [Azure Functions guide](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List.AzureAD/azure%20functions%20guide.md) for more details on how to use Azure Functions in this reference implementation. ### Introduction to webhooks @@ -51,9 +43,9 @@ Webhooks notify your application about changes in SharePoint that the applicatio The reference implementation works with a SharePoint list. To add a webhook to a SharePoint list, your application first creates a webhook subscription by sending a [`POST /_api/web/lists('list-id')/subscriptions`](./lists/create-subscription.md) request. The request includes the following items: -* A payload that identifies the list that you're adding the webhook for. -* The location of your webhook service URL to send the notifications. -* The expiration date of the webhook. +- A payload that identifies the list that you're adding the webhook for. +- The location of your webhook service URL to send the notifications. +- The expiration date of the webhook. After you've requested SharePoint to add your webhook, SharePoint validates that your webhook service endpoint exists. It sends a validation string to your service endpoint. SharePoint expects that your service endpoint returns the validation string within 5 seconds. If this process fails, the webhook creation is canceled. If you've deployed your service, this works and SharePoint returns an HTTP 201 message on the POST request that the application initially sent. The payload in the response contains the ID of the new webhook subscription. @@ -61,7 +53,7 @@ After you've requested SharePoint to add your webhook, SharePoint validates that Take a look at the reference implementation, and you'll see that all webhook CRUD operations are consolidated in the [WebHookManager](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List/SharePoint.WebHooks.Common/WebHookManager.cs) class of the **SharePoint.WebHooks.Common** project. Adding a webhook is done by using the **AddListWebHookAsync** method: -```cs +```csharp /// /// This method adds a webhook to a SharePoint list. Note that you need your webhook endpoint being passed into this method to be up and running and reachable from the internet /// @@ -77,11 +69,9 @@ public async Task AddListWebHookAsync(string siteUrl, string } ``` -
- When making a call to SharePoint, you need to provide authentication information, and in this case you're using a **Bearer** authentication header with an **access token**. To obtain the access token, intercept the token via an **ExecutingWebRequest** event handler: -```cs +```csharp ClientContext cc = null; // Create SharePoint ClientContext object... @@ -92,7 +82,7 @@ cc.ExecutingWebRequest += Cc_ExecutingWebRequest; // Capture the OAuth access token since we want to reuse that one in our REST requests private void Cc_ExecutingWebRequest(object sender, WebRequestEventArgs e) { - this.accessToken = e.WebRequestExecutor.RequestHeaders.Get("Authorization").Replace("Bearer ", ""); + this.accessToken = e.WebRequestExecutor.RequestHeaders.Get("Authorization").Replace("Bearer ", ""); } ``` @@ -119,14 +109,13 @@ In the previous step, your service endpoint was called, but SharePoint only prov ![Async GetChanges](../../images/webhook-sample-async-getchanges.png) -You can learn more about the `GetChanges()` implementation in the **ProcessNotification** method in the [ChangeManager](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List/SharePoint.WebHooks.Common/ChangeManager.cs) class of the **SharePoint.WebHooks.Common** project. +You can learn more about the `GetChanges()` implementation in the **ProcessNotification** method in the [ChangeManager](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List/SharePoint.WebHooks.Common/ChangeManager.cs) class of the **SharePoint.WebHooks.Common** project. To avoid getting the same change repeatedly, it's important that you inform SharePoint from which point you want the changes. This is done by passing a **changeToken**, which also implies that your service endpoint needs to persist the last used **changeToken** so that it can be used the next time the service endpoint is called. The following are some key things to note about changes: - SharePoint does not call your service in real-time: when a change happens on a list that has a webhook, SharePoint queues a webhook callout. Once each minute, this queue is read and the appropriate service endpoints are called. This batching of requests is important. For example, if a bulk upload of 1000 records occurred at once, batching prevents SharePoint from calling your endpoint 1000 times. So your endpoint is only called once, but when you call the `GetChanges()` method, you get 1000 change events that you need to process. - - To guarantee an immediate response, regardless of the number of changes there, it's important that the workload of your service endpoint runs asynchronously. In the reference implementation, we leveraged the power of Azure: the service serializes the incoming payload and stores it in an Azure Storage queue while there's an Azure web job that runs continuously and checks for messages in the queue. When there are messages in the queue, the web job processes them and also executes your logic asynchronously. ## Complete end-to-end flow @@ -136,14 +125,14 @@ The following diagram describes the complete end-to-end webhook flow. ![Webhooks reference implementation end-to-end flow](../../images/webhook-sample-end-to-end-flow.png) 1. Your application creates a webhook subscription. When it does, it gets the current **changeToken** from the list it created the webhook for. -2. Your application persists the **changeToken** in a persistent storage, such as SQL Azure in this case. -3. A change in SharePoint occurs, and SharePoint calls your service endpoint. -4. Your service endpoint serializes the notification request and stores it in a storage queue. -5. Your web job sees the message in the queue and starts your message processing logic. -6. Your message processing logic retrieves the last used change token from the persistent storage. -7. Your message processing logic uses the `GetChanges()`API to determine what changed. -8. The returned changes are processed and now your application performs what it needs to do based on the changes. -9. Finally, the application persists the last retrieved **changeToken** so that next time it does not receive changes that were already processed. +1. Your application persists the **changeToken** in a persistent storage, such as SQL Azure in this case. +1. A change in SharePoint occurs, and SharePoint calls your service endpoint. +1. Your service endpoint serializes the notification request and stores it in a storage queue. +1. Your web job sees the message in the queue and starts your message processing logic. +1. Your message processing logic retrieves the last used change token from the persistent storage. +1. Your message processing logic uses the `GetChanges()`API to determine what changed. +1. The returned changes are processed and now your application performs what it needs to do based on the changes. +1. Finally, the application persists the last retrieved **changeToken** so that next time it does not receive changes that were already processed. ## Work with webhook renewal @@ -155,14 +144,14 @@ When your service receives a notification, it also gets information about the su ### Reliable but more complex model -Create a web job that on a weekly basis reads all the subscription IDs from the persistent storage. One-by-one extend the found subscriptions each time. +Create a web job that on a weekly basis reads all the subscription IDs from the persistent storage. One-by-one extend the found subscriptions each time. > [!NOTE] > This web job is not part of this reference implementation. -The actual renewal of a SharePoint list webhook can be done by using a [`PATCH /_api/web/lists('list-id')/subscriptions(‘subscriptionID’)`](./lists/update-subscription.md) REST call. +The actual renewal of a SharePoint list webhook can be done by using a [`PATCH /_api/web/lists('list-id')/subscriptions(‘subscriptionID’)`](./lists/update-subscription.md) REST call. -In the reference implementation, updating of webhooks is implemented in the [WebHookManager](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List/SharePoint.WebHooks.Common/WebHookManager.cs) class of the **SharePoint.WebHooks.Common** project. +In the reference implementation, updating of webhooks is implemented in the [WebHookManager](https://github.com/SharePoint/sp-dev-samples/blob/master/Samples/WebHooks.List/SharePoint.WebHooks.Common/WebHookManager.cs) class of the **SharePoint.WebHooks.Common** project. Updating a webhook is done by using the **UpdateListWebHookAsync** method: @@ -179,7 +168,7 @@ Updating a webhook is done by using the **UpdateListWebHookAsync** method: /// true if successful, exception in case something went wrong public async Task UpdateListWebHookAsync(string siteUrl, string listId, string subscriptionId, string webHookEndPoint, DateTime expirationDateTime, string accessToken) { - // webhook update code... + // webhook update code... } ``` @@ -187,10 +176,8 @@ public async Task UpdateListWebHookAsync(string siteUrl, string listId, st Because SharePoint is calling out to your webhook service endpoint, your endpoint needs to be reachable by SharePoint. This makes development and debugging slightly more complex. The following are some strategies that you can use to make your life easier: -* During initial development, you provide your own serialized payload to your service processing logic. This makes it possible to completely test your processing logic without deploying the service endpoint (and even without configuring a webhook). - -* If you have access to Azure resources, you can deploy your endpoint to Azure by using a debug build and configuring the Azure App Service for debugging. This allows you to set a remote breakpoint and do remote debugging using Visual Studio. - +- During initial development, you provide your own serialized payload to your service processing logic. This makes it possible to completely test your processing logic without deploying the service endpoint (and even without configuring a webhook). +- If you have access to Azure resources, you can deploy your endpoint to Azure by using a debug build and configuring the Azure App Service for debugging. This allows you to set a remote breakpoint and do remote debugging using Visual Studio. - If you do not want to deploy your service during development time, you need to use a secure tunnel for your service. The idea is that you tell SharePoint that the notification service is located on a shared public endpoint. In the client, you install a component that connects to that shared public service, and whenever a call is made to the public endpoint, the client component is notified and it pushes the payload to your service running on localhost. [ngrok](https://ngrok.com/) is an implementation of such a secure tunnel tool that you can use to debug your webhook service locally. ## See also diff --git a/docs/business-apps/get-started/set-up-sharepoint-site-lists-libraries.md b/docs/business-apps/get-started/set-up-sharepoint-site-lists-libraries.md index 7490299c5..6bdb52272 100644 --- a/docs/business-apps/get-started/set-up-sharepoint-site-lists-libraries.md +++ b/docs/business-apps/get-started/set-up-sharepoint-site-lists-libraries.md @@ -2,8 +2,7 @@ title: Set up your SharePoint site with lists and libraries description: Set up your SharePoint site with lists and libraries ms.date: 6/23/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Set up your SharePoint site with lists and libraries diff --git a/docs/business-apps/introduction-to-sharepoint-business-process-integration.md b/docs/business-apps/introduction-to-sharepoint-business-process-integration.md index 32507ead0..576208048 100644 --- a/docs/business-apps/introduction-to-sharepoint-business-process-integration.md +++ b/docs/business-apps/introduction-to-sharepoint-business-process-integration.md @@ -1,9 +1,9 @@ --- title: Business apps and business process automation description: Business apps and business process automation. -ms.date: 04/30/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 06/28/2022 +ms.service: sharepoint-online +ms.localizationpriority: high --- # Business apps and business process automation diff --git a/docs/business-apps/power-apps/get-started/create-your-first-custom-form.md b/docs/business-apps/power-apps/get-started/create-your-first-custom-form.md index 7495c5a0c..0ec652047 100644 --- a/docs/business-apps/power-apps/get-started/create-your-first-custom-form.md +++ b/docs/business-apps/power-apps/get-started/create-your-first-custom-form.md @@ -1,9 +1,8 @@ --- title: Customize a form for a SharePoint list description: Customize a form for a SharePoint list -ms.date: 05/18/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 09/27/2022 +ms.localizationpriority: high --- # Customize a form for a SharePoint list @@ -135,9 +134,3 @@ To hide the **Attachments** field if the project owner is Nestor Wilke, follow t The version of the custom form that appears in SharePoint is the most recently published version. 1. In SharePoint, verify the intended functionality of your app. - -## Next steps - -Congratulations on creating your custom form. - -In the next topic, we will create a standalone app using data from a SharePoint list. diff --git a/docs/business-apps/power-automate/get-started/connect-to-other-services-in-your-flow.md b/docs/business-apps/power-automate/get-started/connect-to-other-services-in-your-flow.md index 0d9f8cffd..40d815c10 100644 --- a/docs/business-apps/power-automate/get-started/connect-to-other-services-in-your-flow.md +++ b/docs/business-apps/power-automate/get-started/connect-to-other-services-in-your-flow.md @@ -1,10 +1,10 @@ --- title: Connect your flow to other services description: Connect your flow to 200+ services available in Power Automate, and build an integrated experience to perform actions in the services. -ms.date: 06/22/2021 -ms.prod: sharepoint -localization_priority: Priority -search.app: +ms.date: 09/23/2022 +ms.service: sharepoint-online +ms.localizationpriority: high +search.app: - Flow search.appverid: met150 --- @@ -73,4 +73,4 @@ In this article, we will connect to Microsoft Teams and post a message to one of ## Next steps -Learn new skills and discover Power Automate with step-by-step guidance by exploring learning paths and modules available here: [Power Automate Learning Paths](/learn/browse/?term=Power%20Automate&products=power-automate). +Learn new skills and discover Power Automate with step-by-step guidance by exploring learning paths and modules available here: [Power Automate Learning Paths](/training/browse/?term=Power%20Automate&products=power-automate). diff --git a/docs/business-apps/power-automate/get-started/create-your-first-flow.md b/docs/business-apps/power-automate/get-started/create-your-first-flow.md index 3d2809732..77b9f7505 100644 --- a/docs/business-apps/power-automate/get-started/create-your-first-flow.md +++ b/docs/business-apps/power-automate/get-started/create-your-first-flow.md @@ -1,10 +1,10 @@ --- title: Send an email when a new item is created or modified in a SharePoint list description: Send an email when a new item is created or modified in a SharePoint list -ms.date: 06/14/2021 -ms.prod: sharepoint -localization_priority: Priority -search.app: +ms.date: 06/28/2022 +ms.service: sharepoint-online +ms.localizationpriority: high +search.app: - Flow search.appverid: met150 --- @@ -26,10 +26,10 @@ Before proceeding with these instructions, make sure your SharePoint site is set * Create a flow * See your flows - * Configure flows + * Configure flows ![Create a flow from Projects list](../../../images/lists-integrate-power-automate-create-flow.png) - + > [!NOTE] > If they are available for the list or library here, you may see other options on the **Automate** menu, such as **Set a reminder** and other flows. diff --git a/docs/business-apps/power-automate/guidance/customize-page-approvals.md b/docs/business-apps/power-automate/guidance/customize-page-approvals.md index d5e185bb9..72fe0d715 100644 --- a/docs/business-apps/power-automate/guidance/customize-page-approvals.md +++ b/docs/business-apps/power-automate/guidance/customize-page-approvals.md @@ -1,7 +1,7 @@ --- title: Customize SharePoint page approvals to meet your needs description: With the help of flows in Power Automate, you can configure page approval to add to the standard publishing process for a site. The default publishing flow meets your basic needs. -ms.date: 07/12/2020 +ms.date: 06/28/2022 search.app: - Flow search.appverid: met150 @@ -44,5 +44,3 @@ Occasionally, the default approval action may not help in tracking and auditing ![Parallel approvals in flow](../../../images/parallel-approvals-in-flow.png) To learn more, see [Create parallel approval workflows with Power Automate](/power-automate/parallel-modern-approvals). - - diff --git a/docs/business-apps/power-automate/guidance/manage-list-flows.md b/docs/business-apps/power-automate/guidance/manage-list-flows.md index 92dbd6cb0..52416dbef 100644 --- a/docs/business-apps/power-automate/guidance/manage-list-flows.md +++ b/docs/business-apps/power-automate/guidance/manage-list-flows.md @@ -1,10 +1,10 @@ --- title: Manage owners and users in your Microsoft list flows with Power Automate -ms.date: 06/02/2021 -search.app: +description: Manage owners and users of your Power Automate flows for Microsoft lists. You can see all users of a flow, add new users or owners, and modify existing users or owners. +ms.date: 06/28/2022 +search.app: - Flow search.appverid: met150 -description: Manage owners and users of your Power Automate flows for Microsoft lists. You can see all users of a flow, add new users or owners, and modify existing users or owners. --- # Manage owners and users in your Microsoft list flows with Power Automate diff --git a/docs/business-apps/power-automate/guidance/manage-list-item-file-permissions.md b/docs/business-apps/power-automate/guidance/manage-list-item-file-permissions.md index f848aadf4..2a5f77c7d 100644 --- a/docs/business-apps/power-automate/guidance/manage-list-item-file-permissions.md +++ b/docs/business-apps/power-automate/guidance/manage-list-item-file-permissions.md @@ -1,13 +1,16 @@ --- title: Manage list item and file permissions with Power Automate -ms.date: 07/16/2020 -search.app: +description: "SharePoint connector in Power Automate lets you grant access, create sharing links, or rescind access for items or folders." +ms.date: 12/01/2022 +search.app: - Flow search.appverid: met150 --- # Manage list item and file permissions with Power Automate flows -SharePoint connector in Power Automate provides the following actions to manage permissions of an individual list item in a list or a file in a document library. + +SharePoint connector in Power Automate provides the following actions to manage permissions of an individual list item in a list or a file in a document library. + - Grant access to an item or a folder - Create sharing link for a file or folder - Stop sharing an item or a file @@ -15,7 +18,9 @@ SharePoint connector in Power Automate provides the following actions to manage All of the above actions let you customize permissions for the item or a file to allow the right users to access that item or the file. To grant access or stop sharing, you will need to be a list owner of that list or library. That means, in your flow for these actions, you must connect to the list or library using a list owner user account. ## Grant access to an item or a folder + The 'Grant access to an item or a folder' action requires the following inputs: + - SharePoint site URL - List or library name or identifier - The item or the file identifier for which to grant access @@ -24,22 +29,26 @@ The 'Grant access to an item or a folder' action requires the following inputs: ![Grant access to an item or a folder](../../../images/grant-access-item-file-action-flow.png) -In the flow action, you can also include a message and choose to notify the recipients once they get access to the item or the file. +In the flow action, you can also include a message and choose to notify the recipients once they get access to the item or the file. > [!NOTE] > 'Grant access to an item or a folder' does not support granting access to external users. ### Choosing a permission role to grant access -Depending on the user, you may want to grant them either access to edit or read. You can choose the right access in the Roles property. + +Depending on the user, you may want to grant them either access to edit or read. You can choose the right access in the Roles property. ![Choose the right role to grant access to an item or a file](../../../images/grant-access-item-file-roles-flow.png) -The permission roles map to [simplified standard SharePoint permission groups](https://docs.microsoft.com/sharepoint/modern-experience-sharing-permissions): +The permission roles map to [simplified standard SharePoint permission groups](/sharepoint/modern-experience-sharing-permissions): + - Members -- Owners +- Visitors ### Using custom-defined roles to grant access + In advanced scenarios where you need to specify a custom-defined permission role, you can do so in the flow action by entering a custom value for the *Roles* property in the following format: + ``` role: ``` @@ -47,23 +56,26 @@ role: ![Use a custom role to grant access to an item or a file](../../../images/grant-access-item-file-custom-role-flow.png) If you want to get the role id for the custom-defined role permission, you can do so by navigating to the SharePoint URL in your web browser and then search for that role. + ``` https:///_api/web/roledefinitions ``` For example: + ``` https://contoso.microsoft.com/teams/itweb/_api/web/roledefinitions ``` -You can find the role Id in the *category* property of an role item. +You can find the role Id in the *category* property of an role item. ![SharePoint site role definitions](../../../images/sp-web-roledefinitions.png) ## Grant access using sharing links -Instead of granting users access to files directly, you can provide access to a specific file using [shareable links](https://docs.microsoft.com/sharepoint/modern-experience-sharing-permissions#sharable-links). -You can use the '[Create sharing link for a file or folder](https://docs.microsoft.com/sharepoint/dev/business-apps/power-automate/sharepoint-connector-actions-triggers#create-sharing-link-for-a-file-or-folder)' action to create shareable links for a given file. +Instead of granting users access to files directly, you can provide access to a specific file using [shareable links](/sharepoint/modern-experience-sharing-permissions#sharable-links). + +You can use the '[Create sharing link for a file or folder](/sharepoint/dev/business-apps/power-automate/sharepoint-connector-actions-triggers#create-sharing-link-for-a-file-or-folder)' action to create shareable links for a given file. > [!NOTE] > 'Create sharing link for a file or folder' only supports files or folders in a document library. List items are not supported yet. @@ -71,17 +83,20 @@ You can use the '[Create sharing link for a file or folder](https://docs.microso ![Create sharing link for a file or folder flow action](../../../images/create-sharing-link-file-action-flow.png) When creating a shareable link using the action, you can specify: + - Link type - - Type of sharing link - view and edit or view only + - Type of sharing link - view and edit or view only - Link scope - Who gets access to the link - anyone with the link, including anonymous or people in your organization ## Stop sharing an item or a file + The 'Stop sharing an item or a file' action requires the following inputs: + - SharePoint site address - List or library name or identifier - The item or the file identifier for which to stop sharing ![Stop sharing an item or a file flow action](../../../images/stop-sharing-item-action-flow.png) -Applying this flow action will reset all permissions except on that item or the file except for site owners. +Applying this flow action will remove all permissions on that item or file except for site owners. diff --git a/docs/business-apps/power-automate/guidance/migrate-from-classic-workflows-to-power-automate-flows.md b/docs/business-apps/power-automate/guidance/migrate-from-classic-workflows-to-power-automate-flows.md index 43ec96450..c2a03fc9c 100644 --- a/docs/business-apps/power-automate/guidance/migrate-from-classic-workflows-to-power-automate-flows.md +++ b/docs/business-apps/power-automate/guidance/migrate-from-classic-workflows-to-power-automate-flows.md @@ -1,7 +1,8 @@ --- title: Guidance - Migrate from classic workflows to Power Automate flows in SharePoint description: This article specifically provides guidance about how to plan for transitioning from classic SharePoint Workflows to Power Automate flows. -ms.date: 07/21/2020 +ms.date: 05/12/2023 +ms.service: power-automate search.app: - Flow search.appverid: met150 @@ -23,17 +24,22 @@ This article specifically provides guidance about how to plan for transitioning Classic workflows in SharePoint constitutes two workflow systems namely -- SharePoint 2010 workflow +- SharePoint 2010 workflow ([deprecated in November 2020](https://support.microsoft.com/en-us/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f)) - SharePoint 2013 workflow While both workflow systems allow users to build and publish workflows in SharePoint, see the following key differences: - SharePoint 2010 workflows, released along with SharePoint Server 2010, are hosted, and executed in SharePoint workflow runtime. - - SharePoint 2013 workflows, released along with SharePoint Server 2013, are hosted in SharePoint, and executed in Workflow Manager, that runs independently. Users primarily use SharePoint Designer to author and publish workflows in SharePoint, while professional developers, looking to extend and build workflows, use Visual Studio to build and publish workflows in SharePoint. +> [!Important] +> After August 1, 2020, new Microsoft 365 customers can use SharePoint 2013 workflows or Power Automate. However, SharePoint 2013 workflows will follow a similar retirement path in the future, so it's highly recommended to use Power Automate or other supported solutions. If you want to learn more about the SharePoint 2013 workflow usage inside your tenant you can use the [Workflow 2013 Assessment tool](https://aka.ms/microsoft365assessmenttool). This tool will assess your tenant on SharePoint 2013 workflow usage and generates a Power BI report with the findings. + +>[!Note] +>The SharePoint Migration Tool (SPMT) lets you migrate SharePoint Server 2010 out-of-the-box workflows and SharePoint Designer 2010 & 2013 workflows to Power Automate. [Learn more about migrating your SharePoint Server and SharePoint Designer workflows with SPMT.](/sharepointmigration/spmt-workflow-overview) + ## Modern workflows with Power Automate flows Since the release of classic workflows, SharePoint and Microsoft 365 apps have evolved to provide compelling, flexible and more performant experiences. Modern experiences in SharePoint integrate with rest of the Microsoft 365 apps and services driving security, productivity, and collaboration. @@ -45,7 +51,6 @@ Since the release of classic workflows, SharePoint and Microsoft 365 apps have e Using Microsoft Power Automate, SharePoint users can use the SharePoint Connector to create automations for when data changes in a list or a library. Users can build simple to complex workflows such as, but not limited to: - Send an email when a new item is created in a list. - - Start approval when a new file is added in a library. To create and author flows, users primarily use [Power Automate website](https://flow.microsoft.com/) while users can also [create flows from within SharePoint](https://support.microsoft.com/office/create-a-flow-for-a-list-or-library-in-sharepoint-or-onedrive-a9c3e03b-0654-46af-a254-20252e580d01?ui=en-us&rs=en-us&ad=us) or using the [Power Automate mobile app](/power-automate/mobile-create-flow). @@ -56,25 +61,23 @@ To learn more about building workflows using Power Automate in SharePoint, start Many people feel there are significant gaps between SharePoint Designer (classic) workflows and Power Automate flows, but the list is not long. Of course, there are some workarounds you should consider in your planning as you move from classic workflows to Power Automate flows. -- **30 day run limit for flows** – SharePoint Designer workflows can run endlessly, but flows have a 30 day lifespan. Getting beyond this limitation means your flow will need to call itself in a re-entrant way to restart the clock ticking. -- **HTTP Connector** – If you make calls to SharePoint's REST API, then you can use the ['Send HTTP Request to SharePoint'](../guidance/working-with-send-sp-http-request.md) action available in the SharePoint connector. Flow also has a generic HTTP connector (as an action), but it is a Premium connector. If you use HTTP calls extensively, you may want to create a “service account” user with a Power Automate license and run these flows with that user account. This also will make it easier to manage the set of flows you consider "enterprise" flows. -- **Reusable Flows** – Using some modular thinking, you can create a master flow which a flow per list or library can call to do the heavy lifting. (In some ways this is even preferable, as you can edit a flow which is used in many locations centrally.) Alternatively, you can use flow actions to discover all of the lists or libraries which match some criteria and run the flow on them all on a timer rather than based on events. -- **Workflow history storage** – Flows maintain a history in the context of the flow itself in the Power Automate dashboard. If you need tracking in your sites, you can have the flow log information in a list you create. -- **Impersonation** - In SharePoint 2010 workflows, you can add an impersonation step to act as a different user. This capability is not readily available in flows. +- **30 day run limit for flows** – SharePoint Designer workflows can run endlessly, but flows have a 30 day lifespan. Getting beyond this limitation means your flow will need to call itself in a re-entrant way to restart the clock ticking. Depending on the solution you choose to accomplish this, this may require a Premium Power Automate license. +- **HTTP Connector** – If you make calls to SharePoint's REST API, then you can use the ['Send HTTP Request to SharePoint'](../guidance/working-with-send-sp-http-request.md) action available in the SharePoint connector. Flow also has a generic HTTP connector (as an action), but it is a Premium connector. If you use HTTP calls extensively, you may want to create a “service account” user with a Power Automate license and run these flows with that user account. This also will make it easier to manage the set of flows you consider "enterprise" flows. +- **Reusable Flows** – Using some modular thinking, you can create a master flow which a flow per list or library can call to do the heavy lifting. In some ways this is even preferable, as you can edit a flow which is used in many locations centrally. This will however require a Premium Power Automate license. Alternatively, you can use flow actions to discover all of the lists or libraries which match some criteria and run the flow on them all on a timer rather than based on events. +- **Workflow history storage** – Flows maintain an extensively detailed history in the context of the flow itself in the Power Automate dashboard for the runs that have occured in the last 28 days. If you need tracking in your sites, or keep historical logging longer than 28 days, you can have the flow log information in a list you create. +- **Impersonation** - In SharePoint 2010 workflows, you can add an impersonation step to act as a different user. You could achieve similar functionality by using different user accounts with different (elevated) priviledges for certain actions. Alternatively you can consider using an Azure Active Directory Application registration, assigning it permissions and using that to directly call into the APIs. The latter will require a Premium Power Automate license and requires more manual effort to make the calls. -While these pain points do exist, you can see there are workarounds for each of them. +While these pain points do exist, you can see there are workarounds for each of them. Do beware that some of these workarounds will require a Power Automate Premium license. Read more about the [license implications](/power-platform/admin/power-automate-licensing/faqs#i-have-multiple-flows-running-under-a-shared-service-account-what-licenses-do-i-need) of doing so and [who will require to have a Premium license](/power-platform/admin/power-automate-licensing/faqs#who-needs-to-purchase-a-premium-license). ## Modern approvals with Power Automate flows Approvals are the most common workflow scenario when it comes to automating business processes in SharePoint. Transitioning to Power Automate flows, approvals can be streamlined for data in SharePoint, Dynamics 365, forms, SQL, and so on. You can create approvals in your workflow, and view sent and received requests in a unified Actions center. Power Automate approvals enable users to customize flows and create approvals for the following types: - [Single approvals](/power-automate/modern-approvals) - - [Sequential approvals](/power-automate/sequential-modern-approvals) - - [Parallel approvals](/power-automate/parallel-modern-approvals) -SharePoint approvals such as [page approvals](customize-page-approvals.md), [document approvals][Require approval of documents in SharePoint using Power Automate](require-doc-approval.md), and [hub association approvals](https://support.microsoft.com/office/set-up-your-sharepoint-hub-site-e2daed64-658c-4462-aeaf-7d1a92eba098#bkmk_managesiteassociationapprovals) are all integrated and powered by Power Automate flows, providing users the flexibility to customize the business process for each of the approval scenarios. +SharePoint approvals such as [page approvals](customize-page-approvals.md), [document approvals](require-doc-approval.md), and [hub association approvals](https://support.microsoft.com/office/set-up-your-sharepoint-hub-site-e2daed64-658c-4462-aeaf-7d1a92eba098#bkmk_managesiteassociationapprovals) are all integrated and powered by Power Automate flows, providing users the flexibility to customize the business process for each of the approval scenarios. ## Authoring classic workflows and flows @@ -87,145 +90,145 @@ See the following tables that compare the workflow terminologies, triggers, and While the following lists show some of the most common workflow capabilities, Power Automate offers many more features, and is actively updated with new features. We highly recommend visiting the following Power Automate websites for guided learning: - [Microsoft SharePoint Connector in Power Automate](../sharepoint-connector-actions-triggers.md) -- [Learn Power Automate](/learn/browse/?products=power-automate&term=Power%20Automate&terms=Power%20Automate) -- [Power Automate Documentation](/power-automate/?utm_source=flow-sidebar&utm_medium=web) +- [Learn Power Automate](/training/browse/?products=power-automate&term=Power%20Automate&terms=Power%20Automate) +- [Power Automate Documentation](/power-automate) ### Workflow concepts -|Workflow concept |SharePoint workflow |Power Automate | -|:-------|:-------|:--------| -| A condition that causes the workflow to run or execute | Start options and events | Trigger | -| Building blocks that allow users to customize workflow with business logic | Actions | Actions | -| Apply and perform conditional business logic in workflows | Conditions | Conditions (available under Actions) | -| Get additional input from users when running manual workflows | Initiation form | Trigger Inputs | +| Workflow concept | SharePoint workflow | Power Automate | +| :------------------------------------------------------------------------- | :----------------------- | :----------------------------------- | +| A condition that causes the workflow to run or execute | Start options and events | Trigger | +| Building blocks that allow users to customize workflow with business logic | Actions | Actions | +| Apply and perform conditional business logic in workflows | Conditions | Conditions (available under Actions) | +| Get additional input from users when running manual workflows | Initiation form | Trigger Inputs | ### Workflow types -|Workflow type |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| List workflows | Yes | Yes | -| Library workflows | Yes | Yes | -| Reusable workflows | Yes | Not available | -| Site workflows | Yes | Not available | +| Workflow type | SharePoint workflow | Power Automate flow | +| :----------------- | :------------------ | :------------------ | +| List workflows | Yes | Yes | +| Library workflows | Yes | Yes | +| Reusable workflows | Yes | Not available | +| Site workflows | Yes | Not available | ### SharePoint integrations -|SharePoint integration |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Create a custom workflow from a list or library | Yes | Yes, only in Modern Experiences | -| Run or start a custom workflow for an item or a file or a folder | Yes | Yes, only in Modern Experiences | -| Create and respond to standard approval for an item or a file | Yes | Yes | -| Create and respond to classic publishing page approvals | Yes | Not available | -| Create and respond to modern page approvals | Not available | Yes | -| Create and manage Hub Site association approval requests | Not available | Yes | +| SharePoint integration | SharePoint workflow | Power Automate flow | +| :--------------------------------------------------------------- | :------------------ | :------------------------------ | +| Create a custom workflow from a list or library | Yes | Yes, only in Modern Experiences | +| Run or start a custom workflow for an item or a file or a folder | Yes | Yes, only in Modern Experiences | +| Create and respond to standard approval for an item or a file | Yes | Yes | +| Create and respond to classic publishing page approvals | Yes | Not available | +| Create and respond to modern page approvals | Not available | Yes | +| Create and manage Hub Site association approval requests | Not available | Yes | ### List triggers -|List trigger |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| When an item is created | Yes | Yes | -| When an item is modified | Yes | Yes | -| When an item is created or modified | Not available | Yes | -| Site workflows | Yes | Not available | -| When an item is deleted | Not available | Yes | -| For a selected item | Yes | Yes | +| List trigger | SharePoint workflow | Power Automate flow | +| :---------------------------------- | :------------------ | :------------------ | +| When an item is created | Yes | Yes | +| When an item is modified | Yes | Yes | +| When an item is created or modified | Not available | Yes | +| Site workflows | Yes | Not available | +| When an item is deleted | Not available | Yes | +| For a selected item | Yes | Yes | ### List actions -|List action |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Get items | Not available | Yes | -| Create an item | Yes | Yes | -| Update an item | Yes | Yes | -| Delete an item | Yes | Yes | -| Copy a list item | Yes | Yes, by reusing ‘Create an item' action | -| Get attachments | Not available | Yes | -| Get attachment content | Not available | Yes | -| Add attachment | Not available | Yes | -| Delete attachment | Not available | Yes | -| Set field value in current item | Yes | Yes, using ‘Update an item’ action | -| Get changes for an item | No | Yes | +| List action | SharePoint workflow | Power Automate flow | +| :------------------------------ | :------------------ | :-------------------------------------- | +| Get items | Not available | Yes | +| Create an item | Yes | Yes | +| Update an item | Yes | Yes | +| Delete an item | Yes | Yes | +| Copy a list item | Yes | Yes, by reusing ‘Create an item' action | +| Get attachments | Not available | Yes | +| Get attachment content | Not available | Yes | +| Add attachment | Not available | Yes | +| Delete attachment | Not available | Yes | +| Set field value in current item | Yes | Yes, using ‘Update an item’ action | +| Get changes for an item | No | Yes | ### File triggers -|List action |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| When a file is created | Yes, using List triggers | Yes | -| When a file is created in a folder | Not available | Yes | -| When a file is modified | Yes, using List triggers | Yes | -| When a file is created or modified | Not available | Yes | -| When a file is created or modified in a folder | Not available | Yes | -| When a file is deleted | Not available | Yes | -| For a selected file | Yes, using List triggers | Yes | +| List action | SharePoint workflow | Power Automate flow | +| :--------------------------------------------- | :----------------------- | :------------------ | +| When a file is created | Yes, using List triggers | Yes | +| When a file is created in a folder | Not available | Yes | +| When a file is modified | Yes, using List triggers | Yes | +| When a file is created or modified | Not available | Yes | +| When a file is created or modified in a folder | Not available | Yes | +| When a file is deleted | Not available | Yes | +| For a selected file | Yes, using List triggers | Yes | ### File actions -|File action |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Get files | Not available | Yes | -| Create file content | Not available | Yes | -| Get file properties | Not available | Yes | -| Create a file | Not available | Yes | -| Create new folder | Not available | Yes | -| Update file properties | Yes, using List triggers | Yes | -| Delete a file | Yes, using List triggers | Yes | -| Copy file | Not available | Yes | -| Copy folder | Not available | Yes | -| Move file | Not available | Yes | -| Get changes for a file (properties only) | No | Yes | +| File action | SharePoint workflow | Power Automate flow | +| :--------------------------------------- | :----------------------- | :------------------ | +| Get files | Not available | Yes | +| Create file content | Not available | Yes | +| Get file properties | Not available | Yes | +| Create a file | Not available | Yes | +| Create new folder | Not available | Yes | +| Update file properties | Yes, using List triggers | Yes | +| Delete a file | Yes, using List triggers | Yes | +| Copy file | Not available | Yes | +| Copy folder | Not available | Yes | +| Move file | Not available | Yes | +| Get changes for a file (properties only) | No | Yes | ### Document management actions -|Document management action |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Check in file | Yes | Yes | -| Check out file | Yes | Yes | -| Discard checkout | Yes | Yes | -| Delete drafts | Yes | Not available | -| Wait for change in document check out status | Yes | Not available | +| Document management action | SharePoint workflow | Power Automate flow | +| :------------------------------------------- | :------------------ | :------------------ | +| Check in file | Yes | Yes | +| Check out file | Yes | Yes | +| Discard checkout | Yes | Yes | +| Delete drafts | Yes | Not available | +| Wait for change in document check out status | Yes | Not available | ### Permissions management actions -|Permissions management action |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Grant access to an item or a folder | Yes | Yes | -| Stop sharing an item or a file | Yes | Yes | -| Create sharing link for a file or folder | Not available | Yes | +| Permissions management action | SharePoint workflow | Power Automate flow | +| :--------------------------------------- | :------------------ | :------------------ | +| Grant access to an item or a folder | Yes | Yes | +| Stop sharing an item or a file | Yes | Yes | +| Create sharing link for a file or folder | Not available | Yes | ### Approval actions -|Approval action |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Set content approval status of an item or a file or a page | Yes | Yes | -| Create and wait for approval for an item or a file | Yes | Yes | -| Include attachments in approval requests | Not available | Yes | -| Respond to approvals | Yes | Yes | -| Create sequential approvals | Yes | Yes | -| Create parallel approvals | Yes | Yes | -| Cancel approvals | Yes | Yes | -| Reassign approvals | Yes | Yes | -| Custom approval buttons | Yes | Yes | -| Unified approval center | Not available | Yes | +| Approval action | SharePoint workflow | Power Automate flow | +| :--------------------------------------------------------- | :------------------ | :------------------ | +| Set content approval status of an item or a file or a page | Yes | Yes | +| Create and wait for approval for an item or a file | Yes | Yes | +| Include attachments in approval requests | Not available | Yes | +| Respond to approvals | Yes | Yes | +| Create sequential approvals | Yes | Yes | +| Create parallel approvals | Yes | Yes | +| Cancel approvals | Yes | Yes | +| Reassign approvals | Yes | Yes | +| Custom approval buttons | Yes | Yes | +| Unified approval center | Not available | Yes | ### Workflow controls capabilities -|Workflow controls capability |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Workflow primitives: Loops, do until, switch-case, parallels | Yes | Yes | -| Workflow stage | Yes | Yes, works only with Modern Permissions | -| Schedule-based flows | Yes | Yes | -| Variables | Yes | Yes | -| Email designer and rich text editor | Not available | Yes | -| Versioning of workflows | Not available | Not available | -| Copy/paste actions |Yes | Yes | +| Workflow controls capability | SharePoint workflow | Power Automate flow | +| :----------------------------------------------------------- | :------------------ | :-------------------------------------- | +| Workflow primitives: Loops, do until, switch-case, parallels | Yes | Yes | +| Workflow stage | Yes | Yes, works only with Modern Permissions | +| Schedule-based flows | Yes | Yes | +| Variables | Yes | Yes | +| Email designer and rich text editor | Not available | Yes | +| Versioning of workflows | Not available | Not available | +| Copy/paste actions | Yes | Yes | ## Workflow administration -|Workflow administration |SharePoint workflow |Power Automate flow | -|:-------|:-------|:--------| -| Central location to view all workflows | Yes, only available to view for a given list or library | Yes, 'My flows' lists user flows | -| Share workflows with list or library users | Yes | Yes | -| Share workflows with users | Not available | Yes | -| Save a copy of workflow to create a copy of the workflow | Not available | Yes | -| Workflow versioning | Not available | No | -| Create a workflow with elevated permissions | Yes, by granting permissions to workflow app and then using App Step action and SharePoint Add-ins | Not available +| Workflow administration | SharePoint workflow | Power Automate flow | +| :------------------------------------------------------- | :------------------------------------------------------------------------------------------------- | :------------------------------- | +| Central location to view all workflows | Yes, only available to view for a given list or library | Yes, 'My flows' lists user flows | +| Share workflows with list or library users | Yes | Yes | +| Share workflows with users | Not available | Yes | +| Save a copy of workflow to create a copy of the workflow | Not available | Yes | +| Workflow versioning | Not available | No | +| Create a workflow with elevated permissions | Yes, by granting permissions to workflow app and then using App Step action and SharePoint Add-ins | Not available | diff --git a/docs/business-apps/power-automate/guidance/require-doc-approval.md b/docs/business-apps/power-automate/guidance/require-doc-approval.md index af7013884..c5c548834 100644 --- a/docs/business-apps/power-automate/guidance/require-doc-approval.md +++ b/docs/business-apps/power-automate/guidance/require-doc-approval.md @@ -1,7 +1,8 @@ --- title: Require approval of documents in SharePoint using Power Automate -ms.date: 05/19/2020 -search.app: +description: Documents that contain sensitive information often require approvals. With the content approval feature in SharePoint, you can put a simple approval process for documents in a specific document library. Using this content approval process, documents pending approval will not be visible to users until they are approved. +ms.date: 06/28/2022 +search.app: - Flow search.appverid: met150 --- @@ -51,7 +52,7 @@ The following actions occur: Using the following template, create a flow in Power Automate. -1. In the SharePoint library, from the command bar, select **Automate** > **Power Automate** > **Create a flow**. +1. In the SharePoint library, from the command bar, select **Integrate** > **Power Automate** > **Create a flow**. 1. Next, select the template: **When a new file is added in SharePoint, complete a custom action**. ![File add custom action](../../../images/create-flow-template-file-added.png) @@ -83,10 +84,10 @@ You must ensure you enter the correct site and library name. However, you can ge - Using the *Id* property from the *trigger output* - Comments - Using the *comments* property from the *approval response* - - ETAG -- Using the *ETag* property from the *Get file metadata* action output +- ETAG + - Using the *ETag* property from the *Get file metadata* action output -You can now use the content approval status action to approve and reject the document based on the approval response. +You can now use the content approval status action to approve or reject the document based on the approval response. The end result is that: @@ -100,4 +101,3 @@ The end result is that: ![Email approval status](../../../images/output-content-approval-status.png) This is an effective way to automate document approval in SharePoint using Power Automate! Use this procedure for list items and pages as well. - diff --git a/docs/business-apps/power-automate/guidance/working-with-get-items-and-get-files.md b/docs/business-apps/power-automate/guidance/working-with-get-items-and-get-files.md index 5656ad992..284490333 100644 --- a/docs/business-apps/power-automate/guidance/working-with-get-items-and-get-files.md +++ b/docs/business-apps/power-automate/guidance/working-with-get-items-and-get-files.md @@ -1,7 +1,8 @@ --- title: In-depth analysis into 'Get items' and 'Get files' SharePoint actions for flows in Power Automate -ms.date: 03/11/2020 -search.app: +description: In this article, learn more about the SharePoint actions get items & get files actions with Power Automate. +ms.date: 06/28/2022 +search.app: - Flow search.appverid: met150 --- @@ -15,7 +16,7 @@ The **Get items** and **Get files** SharePoint actions for flows in Power Automa First, and of primary consideration, the **Get items** action only works with lists, whereas the **Get files** action only works with libraries. ## Item limits -The default item limit is 100 and items are paginated by default as well. +The default item limit is 100 and items are paginated by default as well. If you are using the default options, and simply specifying the site address and list or library name, Power Automate returns 100 items from the list or library. @@ -29,7 +30,7 @@ If you go beyond 5,000 item limit, Power Automate fails and generates an error d ## Limit items to a specific folder By default, this action returns all items or files in the list or library, recursively, from all folders, if available. You can change this behavior by doing the following: -* To select a specific folder in the list or library, use _Limit Entries_ to Folder property. +* To select a specific folder in the list or library, use _Limit Entries_ to Folder property. * To limit entries to that specific folder or within all sub-folders, use _Include Nested Items_ property. ![Limit entries to folder in Get items action](../../../images/flow-get-items-limit-entries-to-folder.png) @@ -65,7 +66,7 @@ Other examples: * startswith(Title, 'A') and Start_x0020_Date gt 'formatDateTime(utcNow(),'yyyy-MM-dd')' * formatDateTime(utcNow(),'yyyy-MM-dd') is an expression. * Country/Title eq 'New Zealand' - * Country is a lookup column in the list and Title is a column in the referenced list. + * Country is a lookup column in the list and Title is a column in the referenced list. ![ODATA filter queries in Get items action](../../../images/flow-get-items-filter-query.png) @@ -91,14 +92,6 @@ We support the following query methods and operators. * eq * ne -### Date and time functions -* day() -* month() -* year() -* hour() -* minute() -* second() - ## Order by query To order items based off of a column either in ascending or descending order, you can also specify an order by query. For example: @@ -111,4 +104,5 @@ Spaces in the column name are replaced with `_x0020_` (0 is numeral zero). The format is the column name followed by asc or desc depending on ascending or descending order, respectively. - +### Known Limitation +While using Get items on lists with more than 5000 items with a filter query, you may observe that no records are returned if there are no items matching the filter query in the first 5000 items. To fix this, enable Pagination on Get items from the action settings menu when working with lists with more than 5000 items. diff --git a/docs/business-apps/power-automate/guidance/working-with-send-sp-http-request.md b/docs/business-apps/power-automate/guidance/working-with-send-sp-http-request.md index 208b87abc..18c911428 100644 --- a/docs/business-apps/power-automate/guidance/working-with-send-sp-http-request.md +++ b/docs/business-apps/power-automate/guidance/working-with-send-sp-http-request.md @@ -1,12 +1,13 @@ --- title: Working with the SharePoint Send HTTP Request flow action in Power Automate -ms.date: 03/11/2020 -search.app: +description: In Power Automate, the SharePoint Send HTTP Request flow action lets you construct and execute SharePoint REST API queries. +ms.date: 01/27/2023 +search.app: - Flow search.appverid: met150 --- - # Working with the SharePoint Send HTTP Request flow action in Power Automate + In Power Automate, the SharePoint Send HTTP Request flow action lets you construct and execute SharePoint REST API queries. This action is particularly useful in cases where the existing SharePoint flow actions do not handle your requirements, or the action you are looking for is not yet available in the SharePoint connector. ![Send an HTTP Request to SharePoint action](../../../images/flow-send-http-request-to-sp-action.png) @@ -15,14 +16,18 @@ To work effectively with the SharePoint Send HTTP Request action, see the follow > [!NOTE] > This is a developer-focused action. You must understand how SharePoint REST API works and also how to parse JSON strings in Power Automate. +> +> Additionally, this action only supports SharePoint REST APIs (excluding any deprecated APIs), if you need to access another Microsoft service, you will need to leverage the "HTTP with Microsoft Entra ID" connector. ## Get to know the SharePoint REST/OData APIs -SharePoint has many APIs. The focus here is the REST/OData APIs. For the complete set of REST/OData APIs, see [Get to know the SharePoint REST service](https://docs.microsoft.com/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service#bk_learnmore). + +SharePoint has many APIs. The focus here is the REST/OData APIs. For the complete set of REST/OData APIs, see [Get to know the SharePoint REST service](/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service#bk_learnmore). Although, in some cases, you can use the SharePoint 2010 REST APIs *(_vti_bin/listdata.svc)*, we recommend using REST/OData APIs instead. ## Use JSON light -SharePoint REST/OData APIs support [JSON light](https://www.microsoft.com/microsoft-365/blog/2014/08/13/json-light-support-rest-sharepoint-api-released/). This means that you can set headers in your API request that inform SharePoint whether to include any metadata in the response. In many cases, you do not require the metadata. Metadata makes things simpler to parse the output of the action. + +SharePoint REST/OData APIs support [JSON light](https://www.microsoft.com/en-us/microsoft-365/blog/2014/08/13/json-light-support-rest-sharepoint-api-released/). This means that you can set headers in your API request that inform SharePoint whether to include any metadata in the response. In many cases, you do not require the metadata. Metadata makes things simpler to parse the output of the action. To do this, just add the following header: @@ -31,6 +36,7 @@ Accept: application/json; odata=nometadata ``` ## Parse the response + If you execute a GET request, you generally want to parse the response. The default response is JSON, making execution simpler. Parse the response by querying the body of the action, and then parsing through the JSON array or object depending on your response. diff --git a/docs/business-apps/power-automate/sharepoint-connector-actions-triggers.md b/docs/business-apps/power-automate/sharepoint-connector-actions-triggers.md index 1486400ae..6566e5ef0 100644 --- a/docs/business-apps/power-automate/sharepoint-connector-actions-triggers.md +++ b/docs/business-apps/power-automate/sharepoint-connector-actions-triggers.md @@ -1,8 +1,9 @@ --- title: Microsoft SharePoint Connector for Power Automate description: In Power Automate, Microsoft SharePoint Connector supports the following flow triggers and actions. -ms.date: 06/10/2021 -search.app: +ms.date: 10/23/2024 +ms.service: power-automate +search.app: - Flow search.appverid: met150 --- @@ -25,13 +26,13 @@ Triggers the flow when you create an item, and each time you modify it in a Shar ### When an item or a file is modified -Triggers the flow when you modify an item or a file in a SharePoint list or a document library. +Triggers the flow when you modify an item or a file in a SharePoint list or a document library. For more info about how to use this trigger, see this tutorial video: [Introducing 'when an item or file modified' trigger and 'Get changes' action](https://youtu.be/AaWB3xlhJdc) ### When an item is deleted -Triggers the flow when you delete an item in a list. To get the properties of a deleted item, you must connect this trigger to the associated SharePoint site on which it is expected to run, using a site collection user account. +Triggers the flow when you delete an item in a list. To get the properties of a deleted item, you must connect this trigger to the associated SharePoint site on which it is expected to run, using a site collection admin account. ### For a selected item @@ -40,30 +41,36 @@ Allows users of lists to trigger a flow after selecting an item in a list. > [!NOTE] > Only flows within the default environment can be executed manually from a SharePoint list. -### When a file is classified by a content understanding model -Triggers the flow when a SharePoint Syntex content understanding model classifies a file, shown in the classification date property of the file. +### When a file is classified by a content understanding model +Triggers the flow when a Microsoft Syntex content understanding model classifies a file, shown in the classification date property of the file. -For more info about when SharePoint Syntex and how it classifies files see: [Introduction to Microsoft SharePoint Syntex](/microsoft-365/contentunderstanding) +For more info about when Microsoft Syntex and how it classifies files see: [Introduction to Microsoft Microsoft Syntex](/microsoft-365/contentunderstanding) ### When a file is created (properties only) -Triggers the flow when you create a file in a document library, and returns only the custom file properties associated with that file. +Triggers the flow when you create a file in a document library and returns only the custom file properties associated with that file. -### When a file is created in a folder +### When a file is created in a folder [deprecated] + +> [!NOTE] +> This trigger is deprecated and may not work as expected. Triggers the flow when you create a file in a SharePoint folder. This trigger does not run if you add or update a file in a subfolder inside the folder this trigger is operating on. If the flow is required to trigger on subfolders, create different flows for one or more subfolder(s). ### When a file is created or modified (properties only) -Triggers the flow when you create a file, and each time you modify the file properties in a library. Returns only the custom file properties associated with that file. +Triggers the flow when you create a file, and each time you modify the file properties in a library. Specify a value in the "Folder" property to target a specific folder; otherwise, the trigger applies to the entire library. Returns only the custom file properties associated with that file. -### When a file is created or modified in a folder (properties only) +### When a file is created or modified in a folder [deprecated] + +> [!NOTE] +> This trigger is deprecated and may not work as expected. -Triggers the flow when you create a file, and each time you modify the file properties in the selected SharePoint folder. The trigger does not activate if you add or update a file in a subfolder. If the flow is required to trigger on subfolders, create different flows for one or more subfolder(s). +Triggers when a file is created, and also each time it is modified in a SharePoint folder. The trigger does not fire if a file is added/updated in a subfolder. If it is required to trigger on subfolders, multiple triggers should be created. ### When a file is deleted -Triggers the flow when you delete a file in a document library. You can optionally specify a folder to watch. When you delete a folder, the trigger activates only once for the deleted folder, including its subfolders. To get the properties of the deleted file, you must connect this trigger to the associated SharePoint site on which the trigger is epxected to run, using a site collection user account. +Triggers the flow when you delete a file in a document library. You can optionally specify a folder to watch. When you delete a folder, the trigger activates only once for the deleted folder, including its subfolders. To get the properties of the deleted file, you must connect this trigger to the associated SharePoint site on which the trigger is expected to run, using a site collection admin account. ### For a selected file @@ -92,7 +99,7 @@ Cancels hub join request. If applicable, specify the same Approval Correlation I ### Check in file -Checks in a checked out file in a document library, which makes the version of the document available to others. +Checks in a checked-out file in a document library, which makes the version of the document available to others. ### Check out file @@ -102,7 +109,10 @@ Checks out a file in a document library to prevent others from editing the docum Copies a file. Works similarly to the **Copy to** command in SharePoint libraries. After copying, returns info about the new file. -### Copy file (deprecated) +### Copy file [deprecated] + +> [!NOTE] +> This action is deprecated and may not work as expected. Copies a file to a SharePoint site. @@ -162,14 +172,14 @@ Returns the list of attachments for the specified list item. To get to the conte Gets all the columns or file properties changed since and until a specified time interval. To get all the columns changed when an item or a file is modified: - Use the _when an item or file is modified_ trigger, and, -- Use the _Trigger Window Start Token_ & _Trigger Window End Token_ outputs from the _when an item or file is modified_ trigger to infer what columnns changed since last time flow checked for item or file updates. +- Use the _Trigger Window Start Token_ & _Trigger Window End Token_ outputs from the _when an item or file is modified_ trigger to infer what columns changed since the last time flow checked for item or file updates. For more info about how to use this action, see this tutorial video: [Introducing 'when an item or file modified' trigger and 'Get changes' action](https://youtu.be/AaWB3xlhJdc) > [!NOTE] -> - The list or library should have versioning configured in order to infer what columns or properties got modified since last change. -> - Only column changes are suported for lists and libraries. -> - File content changes are not supported. +> - The list or library should have versioning configured in order to infer what columns or properties got modified since last change. +> - Only column changes are supported for lists and libraries. +> - File content changes are not supported. > - Attachment changes are not supported. > - _Trigger Window Start Token_ & _Trigger Window End Token_ are only available when you use _when an item or file is modified_ trigger. @@ -227,7 +237,7 @@ Grants access to an item or a folder in SharePoint to specific people. ### Join hub site -Joins the requested site to the hub site. An Approval Token is required to complete the join successfully, if that hub requires approval. If applicable, specify the same Approval Correlation Id as used in the **Set hub site join status to pending** action. +Joins the requested site to the hub site. An Approval Token is required to complete the join successfully if that hub requires approval. If applicable, specify the same Approval Correlation Id as used in the **Set hub site join status to pending** action. ### List folder @@ -247,7 +257,7 @@ Moves a folder. Works similarly to the **Move to** command in SharePoint librari ### Resolve person -Returns a single matching user value so it can be assigned to a column of type person. If there are no matches, or multiple matches, this action errors out. +Returns a single matching user value so it can be assigned to a column of type person. If there are no matches or multiple matches, this action errors out. ### Send an HTTP request to SharePoint @@ -298,7 +308,7 @@ The following tables list all of the actions and triggers that are supported for | When a file is deleted | No | No | Yes2 | | Resolve Person | No | No | Yes | | Set content approval status | No | No | Yes | - + > [!NOTE] > 1. Does not support “Limit Columns by View”. > 1. While this trigger is supported for SharePoint 2019, flows created using this trigger may encounter the following issues: @@ -317,7 +327,7 @@ The following tables list all of the actions and triggers that are supported for | Get file content | Yes | Yes | Yes | | Create file | Yes1 | Yes1 | Yes1 | | Update file | Yes | Yes | Yes | -| Copy file (deprecated)2| Yes | Yes | Yes | +| Copy file [deprecated]2| Yes | Yes | Yes | | List folder | Yes | Yes | Yes | | Extract folder | Yes | Yes | Yes | | Get attachments | Yes | Yes | Yes | @@ -332,18 +342,19 @@ The following tables list all of the actions and triggers that are supported for > [!NOTE] > 1. Does not support creating a large file by uploading it as a set of chunks. -> 1. This action includes "(deprecated)" in its display name. The "Copy file" action is different from this action. +> 1. This action includes "[deprecated]" in its display name. The "Copy file" action is different from this action. > 1. This action only supports OData parameters, which excludes parameters such as "Limit Entries to Folder", "Include Nested Items", and "Limit Columns by View". > 1. Does not support “Limit Columns by View”. -### Deprecated triggers +### Deprecated triggers and actions These triggers are deprecated and are no longer actively maintained. While they are still present in the Microsoft SharePoint Connector, we recommend not utilizing deprecated triggers or actions in any new applications or solutions. -| Trigger | Supported Version | Suggested Alternative | -| :-- | :-- | :-- | -| When a file is created in a folder | SharePoint 2019 | When a file is created (properties only) | -| When a file is created or modified in a folder | SharePoint 2019 | When a file is created or modified (properties only) | +| Name | Type | Supported Version | Suggested Alternative | +| :-- | :-- | :-- | :-- | +| When a file is created in a folder [deprecated] | Trigger |SharePoint 2019 | When a file is created (properties only) | +| When a file is created or modified in a folder [deprecated] | Trigger | SharePoint 2019 | When a file is created or modified (properties only) | +| Copy file [deprecated] | Action | SharePoint 2019 | Copy file | ## Known limitations @@ -357,9 +368,9 @@ When you build a Power Automate flow to be triggered for an item, or for creatin ### Move files and flow runs -When you move one or more files from one document library to another, the original file is moved from the source library to the destination library. Moving the file does not alter any custom metadata, including when the file was created and modified. Hence, this action does not trigger any flows for those file updates associated in the library where it was moved. +When you move one or more files from one document library to another, the original file is moved from the source library to the destination library. Moving the file does not alter any custom metadata, including when the file was created and modified. Hence, this action does not trigger any flows for those file updates associated with the library where it was moved. -### Syncing files to your OneDrive for business and SharePoint document libraries +### Syncing files to your OneDrive for Business and SharePoint document libraries When users sync one or more files from one document library to another, the original file is moved (synced) from your client to the destination library. Syncing the file will not alter any custom metadata including when the file was created and modified. Hence, this action will not trigger any flows for those file syncs in that library or in your OneDrive for business. diff --git a/docs/community/community.md b/docs/community/community.md index 324b68122..79d2ffccc 100644 --- a/docs/community/community.md +++ b/docs/community/community.md @@ -1,14 +1,14 @@ --- title: SharePoint Developer Community (SharePoint PnP) resources description: The SharePoint Development Community (also known as the SharePoint PnP community) is an open-source initiative coordinated by SharePoint engineering. -ms.date: 02/14/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 06/09/2022 +ms.service: sharepoint-online +ms.localizationpriority: high --- -# SharePoint Developer Community (SharePoint PnP) resources +# Microsoft 365 Platform Community (PnP) resources around SharePoint Framework -The SharePoint Development Community (also known as the SharePoint PnP community) is an open-source initiative coordinated by SharePoint engineering. This community controls SharePoint development documentation, samples, reusable controls, and other relevant open-source initiatives related to SharePoint development. +The Microsoft 365 Platform Community (also known as M365 PnP community) is an open-source initiative coordinated by Microsoft 365 engineering. This community controls SharePoint development documentation, samples, reusable controls, and other relevant open-source initiatives related to SharePoint development. ## Blog posts, videos, and social media @@ -17,7 +17,7 @@ The SharePoint Development Community (also known as the SharePoint PnP community - [Microsoft 365 Dev Twitter](https://twitter.com/Microsoft365Dev) - Official communication channel for SharePoint, Office 365, Windows 10 and Enterprise Mobility + Security developer topics - [Microsoft 365 PnP Twitter](https://twitter.com/m365pnp) - Community account for Microsoft 365 and SharePoint topics - [Microsoft 365 Dev Facebook](https://www.facebook.com/Microsoft365Developer) - Official communication channel for SharePoint, Office 365, Windows 10 and Enterprise Mobility + Security developer topics -- [Microsoft 365 PnP Facebook](https://www.facebook.com/OfficeDevPnP/) - Community account for SharePoint and Office 365 developer topics +- [Microsoft 365 PnP Facebook](https://www.facebook.com/Microsoft365/community) - Community account for SharePoint and Office 365 developer topics ## GitHub @@ -37,15 +37,15 @@ Found an issue related to SharePoint development around the APIs, documentation, There are numerous community calls for SharePoint development, and you can choose which of them you'd like to join based on your interest and availability. Each call has live demos from SharePoint Engineering, MVPs, or other community members. > [!TIP] -> If you are interested in doing a live demo in any of our community calls, please reach out by leaving a comment on this page and we'll get you a spot for 10-15 minutes for demonstrating your SharePoint development topic(s). +> If you are interested in doing a live demo in any of our community calls, please reach out by [requesting a demo slot](https://aka.ms/community/request/demo) and we'll get you a spot for 10-15 minutes for demonstrating your Microsoft 365 & Power Platform development topic(s). > > **Do's & Dont's**: Interested in presenting during one of the community calls? Keep in mind these are community calls. The focus of these demos should be on learning and topics beneficial to the community. Please refrain from commercial activities such as selling or promoting products or services. Commercial activities in the community calls are not well received by the community and in certain instances may result in stopping the demo early. In your request to present, please be descriptive about what you intend to show to avoid any confusion. If you are not sure if what you want to present is appropriate, just ask in the submission. | Community call | When | Description | Microsoft Teams Link | | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | -| [Monthly community call](https://aka.ms/sppnp-call) | Second Tuesday of each month at 8:00 AM PT / 3:00 PM GMT | Monthly community call covering the latest changes in SharePoint development-related topics within the last month, including news, UserVoice updates, and community contributions | [Direct MS Teams link to meeting](https://aka.ms/spdev-call-join) | -| [Special interest group call for SharePoint Framework](https://aka.ms/spdev-spfx-call) | Bi-weekly on Thursdays at 7:00 AM PT / 2:00 PM GMT | SharePoint Engineering updates, SharePoint Framework, PnPJS, CLI for Microsoft 365, and reusable SPFx controls | [Direct MS Teams link to meeting](https://aka.ms/spdev-spfx-call-join) | -| [Special interest group call for general SharePoint development](https://aka.ms/spdev-sig-call) | Bi-weekly on Thursdays at 7:00 AM PT / 2:00 PM GMT | SharePoint Engineering updates, end-to-end solution designs, provisioning, PnP CSOM, and PnP PowerShell | [Direct MS Teams link to meeting](https://aka.ms/spdev-sig-call-join) | +| [Microsoft 365 & Power Platform Call (Microsoft Speakers)](https://aka.ms/community/ms-speakers-call-invite) | Weekly on Tuesdays at 8:00 AM PT / 3:00 PM GMT | Community call with Microsoft speakers covering the latest news from Microsoft engineerung on the Microsoft 365 & Power Platform topics including news, UserVoice updates, and demos | [Direct MS Teams link to meeting](https://aka.ms/community/ms-speakers-call-join) | +| [Viva Connections and SharePoint Framework community call](https://aka.ms/spdev-spfx-call) | Bi-weekly on Thursdays at 7:00 AM PT / 2:00 PM GMT | SharePoint Engineering updates, SharePoint Framework, PnPJS, CLI for Microsoft 365, and reusable SPFx controls | [Direct MS Teams link to meeting](https://aka.ms/spdev-spfx-call-join)| +| [Microsoft 365 & Power Platform Development Community call](https://aka.ms/community/m365-powerplat-dev-call-invite) | Bi-weekly on Thursdays at 7:00 AM PT / 2:00 PM GMT | Latest on Latest on PnP Framework and Core SDK extension, PnP PowerShell, yo Teams, Microsoft Graph Toolkit, Independent Publisher Connector Updates plus community demos | [Direct MS Teams link to meeting](https://aka.ms/community/m365-powerplat-dev-call-join) | ## What’s the supportability statement around PnP open-source components and solutions? diff --git a/docs/community/contribute.md b/docs/community/contribute.md index 48d6ee952..dfe50aef8 100644 --- a/docs/community/contribute.md +++ b/docs/community/contribute.md @@ -1,9 +1,8 @@ --- title: SharePoint Developer Community contribution description: Contribution options towards the SharePoint Developer Community. -ms.date: 02/14/2020 -ms.prod: sharepoint -localization_priority: Normal +ms.date: 06/07/2022 +ms.localizationpriority: medium --- # SharePoint Developer Community - How to contribute @@ -15,7 +14,7 @@ There are multiple ways to contribute to the SharePoint Developer Community (Sha * Do a live demo of your sample, solution, or architecture design in the SharePoint community calls. * Report and fix issues within the GitHub repositories in the [SharePoint GitHub Organization](http://github.com/sharepoint). * Report issues in the GitHub issue lists to help others find where they can assist. -* Provide input on new feature requests within [SharePoint Developer UserVoice](https://sharepoint.uservoice.com/forums/329220-sharepoint-dev-platform). +* Provide input on new feature requests within [Feedback Portal: SharePoint](https://feedbackportal.microsoft.com/feedback/forum/06735c62-321c-ec11-b6e7-0022481f8472).. ## FAQ diff --git a/docs/community/open-source-projects.md b/docs/community/open-source-projects.md index 488d95d5c..e3f81365e 100644 --- a/docs/community/open-source-projects.md +++ b/docs/community/open-source-projects.md @@ -1,9 +1,8 @@ --- title: SharePoint Developer Community open source projects description: Open-source projects coordinated by the SharePoint PnP initiative -ms.date: 09/07/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 06/07/2022 +ms.localizationpriority: high --- # SharePoint Developer Community - Open-source projects @@ -13,7 +12,7 @@ There are numerous open-source projects that are coordinated by the SharePoint P | Repository | Description | |--------|--------| | [SharePoint Starter kit](https://github.com/SharePoint/sp-starter-kit) | A starter kit for showing how to extend modern experiences in SharePoint Online by extending them with modern extensibility options. | -| [SharePoint Provisioning Service templates](https://github.com/SharePoint/sp-dev-provisioning-templates) | Tenant templates used by the [SharePoint Provisioning Service](https://provisioning.sharepointpnp.com) to easily provision sample content and structures demonstrating what's possible with modern SharePoint experiences. | +| [SharePoint Provisioning Service templates](https://github.com/SharePoint/sp-dev-provisioning-templates) | Tenant templates previously used by the Look Book Services to easily provision sample content and structures demonstrating what's possible with modern SharePoint experiences. | | [CLI for Microsoft 365](https://pnp.github.io/cli-microsoft365/) | A cross-platform command-line interface (CLI) that allows users on any platform to manage their Microsoft 365 and SharePoint Framework projects. | | [Office 365 Developer PnP Core Component](https://github.com/SharePoint/PnP-Sites-Core) | An extension component that encapsulates commonly used remote CSOM/REST operations as reusable extension methods on out-of-the box CSOM objects. | | [PnP PowerShell cmdlets](/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets) | Allow you to perform complex provisioning and artifact management actions for SharePoint. The commands use CSOM and can work against both SharePoint Online as well as SharePoint on-premises. | diff --git a/docs/community/repositories.md b/docs/community/repositories.md index c7b0df8d0..7f09fcba3 100644 --- a/docs/community/repositories.md +++ b/docs/community/repositories.md @@ -1,9 +1,8 @@ --- title: SharePoint Developer GitHub repositories description: List of different SharePoint Developer GitHub repositories and their description -ms.date: 03/29/2018 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 09/23/2022 +ms.localizationpriority: high --- # SharePoint Developer GitHub repositories @@ -20,7 +19,7 @@ There are numerous SharePoint Developer GitHub repositories, which all have diff | Repository | Description | |--------|--------| -| [sp-dev-docs](https://github.com/SharePoint/sp-dev-docs) | Source for SharePoint dev documentation exposed at `https://docs.microsoft.com/sharepoint/dev/` | +| [sp-dev-docs](https://github.com/SharePoint/sp-dev-docs) | Source for SharePoint dev documentation exposed at `https://learn.microsoft.com/sharepoint/dev/` | | [sp-dev-fx-webparts](https://github.com/SharePoint/sp-dev-fx-webparts) | Samples and tutorial code around SharePoint Framework client-side web parts | | [sp-dev-fx-extensions](https://github.com/SharePoint/sp-dev-fx-extensions) | Samples and tutorial code around SharePoint Framework extensions | | [sp-dev-modernization](https://github.com/SharePoint/sp-dev-modernization) | Solutions, tools and script to help you modernize your sites | @@ -46,7 +45,7 @@ There are numerous SharePoint Developer GitHub repositories, which all have diff | [pnp-partner-pack](https://github.com/SharePoint/PnP-Partner-Pack) | Packaged guidance with detailed instructions about setting things up in Office 365 and Azure | | [pnp-js-core](https://github.com/SharePoint/PnP-JS-Core) | Office Dev PnP Core component for JavaScript | | [pnp-transformation](https://github.com/SharePoint/PnP-Transformation) | Material specifically for the transformation process. Currently, includes samples around InfoPath replacement and transformation tooling from farm solutions to the add-in model | -| [pnp-js-provisioning](https://github.com/SharePoint/pnp-js-provisioning) | Repository for planned JavaScript provisioning library | +| [pnp-js-provisioning](https://github.com/pnp/sp-js-provisioning) | Repository for planned JavaScript provisioning library | | [pnp-provisioning-templates](https://github.com/SharePoint/PnP-Provisioning-Templates) | Repository for provisioning templates. | [pnp-guidance](https://github.com/SharePoint/PnP-Guidance) | Old repository on guidance, presentations, and articles that were partially synced to MSDN | | [pnp-identitymodel](https://github.com/SharePoint/PnP-IdentityModel) | Open source replacement of Microsoft.IdentityModel.Extensions.dll | diff --git a/docs/community/social-media.md b/docs/community/social-media.md index 57f729dce..de4293a18 100644 --- a/docs/community/social-media.md +++ b/docs/community/social-media.md @@ -1,11 +1,11 @@ --- title: Social Media +description: Please monitor and follow the Microsoft 365 community and Microsoft 365, Office, and SharePoint developers on social media. author: andrewconnell ms.author: v-johnco -ms.date: 2/5/2020 +ms.date: 06/03/2022 ms.audience: Developer -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # SharePoint Development on Social Media diff --git a/docs/declarative-customization/column-formatting.md b/docs/declarative-customization/column-formatting.md index 038cb0b30..7e933a74c 100644 --- a/docs/declarative-customization/column-formatting.md +++ b/docs/declarative-customization/column-formatting.md @@ -1,15 +1,15 @@ --- title: Use column formatting to customize SharePoint description: Customize how fields in SharePoint lists and libraries are displayed by constructing a JSON object that describes the elements that are displayed when a field is included in a list view, and the styles to be applied to those elements. -ms.date: 06/16/2021 -localization_priority: Priority +ms.date: 09/08/2022 +ms.localizationpriority: high --- # Use column formatting to customize SharePoint -You can use column formatting to customize how fields in SharePoint lists and libraries are displayed. To do this, you construct a JSON object that describes the elements that are displayed when a field is included in a list view, and the styles to be applied to those elements. The column formatting does not change the data in the list item or file; it only changes how it’s displayed to users who browse the list. Anyone who can create and manage views in a list can use column formatting to configure how view fields are displayed. +You can use column formatting to customize how fields in SharePoint lists and libraries are displayed. To do this, you construct a JSON object that describes the elements that are displayed when a field is included in a list view, and the styles to be applied to those elements. The column formatting doesn't change the data in the list item or file; it only changes how it’s displayed to users who browse the list. Anyone who can create and manage views in a list can use column formatting to configure how view fields are displayed. -For example, a list with the fields Title, Effort, Assigned To, and Status with no customizations applied might look like this: +For example, a list with the fields Title, Effort, Assigned To, and Status with no customizations applied might look like this: ![SharePoint list with four unformatted columns](../images/sp-columnformatting-none.png) @@ -22,19 +22,19 @@ A list with the appearance of the **Effort**, **Assigned To**, and **Status** fi ## How is column formatting different than the Field Customizer? -Both column formatting and [SharePoint Framework Field Customizer](../spfx/extensions/get-started/building-simple-field-customizer.md) extensions enable you to customize how fields in SharePoint lists are displayed. The Field Customizer is more powerful because you can use it to write any code that you want to control how a field is displayed. +Both column formatting and [SharePoint Framework Field Customizer](../spfx/extensions/get-started/building-simple-field-customizer.md) extensions enable you to customize how fields in SharePoint lists are displayed. The Field Customizer is more powerful because you can use it to write any code that you want to control how a field is displayed. -Column formatting is more easily and broadly applied. However, it is less flexible, because it does not allow for custom code; it only allows for certain predefined elements and attributes. +Column formatting is more easily and broadly applied. However, it's less flexible, because it doesn't allow for custom code; it only allows for certain predefined elements and attributes. The following table compares column formatting and the Field Customizer. | Field type | Column formatting | Field Customizer | | ------------- |:-------------| :-----| | Conditional formatting based on item values and value ranges | Supported | Supported | -| Action links | Support for static hyperlinks that do not launch script | Support for any hyperlink, including those that invoke custom script | +| Action links | Support for static hyperlinks that don't launch script | Support for any hyperlink, including those that invoke custom script | | Data visualizations | Support for simple visualizations that can be expressed using HTML and CSS | Support for arbitrary data visualizations | -If you can accomplish your scenario by using column formatting, it’s typically quicker and easier to do that than to use a Field Customizer. Anyone who can create and manage views in a list can use column formatting to create and publish customizations. Use a Field Customizer for more advanced scenarios that column formatting does not support. +If you can accomplish your scenario by using column formatting, it’s typically quicker and easier to do that than to use a Field Customizer. Anyone who can create and manage views in a list can use column formatting to create and publish customizations. Use a Field Customizer for more advanced scenarios that column formatting doesn't support. ## Get started with column formatting @@ -51,7 +51,7 @@ To preview the formatting, select **Preview**. To commit your changes, select ** The easiest way to use column formatting is to start from an example and edit it to apply to your specific field. The following sections contain examples that you can copy, paste, and edit for your scenarios. There are also several samples available in the [SharePoint/sp-dev-column-formatting repository](https://github.com/SharePoint/sp-dev-column-formatting). > [!NOTE] -> All examples in this document refer to the JSON schema used in SharePoint Online. To format columns on SharePoint 2019, please use `https://developer.microsoft.com/json-schemas/sp/v1/column-formatting.schema.json` as the schema. +> All examples in this document refer to the JSON schema used in SharePoint Online and SharePoint Server Subscription Edition starting with the Version 22H2 feature update. To format columns in SharePoint 2019 or SharePoint Server Subscription Edition before the Version 22H2 feature update, please use `https://developer.microsoft.com/json-schemas/sp/v1/column-formatting.schema.json` as the schema. ## Display field values (basic) @@ -174,7 +174,7 @@ The following image shows a field with conditional date formatting applied: ![Status field with the Overdue text colored red](../images/sp-columnformatting-overdue.png) -This example colors the current field red when the value inside an item's DueDate is before the current date/time. Unlike some of the previous examples, this example applies formatting to one field by looking at the value inside another field. Note that DueDate is referenced using the `[$FieldName]` syntax. FieldName is assumed to be the internal name of the field. This example also takes advantage of a special value that can be used in date/time fields - `@now`, which resolves to the current date/time, evaluated when the user loads the list view. +This example colors the current field red when the value inside an item's DueDate is before the current date/time. Unlike some of the previous examples, this example applies formatting to one field by looking at the value inside another field. Note that `DueDate` is referenced using the `[$FieldName]` syntax. FieldName is assumed to be the internal name of the field. This example also takes advantage of a special value that can be used in date/time fields - `@now`, which resolves to the current date/time, evaluated when the user loads the list view. > [!NOTE] > If you have spaces in the field name, those are defined as `_x0020_`. For example, a field named "Due Date" should be referenced as `$Due_x0020_Date`. @@ -193,7 +193,7 @@ This example colors the current field red when the value inside an item's DueDat ### Formatting items based on arbitrary dates (advanced) -To compare the value of a date/time field against a date that's not `@now`, follow the pattern in the following example. The following example colors the current field red if the due date was <= tomorrow. This is accomplished using date math. You can add milliseconds to any date and the result will be a new date. For example, to add a day to a date, you'd add (24\*60\*60\*1000 = 86,400,000). +To compare the value of a date/time field against a date that's not `@now`, follow the pattern in the following example. The following example colors the current field red if the due date was <= tomorrow. This is accomplished using date math. You can add milliseconds to any date and the result will be a new date. For example, to add a day to a date, you'd add (24\*60\*60\*1000 = 86,400,000). This example demonstrates an alternate syntax to express a conditional expression, using the ternary (`?`) operator inside an abstract syntax tree. @@ -289,7 +289,9 @@ Here's the same sample from above, using the Excel-style expression syntax: ## Create clickable actions -You can use column formatting to provide hyperlinks that go to other webpages, or start custom functionality. This functionality is limited to static links that can be parameterized with values from fields in the list. You can't use column formatting to output links to protocols other than `http://`, `https://`, or `mailto:`. +You can use column formatting to provide hyperlinks that go to other webpages, or start custom functionality. This functionality is limited to static links that can be parameterized with values from fields in the list. You can't use column formatting to output links to protocols other than `http://`, `https://`, `mailto:` or `tel:`. + +`tel:` protocol only allows digits, `*+#` special characters and `.-/()` visual separators. ### Turn field values into hyperlinks (basic) @@ -322,7 +324,7 @@ The following image shows action buttons added to a field. You can use column formatting to render quick action links next to fields. The following example, intended for a person field, renders two elements inside the parent `
` element: - A `` element that contains the person’s display name. -- An `` element that opens a mailto: link that creates an email with a subject and body populated dynamically via item metadata. The `` element is styled using the `ms-Icon`, `ms-Icon—Mail`, and `ms-QuickAction` [Fluent UI](https://developer.microsoft.com/fluentui) classes to make it look like a clickable email icon. +- An `` element that opens a mailto: link that creates an email with a subject and body populated dynamically via item metadata. The `` element is styled using the `ms-Icon`, `ms-Icon—Mail`, and `ms-QuickAction` [Fluent UI](https://developer.microsoft.com/fluentui) classes to make it look like a clickable email icon. ```JSON { @@ -338,6 +340,9 @@ You can use column formatting to render quick action links next to fields. The f }, { "elmType": "a", + "style": { + "text-decoration": "none" + }, "attributes": { "iconName": "Mail", "class": "sp-field-quickActions", @@ -472,7 +477,7 @@ Here's the same sample from above, using the Excel-style expression syntax: "elmType": "span", "attributes": { "class": "=if([$After] > [$Before], 'sp-field-trending--up', 'sp-field-trending--down')", - "iconName": "=if([$After] > [$Before], 'SortUp', "if([$After] < [$Before], 'SortDown', ''))" + "iconName": "=if([$After] > [$Before], 'SortUp', if([$After] < [$Before], 'SortDown', ''))" } }, { @@ -483,56 +488,6 @@ Here's the same sample from above, using the Excel-style expression syntax: } ``` -## Create a button to launch a Flow - -The following screenshot shows a list with a Flow button added to the Action column: - -![screenshot of the sample](../images/sp-columnformatting-flow.png) - -You can use column formatting to create buttons that, when selected, run Flows on the corresponding list item. The Flow Launch Panel will be displayed after choosing the button and the Flow will just run. - -To use the sample below, you must substitute the ID of the Flow you want to run. This ID is contained within the `customRowAction` attribute inside the `button` element. To obtain a Flow's ID: - -1. Choose Flow > See your flows in the SharePoint list where the Flow is configured. -2. Choose the Flow you want to run. -3. Copy the ID from the end of the URL. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "button", - "customRowAction": { - "action": "executeFlow", - "actionParams": "{\"id\": \"edf627d9-20f4-45ba-8bc9-4494bf2ff1be\"}" - }, - "attributes": { - "class": "ms-fontColor-themePrimary ms-fontColor-themeDarker--hover" - }, - "style": { - "border": "none", - "background-color": "transparent", - "cursor": "pointer" - }, - "children": [ - { - "elmType": "span", - "attributes": { - "iconName": "Flow" - }, - "style": { - "padding-right": "6px" - } - }, - { - "elmType": "span", - "txtContent": "Send to Manager" - } - ] -} -``` - -Additionally, you can use `headerText` and `runFlowButtonText` options within the `actionParams` property to customize portions of the Flow panel itself! See the [button elements](#button-elements) portion of the Detailed syntax reference for more details. - ## Formatting multi-value fields You can use column formatting to apply styles to each member of a multi-value field of type Person, Lookup and Choice. @@ -550,7 +505,8 @@ This example uses the `length` operator to detect the number of members of the f "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", "elmType": "a", "style": { - "display": "=if(length(@currentField) > 0, 'flex', 'none')" + "display": "=if(length(@currentField) > 0, 'flex', 'none')", + "text-decoration": "none" }, "attributes": { "href": { @@ -599,7 +555,7 @@ The following image shows an example of constructing a simple sentence from the ![Screenshot of a field reads "North America, APAC, and Europe"](../images/sp-columnformatting-multi-value-1.png) -This examples uses operator `loopIndex` and `length` to identify the last member of the field, and attribute `forEach` to duplicate HTML elements. +This example uses operator `loopIndex` and `length` to identify the last member of the field, and attribute `forEach` to duplicate HTML elements. ```json { @@ -633,11 +589,12 @@ This examples uses operator `loopIndex` and `length` to identify the last member ``` ### Complex HTML elements formatting + The following image shows an example of building a list of users with pictures, email addresses and a simple counter for the number of members at the top. ![List with name "Owners" and 3 rows where each user in the field has a profile picture, name and email displayed, and a small gray counter of owners at top left corner that has a different color when it says 0.](../images/sp-columnformatting-multi-value-2.png) -This examples uses operator `loopIndex` to control the margins all rows but the first one, and attribute `forEach` to build the list of members. +This example uses operator `loopIndex` to control the margins all rows but the first one, and attribute `forEach` to build the list of members. ```json { @@ -683,7 +640,7 @@ This examples uses operator `loopIndex` to control the margins all rows but the { "elmType": "img", "attributes": { - "src": "=[$person.picture]" + "src": "=getUserImage([$person.email], 'S')" }, "style": { "width": "3em", @@ -724,194 +681,6 @@ This examples uses operator `loopIndex` to control the margins all rows but the } ``` -## Custom cards on hover - -The following image shows a list with a custom hover added to a List: - -On hover - Metadata on the column "Status" is made available in view formatting - -![Preview Image 1](../images/HoverImage-1.png) - -On hover - Metadata on the column "Status" is made available in column formatting - -![Preview Image 2](../images/HoverImage-2.png) - - - -You can use column and view formatting to define custom call out that can be commissioned basis user defined actions like click or hover - -This example uses customCardProps, openOnEvent, directionalHint and isBeakVisible - -```JSON - -{ - "elmType": "div", - "style": { - "font-size": "12px" - }, - "txtContent": "[$Status]", - "customCardProps": { - "formatter": { - "elmType": "div", - "txtContent": "Define your formatter options inside the customCarProps/formatter property" - }, - "openOnEvent": "hover", - "directionalHint": "bottomCenter", - "isBeakVisible": true, - "beakStyle" : { - "backgroundColor": "white" - } - } -} -``` -## Default cards on hover - -Users can now have profile card or file hover card on formatters too, some of the things users can now do - - 1) Profile card or File Hover card on any column - 2) Profile card or Hover card with view formatting - -Hover on a filename with formatting with default file card - -![Preview Image 3](../images/HoverImage-3.png) - - -Hover on a person column with formatting with default Profile card - -![Preview Image 4](../images/HoverImage-4.png) - -Both the example uses defaultHoverField - -```JSON - -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "div", - "children": [ - { - "elmType": "img", - "style": { - "width": "32px", - "height": "32px", - "overflow": "hidden", - "border-radius": "50%", - "margin": "2px" - }, - "attributes": { - "src": "='/_layouts/15/userphoto.aspx?size=S&accountname=' + [$Editor.email]", - "title": "[$Editor.title]" - } - }, - { - "elmType": "span", - "style": { - "vertical-align": "middle", - "margin-left": "2px" - }, - "txtContent": "[$Editor.title]" - } - ], - "defaultHoverField": "[$Editor]" -} - -``` - - -## Column formatter reference - -Users can refer to a column's formatter JSON inside another column/view formatter and use it along with other elements to build a custom column visualization. This can be done by using `columnFormatterReference` property. - -The following image shows a list with a Gallery layout referencing the Category column formatter: -Gallery layout referring Category column - -List layout with Category column formatted - -``` JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", - "height": 127, - "width": 254, - "hideSelection": false, - "formatter": { - "elmType": "div", - "attributes": { - "class": "sp-card-container" - }, - "children": [ - { - "elmType": "button", - "attributes": { - "class": "sp-card-defaultClickButton" - }, - "customRowAction": { - "action": "defaultClick" - } - }, - { - "elmType": "div", - "attributes": { - "class": "ms-bgColor-white sp-css-borderColor-neutralLight sp-card-borderHighlight sp-card-subContainer" - }, - "children": [ - { - "elmType": "div", - "attributes": { - "class": "sp-card-displayColumnContainer" - }, - "children": [ - { - "elmType": "p", - "attributes": { - "class": "ms-fontColor-neutralSecondaryAlt sp-card-label" - }, - "txtContent": "[!Title.DisplayName]" - }, - { - "elmType": "p", - "attributes": { - "title": "[$Title]", - "class": "ms-fontColor-neutralPrimary sp-card-content sp-card-highlightedContent" - }, - "txtContent": "=if ([$Title] == '', '–', [$Title])" - } - ] - }, - { - "elmType": "div", - "attributes": { - "class": "sp-card-lastTextColumnContainer" - }, - "children": [ - { - "elmType": "p", - "attributes": { - "class": "ms-fontColor-neutralSecondaryAlt sp-card-label" - }, - "txtContent": "[!Category.DisplayName]" - }, - { - "elmType": "div", - "attributes": { - "class": "sp-card-content" - }, - "style": { - "height": "32px", - "font-size":"12px" - }, - "children": [ - { - "columnFormatterReference": "[$Category]" - } - ] - } - ] - } - ] - } - ] - } -} -``` - ## Supported column types The following column types support column formatting: @@ -936,6 +705,10 @@ The following column types support column formatting: * Title (in Lists) * Yes/No * Managed Metadata +* Average Rating +* Likes +* Approval Status +* Attachments The following are currently **not** supported: @@ -966,1010 +739,28 @@ You can use the following predefined classes for several common scenarios. > [!NOTE] > The icons shown above for the `sp-field-severity` classes are **NOT** part of the class. Only the background color is included. Icons can be added by using the `iconName` attribute. -In addition to the classes listed above, the classes (such as the theme color, typography, grid system, etc.) defined by the Fluent UI can be used. For details, see the [Fluent UI website](https://developer.microsoft.com/fluentui#/styles/web/colors/products). +In addition to the classes listed above, the classes (such as the theme color, typography, grid system, etc.) defined by the Fluent UI can be used. For details, see the [Fluent UI website](https://developer.microsoft.com/fluentui#/styles/web/colors/products). ### Predefined icons -You can use predefined icons from Fluent UI. For details, see the [Fluent UI website](https://developer.microsoft.com/fluentui#/styles/web/icons). +You can use predefined icons from Fluent UI. For details, see the [Fluent UI website](https://developer.microsoft.com/fluentui#/styles/web/icons). ## Creating custom JSON -Creating custom column formatting JSON from scratch is simple if user understands the schema, Monaco Editor is integrated in the formatting pane with pre-filled JSON column schema reference to assist in creation of column formatting, Monaco editor has validation and autocomplete to help in crafting right JSON. User can start adding JSON after the first line that defines the schema location. +Creating custom column formatting JSON from scratch is simple if user understands the schema, Monaco Editor is integrated in the formatting pane with pre-filled JSON column schema reference to help creation of column formatting, Monaco editor has validation and autocomplete to help in crafting right JSON. User can start adding JSON after the first line that defines the schema location. > [!TIP] > At any point, select **Ctrl**+**Space** for property/value suggestions. > [!TIP] -> You can start from a HTML using [**formatter helper tool**](https://pnp.github.io/List-Formatting/tools/), which can convert HTML and CSS into formatter JSON with inline styles. +> You can start from a HTML using [**formatter helper tool**](https://pnp.github.io/List-Formatting/tools/), which can convert HTML and CSS into formatter JSON with inline styles. > [!TIP] > SharePoint Patterns and Practices provides a free web part, [Column Formatter](https://github.com/SharePoint/sp-dev-solutions/blob/master/solutions/ColumnFormatter/docs/documentation/docs/getting-started.md), that can be used to edit and apply formats directly in the browser. -## Detailed syntax reference - -### elmType - -Specifies the type of element to create. Valid elements include: - -- div -- span -- a -- img -- svg -- path -- button - -Any other value will result in an error. - -#### button elements - -`Button` elements can be used to launch a specific action on the parent item. Every `button` element has a required property, `customRowAction`, that specifies an `action` that's taken when the button is clicked. This action must be one of the following values: - -- **defaultClick**: buttons with this action will do the same thing as clicking the list item in an uncustomized view. Below is an example of a button that, when clicked, simulates a click on the item, which results in opening the list item. Adding this example button to a document library simulates a click on the file or folder, which results in the file or folder being opened. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "button", - "txtContent": "Open this item", - "customRowAction": { - "action": "defaultClick" - } -} - -``` - -- **share**: Clicking the button will open the sharing dialog. Below is an example of this type of button. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "button", - "txtContent": "Share this item", - "customRowAction": { - "action": "share" - } -} - -``` - -- **delete**: Clicking the button will open the delete confirmation dialog. -- **editProps**: Clicking the button will open the item properties page in edit mode. -- **openContextMenu**: Clicking the button will open the item's default context menu. -- **executeFlow**: Clicking the button will launch the specified Flow, specified by ID inside the `actionParams` attribute. For an example of this, see the [Create a button to launch a Flow](#create-a-button-to-launch-a-flow) section in this document. Below is an example of this type of button. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json", - "elmType": "button", - "txtContent": "It's Flow Time!", - "customRowAction": { - "action": "executeFlow", - "actionParams": "{\"id\":\"f7ecec0b-15c5-419f-8211-302a5d4e94f1\", \"headerText\":\"It's Flow Time!\",\"runFlowButtonText\":\"Do it\"}" - } -} -``` - -The `actionParams` attribute can have the following options when using the `executeFlow` action: -- **id**: ID of the Flow to launch _(required)_ -- **headerText**: Sets the text at the top of the flow panel _(optional)_ -- **runFlowButtonText**: Sets the text of the primary button in the flow panel _(optional)_ - -### txtContent - -An optional property that specifies the text content of the element specified by `elmType`. The value of this property can either be a string (including special strings) or an Expression object. - -### style - -An optional property that specifies style attributes to apply to the element specified by `elmType`. This is an object with name-value pairs that correspond to CSS names and values. The values of each property in the style object can either be a string (including special strings) or an Expression object. The following style attributes are allowed. - -```JS -'background-color' -'fill' -'background-image' -'border' -'border-bottom' -'border-bottom-color' -'border-bottom-style' -'border-bottom-width' -'border-color' -'border-left' -'border-left-color' -'border-left-style' -'border-left-width' -'border-right' -'border-right-color' -'border-right-style' -'border-right-width' -'border-style' -'border-top' -'border-top-color' -'border-top-style' -'border-top-width' -'border-width' -'outline' -'outline-color' -'outline-style' -'outline-width' -'border-bottom-left-radius' -'border-bottom-right-radius' -'border-radius' -'border-top-left-radius' -'border-top-right-radius' -'box-decoration-break' -'box-shadow' -'box-sizing' - -'overflow-x' -'overflow-y' -'overflow-style' -'rotation' -'rotation-point' - -'opacity' -'cursor' - -'height' -'max-height' -'max-width' -'min-height' -'min-width' -'width' - -'flex-grow' -'flex-shrink' -'flex-flow' -'flex-direction' -'flex-wrap' -'flex' -'justify-content' -'align-items' - -'box-align' -'box-direction' -'box-flex' -'box-flex-group' -'box-lines' -'box-ordinal-group' -'box-orient' -'box-pack' - -'font' -'font-family' -'font-size' -'font-style' -'font-variant' -'font-weight' -'font-size-adjust' -'font-stretch' - -'grid-columns' -'grid-rows' - -'margin' -'margin-bottom' -'margin-left' -'margin-right' -'margin-top' - -'column-count' -'column-fill' -'column-gap' -'column-rule' -'column-rule-color' -'column-rule-style' -'column-rule-width' -'column-span' -'column-width' -'columns' - -'padding' -'padding-bottom' -'padding-left' -'padding-right' -'padding-top' - -'bottom' -'clear' -'clip' -'display' -'float' -'left' -'overflow' -'position' -'right' -'top' -'visibility' -'z-index' - -'border-collapse' -'border-spacing' -'caption-side' -'empty-cells' -'table-layout' - -'color' -'direction' -'letter-spacing' -'line-height' -'text-align' -'text-decoration' -'text-indent' -'text-transform' -'unicode-bidi' -'vertical-align' -'white-space' -'word-spacing' -'hanging-punctuation' -'punctuation-trim' -'text-align-last' -'text-justify' -'text-outline' -'text-overflow' -'text-shadow' -'text-wrap' -'word-break' -'word-wrap' -``` - -The following example shows the value of a style object. In this example, two style properties (`padding` and `background-color`) will be applied. The `padding` value is a hard-coded string value. The `background-color` value is an Expression that is evaluated to either red (`#ff0000`) or green (`#00ff00`) depending on whether the value of the current field (specified by `@currentField`) is less than 40. For more information, see the Expression object section. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "div", - "style": { - "padding": "4px", - "background-color": { - "operator": "?", - "operands": [ - { - "operator": "<", - "operands": [ - "@currentField", - 40 - ] - }, - "#ff0000", - "#00ff00" - ] - } - } -} -``` - -Here's the same sample from above, using the Excel-style expression syntax: - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "div", - "style": { - "padding": "4px", - "background-color": "=if(@currentField < 40, '#ff0000', '#00ff00')" - } -} -``` - -### attributes - -An optional property that specifies additional attributes to add to the element specified by `elmType`. This is an object with name-value pairs. Attribute names must be one of the following: - -- href -- rel -- src -- class -- target -- title -- role -- iconName -- d -- aria -- data-interception -- viewBox -- preserveAspectRatio - -Any other attribute name will result in an error. Attribute values can either be Expression objects or strings. The following example adds two attributes (`target` and `href`) to the element specified by `elmType`. The `target` attribute is hard-coded to a string. The `href` attribute is an expression that will be evaluated at runtime to http://finance.yahoo.com/quote/ + the value of the current field (`@currentField`). - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "target": "_blank", - "href": "='http://finance.yahoo.com/quote/' + @currentField" -} -``` - -### children - -An optional property that specifies child elements of the element specified by `elmType`. The value is specified as an array of `elm` objects. There can be an arbitrary level of nesting. If an element has the `txtContent` property, the child properties are ignored. - -### debugMode - -An optional property that is meant for debugging. It outputs error messages and logs warnings to the console. - -### forEach - -An optional property that allows an element to duplicate itself for each member of a specific multi-value field. The value of `"forEach"` property should be in the format of either `"iteratorName in @currentField"` or `"iteratorName in [$FieldName]"`. - -`iteratorName` represents the name of iterator variable that is used to represent the current member of the multi-value field. The name of the iterator can be any combination of alphanumeric characters and underscore (`_`) that does not start with a digit. - -The field used in the loop must be in a supported field type with multi-value option enabled: Person, Lookup, and Choice. - -In the element with `forEach` or its children elements, the iterator variable can be referred as if it is a new field. The index of the iterator can be accessed with `loopIndex` operator. - -`forEach` cannot be applied to the root element, and will render no element if there is no value in the field. - -See [here](#formatting-multi-value-fields) for examples. - -### Expressions - -Values for `txtContent`, style properties, and attribute properties can be expressed as expressions, so that they are evaluated at runtime based on the context of the current field (or row). Expression objects can be nested to contain other Expression objects. - -Expressions can be written using Excel-style expressions in SharePoint Online, or by using Abstract Syntax Tree expressions in SharePoint Online and SharePoint 2019. - -#### Excel-style expressions - -All Excel-style expressions begin with an equal (`=`) sign. This style of expression is only available in SharePoint Online (not SharePoint 2019). - -This simple conditional expression evaluates to `none` if `@me` is not equal to `[$Author.email]`, and evaluates to \`\` otherwise: -```JSON -=if(@me != [$Author.email], 'none', '') -``` - -More complex if/else statements can be written like this: -```JSON -=if([$Sentiment] <= 0.3, 'sp-field-severity--blocked', if([$Sentiment] < 0.9,'sp-field-severity--warning','sp-field-severity--good')) -``` - -Non-conditional operators that take one or two operands can be written like this: -```JSON -=[$foo] * -7 -``` -```JSON -=sin(@currentField) -``` -```JSON -=toString(60 + (sin(6.2831853 * @currentField) * 60)) -``` - -#### Abstract Syntax Tree expressions - -The following example contains an Expression object that performs the following expression: - -`(@currentField > 40) ? '100%' : (((@currentField * 2.5).toString() + '%')` - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "operator": "?", - "operands": [ - { - "operator": ">", - "operands": [ - "@currentField", - "40" - ] - }, - "100%", - { - "operator": "+", - "operands": [ - { - "operator": "toString()", - "operands": [ - { - "operator": "*", - "operands": [ - "@currentField", - 2.5 - ] - } - ] - }, - "%" - ] - } - ] -} -``` - -### Operators - -Operators specify the type of operation to perform. The following operators are valid values: - -- \+ -- \- -- / -- \* -- < -- \> -- \% -- == -- != -- <= -- \>= -- || -- && -- toString() -- Number() -- Date() -- cos -- sin -- ? -- : -- toLocaleString() -- toLocaleDateString() -- toLocaleTimeString() -- indexOf -- toLowerCase -- join -- length -- abs -- loopIndex -- floor -- ceiling -- pow -- substring -- getDate -- getMonth -- getYear -- toUpperCase -- lastIndexOf -- startsWith -- endsWith -- replace -- padStart -- padEnd - -**Binary arithmetic operators** - The following are the standard arithmetic binary operators that expect two operands: - -- \+ -- \- -- / -- \* -- < -- \> -- \% -- == -- != -- <= -- \>= - -**Unary operators** - The following are standard unary operators that expect only one operand: - -- **toString()**: returns a string representing the object - - `"txtContent": "=toString(45)"` results in _"45"_ - -- **Number()**: returns the numeric value, if the operand is not a number, NaN is returned - - `"txtContent": "=Number('365')"` results in _365_ - - `"txtContent": "=Number('Wowee')"` results in _NaN_ - - `"txtContent": "=Number(Date('12/26/1981'))"` results in _378190800000_ - -- **Date()**: returns a datetime object from the parameter (converts strings or numbers to dates, sensitive to locale) - - `"txtContent": "=Date('12/26/1981')"` results in _12/26/1981, 12:00:00 AM_ - -- **cos**: returns the cosine of the specified angle which should be specified in radians - - `"txtContent": "=cos(5)"` results in _0.28366218546322625_ - -- **sin**: returns the sine of a number - - `"txtContent": "=sin(90)"` results in _0.8939966636005579_ - -- **toLocaleString()**: returns a language sensitive representation of a date - - `"txtContent":"=toLocaleString(@now)"` results vary based on user's locale, but en-us looks like _"2/5/2019, 1:22:24 PM"_ - -- **toLocaleDateString()**: returns a language sensitive representation of just the date portion of a date - - `"txtContent":"=toLocaleDateString(@now)"` results vary based on user's locale, but en-us looks like _"2/5/2019"_ - -- **toLocaleTimeString()**: returns a language sensitive representation of just the time portion of a date - - `"txtContent":"=toLocaleTimeString(@now)"` results vary based on user's locale, but en-us looks like _"1:22:24 PM"_ - -- **toLowerCase**: returns the value converted to lower case (only works on strings) - _Only available in SharePoint Online_ - - `"txtContent":"=toLowerCase('DogFood')"` results in _"dogfood"_ - -- **abs**: returns the absolute value for a given number - _Only available in SharePoint Online_ - - `"txtContent":"=abs(-45)"` results in _45_ - -- **length**: returns the number of items in an array (multi-select person or choice field), for all other value types it returns 1 when true and 0 when false. It does NOT provide the length of a string value (*see the `indexOf` workaround explained later on for such operation*). - _Only available in SharePoint Online_ - - `"txtContent":"=length(@currentField)"` might result in _2_ if there are 2 selected values - - `"txtContent":"=length('Some Text')"` results in _1_ - - `"txtContent":"=length('')"` results in _0_ - - `"txtContent":"=length(45)"` results in _1_ - - `"txtContent":"=length(0)"` results in _0_ - -- **floor**: returns the largest integer less than or equal to a given number. - _Only available in SharePoint Online_ - - `"txtContent":"=floor(45.5)"` results in _45_ - -- **ceiling**: rounds the given number up to the next largest whole number or integer. - _Only available in SharePoint Online_ - - `"txtContent":"=ceiling(45.5)"` results in _46_ - -- **getDate**: returns the day of the month of the given date. - _Only available in SharePoint Online_ - - `"txtContent":"=getDate(Date('12/26/1981'))"` results in _26_ - -- **getMonth**: returns the month in the specified date according to local time, as a zero-based value (where zero indicates the first month of the year). - _Only available in SharePoint Online_ - - `"txtContent":"=getMonth(Date('12/26/1981'))"` results in _11_ - -- **getYear**: returns the year of the given date. - _Only available in SharePoint Online_ - - `"txtContent":"=getYear(Date('12/26/1981'))"` results in _1981_ - -- **toUpperCase**: returns the value converted to upper case (only works on strings) - _Only available in SharePoint Online_ - - `"txtContent":"=toUpperCase('DogFood')"` results in _"DOGFOOD"_ - -**Binary operators** - The following are operators that expect two operands: - -- **indexOf**: takes 2 operands. The first is the text you would like to search within, the second is the text you would like to search for. Returns the index value of the first occurrence of the search term within the string. Indexes start at 0. If the search term is not found within the text, -1 is returned. This operator is case-sensitive. - _Only available in SharePoint Online_ - - `"txtContent": "=indexOf('DogFood', 'Dog')"` results in _0_ - - `"txtContent": "=indexOf('DogFood', 'F')"` results in _3_ - - `"txtContent": "=indexOf('DogFood', 'Cat')"` results in _-1_ - - `"txtContent": "=indexOf('DogFood', 'f')"` results in _-1_ - -- **join**: takes 2 operands. The first is an array (multi-select person or choice field) and the second is the separating string. Returns a string concatenation of the array values separated by the separating string. - _Only available in SharePoint Online_ - - `"txtContent": "=join(@currentField, ', ')"` might result in _"Apple, Orange, Cherry"_ (depending on the selected values) - - `"txtContent": "=join(@currentField.title, '|')"` might result in _"Chris Kent|Vesa Juvonen|Jeff Teper"_ (depending on the selected persons) - -- **pow**: returns the base to the exponent power. - _Only available in SharePoint Online_ - - `"txtContent":"=pow(2,3)"` results in _8_ - -- **lastIndexOf**: returns the position of the last occurrence of a specified value in a string - - `"txtContent": "=lastIndexOf('DogFood DogFood', 'Dog')"` results in _8_ - - `"txtContent": "=lastIndexOf('DogFood DogFood', 'F')"` results in _11_ - - `"txtContent": "=lastIndexOf('DogFood DogFood', 'Cat')"` results in _-1_ - - `"txtContent": "=lastIndexOf('DogFood DogFood', 'f')"` results in _-1_ - -- **startsWith**: determines whether a string begins with the characters of a specified string - - `"txtContent":"=startsWith('DogFood', 'Dog')"` results in _true_ - - `"txtContent":"=startsWith('DogFood', 'Food')"` results in _false_ - -- **endsWith**: determines whether a string ends with the characters of a specified string - - `"txtContent":"=endsWith('DogFood', 'Dog')"` results in _false_ - - `"txtContent":"=endsWith('DogFood', 'Food')"` results in _true_ - -**Ternary operators** - The following are operators that expect three operands: - -- **substring**: returns the part of the string between the start and end indices. - _Only available in SharePoint Online_ - - `"txtContent":"=substring('DogFood', 3, 4)"` results in _F_ - - `"txtContent":"=substring('DogFood', 4, 3)"` results in _F_ - - `"txtContent":"=substring('DogFood', 3, 6)"` results in _Foo_ - - `"txtContent":"=substring('DogFood', 6, 3)"` results in _Foo_ - - The substring() method returns the part of the string between the start and end indexes, or to the end of the string. - -- **replace**: searches a string for a specified value and returns a new string where the specified value is replaced. Only the first instance of the value will be replaced. - - `"txtContent":"=replace('Hello world', 'world', 'everyone')"` results in _Hello everyone_ - -- **padStart**: pads the current string with another string until the resulting string reaches the given length. The padding is applied from the start of the current string. - - `"txtContent":"=padStart('DogFood', 10, 'A')"` results in _AAADogFood_ - - `"txtContent":"=padStart('DogFood', 10, 'AB')"` results in _ABADogFood_ - - `"txtContent":"=padStart('DogFood', 5, 'A')"` results in _DogFood_ - -- **padEnd**: pads the current string with a given string until the resulting string reaches the given length. The padding is applied from the end of the current string. - - `"txtContent":"=padEnd('DogFood', 10, 'A')"` results in _DogFoodAAA_ - - `"txtContent":"=padEnd('DogFood', 10, 'AB')"` results in _DogFoodABA_ - - `"txtContent":"=padEnd('DogFood', 5, 'A')"` results in _DogFood_ - -**Conditional operator** - The conditional operator is: - -- **?**: Conditional operations written in Abstract Tree Syntax use `?` as the operator. This is to achieve an expression equivalent to a ? b : c, where if the expression a evaluates to true, then the result is b, else the result is c. For Excel style expressions you write these with an `if` statement. Regardless, there are 3 operands. The first is the condition to evaluate. The second is the result when the condition is true. The third is the result when the condition is false. - - `"txtContent":"=if(4 < 5, 'yes', 'no')"` results in _"yes"_ - - `"txtContent":"=if(4 > 5, 'yes', 'no')"` results in _"no"_ - -**Multi-value field-related operators** - The following operators are only used in a context with multi-value field of type Person, Lookup, or Choice. - -- length -- join -- loopIndex - -`length`, when provided with a field name, returns the number of members in a multi-valued field. When a single-value field is provided, `length` will return 1 when there is a value in that field. - -`join` concatenates values in a multi-value field with a specified separator. The first operand shall point to a value in a multi-value field, e.g. `"@currentField.lookupValue"`, `"[$AssignedTo.title]"`. The second operand shall be a string literal that is the separator that joins the values together. - -`loopIndex`, when provided with a name of iterator variable, returns the current index (starting from 0) of the iterator. The name of iterator must be provided as a string literal. `loopIndex` would only work within the element with respective `forEach` enabled or its children elements. - -See [here](#formatting-multi-value-fields) for examples. - -**String related operators** - Some of the previously detailed operators can be used when working with string values - -- \+ -- indexOf ( *for string length workaround* ) - -`+` can be used when there is a need to concatenate strings, for instance : `"txtContent": "=[$column1] + ' ' + [$column2] + 'some other text"` - -`indexOf` Since the operator `length` doesn't work for string value types ( it will return 1 or 0 ), `indexOf` can serve us as a nice workaround to get the length of a string, for instance: `indexOf([$column1] + '^', '^')`. We will use `'^'` or any other character we may want to use to find out the end of the string. - -### operands - -Specifies the parameters, or operands for an expression. This is an array of Expression objects or base values. - -### Special string values - -The values for `txtContent`, styles, and attributes can be either strings or Expression objects. A few special string patterns for retrieving values from the fields in the list and the user's context are supported. - -#### "@currentField" - -Will evaluate to the value of the current field. - -Some field types are represented as objects. To output a value from an object, refer to a particular property inside that object. For example, if the current field is a person/group field, specify `@currentField.title` to retrieve the person's name, which is normally displayed in list views. The following are the field types that are represented as objects with a list of their properties. - -> [!NOTE] -> The `@currentField.title` returns a person's name by default. However, if the person field's Show Field has been adjusted, it may change the value of the `title` property. For example, a person field with the Show Field configured as Department will have the person's department for the `title` property. - -**People fields** - -The people field object has the following properties (with example values): - -```JSON -{ - "id": "122", - "title": "Kalya Tucker", - "email": "kaylat@contoso.com", - "sip": "kaylat@contoso.com", - "picture": "https://contoso.sharepoint.com/kaylat_contoso_com_MThumb.jpg?t=63576928822", - "department":"Human Resources", - "jobTitle":"HR Manager" -} -``` -People field can have profile hover cards along with formatting - -```json -{ - "elmType": "div", - "txtContent": "[$Editor.title]", - "defaultHoverField": "[$Editor]" -} -``` -**Date/Time fields** - -The value of Date/Time fields can be retrieved a few different ways, depending on the date format you'd like to display. The following methods for converting date values to specific formats are supported: - -* `toLocaleString()` - Displays a date type fully expanded with date and time. -* `toLocaleDateString()` - Displays a date type with just the date. -* `toLocaleTimeString()` - Displays a date type with just the time. - -For example, the following JSON will display the current field (assuming it's a date field) as a date and time string. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "div", - "txtContent": { - "operator": "toLocaleString()", - "operands" : ["@currentField"] - } -} -``` - -Here's the same sample from above, using the Excel-style expression syntax: -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "div", - "txtContent": "=toLocaleString(@currentField)" -} -``` - -**Location fields** - -The location field object has the following properties (with example values): - -```JSON -{ - "Address": { - "City": "Knoxville", - "CountryOrRegion": "United States", - "State": "TN", - "Street": "963 Worlds Fair Park Dr" - }, - "Coordinates": { - "Latitude": "35.961673736572266", - "Longitude": "-83.92420959472656" - }, - "DisplayName": "World's Fair Park", - "LocationUri": "https://www.bingapis.com/api/v6/localentities/8346bf26-6da4-104c-6ba5-2334b83f6ac8?setLang=en" -} -``` - -> [!NOTE] -> Location fields do not currently have a "Format this column" option in the list view and formats applied directly to these fields will need to be done through field settings. - -
- -The following example shows how a location field might be used on a current field. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json", - "elmType": "div", - "style": { - "display": "block" - }, - "children": [ - { - "elmType": "a", - "txtContent": "@currentField.DisplayName", - "attributes": { - "href": "='https://www.bing.com/maps?cp=' + @currentField.Coordinates.Latitude + '~' + @currentField.Coordinates.Longitude + '&lvl=17&sV=2'", - "target": "_blank", - "title": "=@currentField.Coordinates.Latitude + ', ' + @currentField.Coordinates.Longitude" - }, - "style": { - "display": "block" - } - }, - { - "elmType": "div", - "txtContent": "@currentField.Address.Street" - }, - { - "elmType": "div", - "txtContent": "=@currentField.Address.City + ', ' + @currentField.Address.State" - }, - { - "elmType": "div", - "txtContent": "@currentField.Address.CountryOrRegion" - } - ] -} -``` - - -**Lookup fields** - -The lookup field object has the following properties (with example values): - -```JSON -{ - "lookupId": "100", - "lookupValue": "North America", -} -``` - -
- -The following example shows how a lookup field might be used on a current field. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "a", - "txtContent": "@currentField.lookupValue", - "attributes": { - "href": { - "operator": "+", - "operands": [ - "https://contoso.sharepoint.com/teams/Discovery/Lists/Regions/DispForm.aspx?ID=", - "@currentField.lookupId" - ] - }, - "target": "_blank" - } -} -``` - -**Hyperlink fields** - -The hyperlink field object has the following property (with example value): - -```JSON -{ - "desc": "SharePoint Patterns and Practices", -} -``` - -
- -To reference the URL value, use `@currentField`. - -The following example shows how a hyperlink field might be used on a current field. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "a", - "txtContent": "@currentField.desc", - "attributes": { - "href": "@currentField", - "target": "_blank" - } -} -``` - -**Image fields** - -The image field object has the following properties (with example values): - -```JSON -{ - "fileName": "image.png", - "id": "6bb1d843-0633-4c9a-9a16-90bc5abd1d8e", - "serverRelativeUrl": "/teams/Discovery/SiteAssets/Lists/ad6ed939-0db2-4d85-8a39-8f3497f41eee/image.png", - "serverUrl": "https://contoso.sharepoint.com" -} - -``` - -
- -The following example shows how an image field can be used on a current field. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "img", - "attributes": { - "src": "@currentField.serverRelativeUrl", - "alt": "@currentField.fileName" - }, - "style": { - "width": "100%", - "max-width": "100%" - } -} -``` - - -#### "[$FieldName]" - -The column is formatted within the context of the entire row. You can use this context to reference the values of other fields within the same row by specifying the **internal name** of the field surrounded by square brackets and preceded by a dollar sign: `[$InternalName]`. For example, to get the value of a field with an internal name of "MarchSales", use `[$MarchSales]`. - -If the value of a field is an object, the object's properties can be accessed. For example, to access the "Title" property of a person field named "SalesLead", use "[$SalesLead.title]". - -#### "[!FieldName]" - -In column and view formatting, you can refer to any field's metadata by specifying the **internal name** of the field surrounded by square brackets and preceded by a exclamation mark: `[!InternalName]`. - -Currently field's display name is available in this metadata, and can be accessed using DisplayName property: `[!SalesLead.DisplayName]`. - - -#### "@currentWeb" - -This will evaluate to the absolute URL for the site. This is equivalent to the `webAbsoluteUrl` value within the page context. This value is only available in SharePoint Online. - -#### "@me" - -This will evaluate to the email address of the current logged in user. - -This field can be used to display the current user's email address, but more likely it will be used within conditions. The following is an example of setting the color for a person field to red when it is equal to the current logged in user and blue otherwise: - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "div", - "txtContent": "@currentField.title", - "style": { - "color": { - "operator": "?", - "operands": [ - { - "operator": "==", - "operands": [ - "@me", - "@currentField.email" - ] - }, - "red", - "blue" - ] - } - } -} -``` - -Here's the same sample from above, using the Excel-style expression syntax: - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "div", - "txtContent": "@currentField.title", - "style": { - "color": "=if(@me == @currentField.email, 'red', 'blue')" - } -} -``` - -#### "@now" - -This will evaluate to the current date and time. - -#### "@rowIndex" - -This will evaluate to the rendered index of a row within a view. This value is based on render position and will remain consistent based on position even as views are sorted and filtered. Indexes start at 0. This value is only available in SharePoint Online. - -Here's an example of using the value within a view format to apply alternating styles to rows: - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", - "additionalRowClass": "=if(@rowIndex % 2 == 0,'ms-bgColor-themeLighter ms-bgColor-themeLight--hover','')" -} -``` - -#### "@window.innerHeight" - -This will evaluate to a number equal to the height of the browser window (in pixels) when the list was rendered. - -#### "@window.innerWidth" - -This will evaluate to a number equal to the width of the browser window (in pixels) when the list was rendered. - -#### Thumbnails - -In a document library, there is a series of tokens that can be used to retrieve the URL to the thumbnail of a file, including: - -- `@thumbnail.small`, `@thumbnail.medium`, and `@thumbnail.large` evaluate to the thumbnail URL in 3 different predefined sizes. -- `@thumbnail.` evaluates to the URL to the largest thumbnails that is not larger than the bounding size in both width and height. For example, `@thumbnail.150` evaluates to the URL to a thumbnail not larger than 150×150 pixels. -- `@thumbnail.x` evaluates to the URL to the largest thumbnail that is not larger than the bounding width and bounding height. For example, `@thumbnail.100x200` evaluates to the URL to a thumbnail not wider than 100 pixels and not higher than 200 pixels. - -These tokens will yield no value on non-file items including folders. - -> [!NOTE] -> The aspect ratio of thumbnail generated is the same as how the file looks like, changing the bounding sizes will not affect the aspect ratio of the thumbnail. - -> [!TIP] -> Thumbnails are only available for a list of supported file formats. It means that sometimes the URL generated is not accessible due to lack of support on certain formats. However, if a valid thumbnail token is set as the _only_ `src` attribute of an `img` tag, we will take care of it and hide the image when it is not available. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", - "elmType": "img", - "attributes": { - "src": "@thumbnail.200x150", - "alt": "='Thumbnail of file ' + [$FileLeafRef]" - }, - "style": { - "width": "100%", - "max-width": "100%" - } -} -``` -Default file hover card using FileLeafRef - -```JSON - { - "elmType": "img", - "style": { - "width": "100%", - "height": "100%", - "display": "=if([$File_x0020_Type] == '', 'none', '')" - }, - "attributes": { - "src": "@thumbnail.300x300" - }, - "defaultHoverField": "[$FileLeafRef]" -} - ``` - -#### displayValue - -The following column types can use displayValue property to get the default rendered value, based on the column setting -* Date/Time -* Number -* Yes/No -* Currency - -```JSON - { - "elmType": "div", - "txtContent": "@currentField.displayValue" -} -``` -This also works with field name -```JSON - { - "elmType": "div", - "txtContent": "[$FieldName.displayValue]" -} -``` - -#### columnFormatterReference - -This will be replaced with the referenced column's formatter JSON. Multi level reference is not supported. - -```JSON -{ - "columnFormatterReference": "[$FieldName]" -} -``` - ## See also - [Column formatting](https://support.office.com/article/Column-formatting-1f927342-2bed-4745-b727-ff8b7ff96b22?ui=en-US&rs=en-US&ad=US) +- [View formatting](./view-formatting.md) +- [Advanced formatting concepts](./formatting-advanced.md) +- [Formatting syntax reference](./formatting-syntax-reference.md) diff --git a/docs/declarative-customization/customize-default-site-design.md b/docs/declarative-customization/customize-default-site-design.md index 2745f3259..afffc07db 100644 --- a/docs/declarative-customization/customize-default-site-design.md +++ b/docs/declarative-customization/customize-default-site-design.md @@ -1,66 +1,60 @@ ---- -title: Customize default site designs in SharePoint -description: Customize the default site designs in either the SharePoint Team site or Communication site template. -ms.date: 06/18/2020 -localization_priority: Priority ---- - -# Customize a default site design - -SharePoint contains several site designs already available in the SharePoint Online site templates. These are the default site designs. You can modify them by using PowerShell or the REST APIs to control the entire site provisioning experience. For example, you can ensure that your company theme is applied to every site that gets created, or you can make sure a logging mechanism always runs regardless of which site design is chosen. - -## Apply a site design to the default site designs - -To customize the default site designs, apply a new one with the PowerShell **Add-SPOSiteDesign** cmdlet or the **CreateSiteDesign** REST API. Specify the **IsDefault** switch to apply the site design as the default. - -The WebTemplate ID for a group-connected Team site is 64; for a Communication site it is 68. - -The following example shows how to use the **IsDefault** switch to apply the Contoso company theme to the default site designs. The site script referenced by ID contains the JSON script to apply the correct theme. - -```powershell -C:\> Add-SPOSiteDesign ` - -Title "Contoso company theme" ` - -WebTemplate "68" ` - -SiteScripts "89516c6d-9f4d-4a57-ae79-36b0c95a817b" ` - -Description "Applies standard company theme to site" ` - -IsDefault -``` - -
- -```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.CreateSiteDesign", {info:{Title:"Contoso company theme", Description:"Applies standard company theme to site", SiteScriptIds:["89516c6d-9f4d-4a57-ae79-36b0c95a817b"], WebTemplate:"68", IsDefault: true}}); -``` - -### Which default site designs are updated? - -In the previous example, the **WebTemplate** value of `"68"` refers to the SharePoint Online Communication site template. That template contains the following default site designs: - -- Topic -- Showcase -- Blank - -When you apply a new site design, it updates all three default site designs at the same time. - -The SharePoint Online Team site template contains only one default site design named **Team**. In this case, when you apply a default site design, only the **Team** site design is updated. - -## Restore the default site designs - -To restore a site design to the defaults, remove the site design that you applied. In the previous example, if the site design created had the ID `db752673-18fd-44db-865a-aa3e0b28698e`, you would remove it as shown in the following example. - -```powershell -C:\> Remove-SPOSiteDesign db752673-18fd-44db-865a-aa3e0b28698e -``` - -
- -```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteDesign", {id:"db752673-18fd-44db-865a-aa3e0b28698e"}); -``` - -> [!NOTE] -> If you're not sure which site design is the default, run the **Get-SPOSiteDesign** cmdlet. It will list all site designs, and indicates which ones are defaults. - -## See also - -- [SharePoint site design and site script overview](site-design-overview.md) +--- +title: Customize default site templates in SharePoint +description: Customize the default site templates for the SharePoint Team site or Communication site template. +ms.date: 06/28/2022 +ms.localizationpriority: high +--- + +# Customize a default site template + +SharePoint offers several [site templates that are already available](https://support.microsoft.com/office/apply-and-customize-sharepoint-site-templates-39382463-0e45-4d1b-be27-0e96aeec8398). These are the default site templates and they can be modified by using PowerShell or the REST APIs to control the entire site provisioning experience. For example, you can ensure that your company theme is applied to every site that gets created, or you can make sure a logging mechanism always runs regardless of which site template is chosen. + +## Apply a site script to a default site template + +To customize a default site template, apply a new template script using PowerShell **Add-SPOSiteDesign** cmdlet or the **CreateSiteDesign** REST API. Specify the **IsDefault** switch to apply the site template as the default template. + +| Parameter | Value | Site template type | +| :------------------- | :------------------- |:----------------| +| WebTemplate | 64 | Team site template | +| WebTemplate | 1 | Team site (with group creation disabled) | +| WebTemplate | 68 | Communication site template | +| WebTemplate | 69 | Channel site template | + +The following example shows how to use the **IsDefault** switch to apply the Contoso company theme to the default site templates. The site script referenced by ID contains the JSON script to apply the correct theme. + +```powershell +C:\> Add-SPOSiteDesign ` + -Title "Contoso company theme" ` + -WebTemplate "68" ` + -SiteScripts "89516c6d-9f4d-4a57-ae79-36b0c95a817b" ` + -Description "Applies standard company theme to site" ` + -IsDefault +``` + +```javascript +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.CreateSiteDesign", {info:{Title:"Contoso company theme", Description:"Applies standard company theme to site", SiteScriptIds:["89516c6d-9f4d-4a57-ae79-36b0c95a817b"], WebTemplate:"68", IsDefault: true}}); +``` + +### Which default site templates are updated? + +The default site template for a communication site is the **Topic** template. The default for a team site is the **Team collaboration** template. When you apply a new default site template, it updates the Microsoft-provided default templates. + +## Restore the default site templates + +To restore a site template to the defaults, remove the site template script that you applied. In the previous example, if the site template created had the ID `db752673-18fd-44db-865a-aa3e0b28698e`, you would remove it as shown in the following example. + +```powershell +C:\> Remove-SPOSiteDesign db752673-18fd-44db-865a-aa3e0b28698e +``` + +```javascript +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteDesign", {id:"db752673-18fd-44db-865a-aa3e0b28698e"}); +``` + +> [!NOTE] +> If you're not sure which site template is the default, run the **Get-SPOSiteDesign** cmdlet. It will list all site templates, and indicates which ones are defaults. + +## See also + +- [SharePoint site template and site script overview](site-design-overview.md) +- [Browse and customize Microsoft-provided site templates](https://support.microsoft.com/office/apply-and-customize-sharepoint-site-templates-39382463-0e45-4d1b-be27-0e96aeec8398) diff --git a/docs/declarative-customization/formatting-advanced.md b/docs/declarative-customization/formatting-advanced.md new file mode 100644 index 000000000..5a4d79813 --- /dev/null +++ b/docs/declarative-customization/formatting-advanced.md @@ -0,0 +1,376 @@ +--- +title: Advanced formatting concepts +description: Advanced formatting concepts +ms.date: 07/16/2025 +ms.localizationpriority: high +--- +# Advanced formatting concepts + +You can use some of the following features to make your view and column formatting more information-rich and interactive. + +## Create a button to launch a Flow + +The following screenshot shows a list with a Flow button added to the Action column: + +![screenshot of the sample](../images/sp-columnformatting-flow.png) + +You can use column formatting to create buttons that, when selected, run Flows on the corresponding list item. For flows that are [solution-aware](/power-automate/overview-solution-flows), the Flow Launch Panel will be displayed after choosing the button, and you must select Run Flow to start the flow. For flows that aren't solution-aware, the Flow Launch Panel will be displayed after selecting the button, and the Flow will just run. + +To use the sample below, you must substitute the ID of the Flow you want to run. This ID is contained within the `actionParams` property of the `customRowAction` attribute inside the `button` element. + +To obtain the ID of a flow that is solution-aware: + +1. Select **Flow > See your flows** in the SharePoint list where the Flow is configured. +1. If applicable, [switch to the environment](/power-platform/admin/working-with-environments#switch-the-environment) in which the Flow is hosted. +1. Select the Solutions area. +1. Select the solution in which the Flow was created. +1. Filter for Cloud flows and select the Flow you want to run. +1. Select Export > Get flow identifier. +1. Copy the ID. + +To obtain the ID of a flow that isn't solution-aware: + +1. Switch to the environment in which the Flow is hosted. +1. Select the Flow you want to run. +1. Select Export > Get flow identifier. +1. Copy the ID. + + ```JSON + { + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "button", + "customRowAction": { + "action": "executeFlow", + "actionParams": "{\"id\": \"edf627d9-20f4-45ba-8bc9-4494bf2ff1be\"}" + }, + "attributes": { + "class": "ms-fontColor-themePrimary ms-fontColor-themeDarker--hover" + }, + "style": { + "border": "none", + "background-color": "transparent", + "cursor": "pointer" + }, + "children": [ + { + "elmType": "span", + "attributes": { + "iconName": "Flow" + }, + "style": { + "padding-right": "6px" + } + }, + { + "elmType": "span", + "txtContent": "Send to Manager" + } + ] + } + ``` + +Additionally, you can use `headerText` and `runFlowButtonText` options within the `actionParams` property to customize portions of the Flow panel itself! See the [button elements](./formatting-syntax-reference.md#customrowaction) portion of the Detailed syntax reference for more details. + +## Custom cards on hover + +The following image shows a list with a custom hover added to a List: + +On hover - Metadata on the column "Status" is made available in view formatting: + +![Preview Image 1](../images/HoverImage-1.png) + +On hover - Metadata on the column "Status" is made available in column formatting: + +![Preview Image 2](../images/HoverImage-2.png) + +You can use formatting to define a custom callout that can be commissioned user-defined basis, actions like click or hover. + +This example uses `customCardProps`, `openOnEvent`, `directionalHint`, and `isBeakVisible`: + +```JSON +{ + "elmType": "div", + "style": { + "font-size": "12px" + }, + "txtContent": "[$Status]", + "customCardProps": { + "formatter": { + "elmType": "div", + "txtContent": "Define your formatter options inside the customCardProps/formatter property" + }, + "openOnEvent": "hover", + "directionalHint": "bottomCenter", + "isBeakVisible": true, + "beakStyle" : { + "backgroundColor": "white" + } + } +} +``` + +## Default cards on hover + +Users can now have a profile card or a file hover card on formatters too. Some of the things users can now do: + +- Profile card or File Hover card on any column +- Profile card or Hover card with view formatting + +Hover on a filename with formatting with the default file card: + +![Preview Image 3](../images/HoverImage-3.png) + +Hover on a person column with formatting with the default Profile card: + +![Preview Image 4](../images/HoverImage-4.png) + +This example uses `defaultHoverField`: + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "children": [ + { + "elmType": "img", + "style": { + "width": "32px", + "height": "32px", + "overflow": "hidden", + "border-radius": "50%", + "margin": "2px" + }, + "attributes": { + "src": "=getUserImage([$Editor.email], 's')", + "title": "[$Editor.title]" + } + }, + { + "elmType": "span", + "style": { + "vertical-align": "middle", + "margin-left": "2px" + }, + "txtContent": "[$Editor.title]" + } + ], + "defaultHoverField": "[$Editor]" +} +``` + +## Column formatter reference + +Users can refer to a column's formatter JSON inside another column/view formatter and use it along with other elements to build a custom column visualization. This can be done by using `columnFormatterReference` property. + +The following image shows a list with a Gallery layout referencing the Category column formatter: + +![Gallery layout referring Category column](../images/sp-columnformatting-formatter-reference-1.png) + +![List layout with Category column formatted](../images/sp-columnformatting-formatter-reference-2.png) + +``` JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", + "height": 127, + "width": 254, + "hideSelection": false, + "formatter": { + "elmType": "div", + "attributes": { + "class": "sp-card-container" + }, + "children": [ + { + "elmType": "button", + "attributes": { + "class": "sp-card-defaultClickButton" + }, + "customRowAction": { + "action": "defaultClick" + } + }, + { + "elmType": "div", + "attributes": { + "class": "ms-bgColor-white sp-css-borderColor-neutralLight sp-card-borderHighlight sp-card-subContainer" + }, + "children": [ + { + "elmType": "div", + "attributes": { + "class": "sp-card-displayColumnContainer" + }, + "children": [ + { + "elmType": "p", + "attributes": { + "class": "ms-fontColor-neutralSecondaryAlt sp-card-label" + }, + "txtContent": "[!Title.DisplayName]" + }, + { + "elmType": "p", + "attributes": { + "title": "[$Title]", + "class": "ms-fontColor-neutralPrimary sp-card-content sp-card-highlightedContent" + }, + "txtContent": "=if ([$Title] == '', '–', [$Title])" + } + ] + }, + { + "elmType": "div", + "attributes": { + "class": "sp-card-lastTextColumnContainer" + }, + "children": [ + { + "elmType": "p", + "attributes": { + "class": "ms-fontColor-neutralSecondaryAlt sp-card-label" + }, + "txtContent": "[!Category.DisplayName]" + }, + { + "elmType": "div", + "attributes": { + "class": "sp-card-content" + }, + "style": { + "height": "32px", + "font-size":"12px" + }, + "children": [ + { + "columnFormatterReference": "[$Category]" + } + ] + } + ] + } + ] + } + ] + } +} +``` + +## Inline Editing + +With inline editing, formatters have the ability to load field editors to edit field data on an item. +Users need to have edit permissions on the list item, and the field type should belong to a set of supported types for this feature to work. + +A special JSON property `inlineEditField` is used with value as the field internal name __`[$FieldName]`__ at the target element in the JSON. + +```json +{ + "elmType": "div", + "inlineEditField": "[$FieldName]", + "txtContent": "[$FieldName]" +} +``` + +![Inline Editing using inlineEditField property](../images/sp-columnformatting-inline-editing.gif) + +This allows the users to edit items in-place, within the view, without navigating away to grid-based editing or to an item edit form. + +### Supported Field Types + +List of supported field types for inline editing: + +- Single line text +- Multiline text (without RTF) +- Number +- DateTime +- Choice and MultiChoice +- User and Multiuser +- Lookup + +### Hover Borders and Customizations + +The inline editing adds a hover border on the elements to indicate that these elements have an associated action. The default border is `neutralSecondary`, and on click, the editor appears with a `themePrimary` border. These border colors can be overridden via setting style on the same element with `inlineEditField` by using some special attributes - `--inline-editor-border-width`, `--inline-editor-border-style`, `--inline-editor-border-radius`, and `--inline-editor-border-color`. + +```json +{ + "elmType": "div", + "inlineEditField": "[$FieldName]", + "txtContent": "[$FieldName]", + "style": { + "--inline-editor-border-color": "transparent transparent red transparent", + "border-color": "gray", + "border-width": "1px", + "border-style": "solid" + } +} +``` + +## Set multiple field values of an Item using customRowAction + +With the new `setValue` and `customRowAction` properties, formatters can render action buttons that modify the item internally without opening editors or forms. `setValue` also allows setting multiple field values of the item at once. + +The below JSON will set the value of `FieldInternalName_1`, `FieldInternalName_2`, and `FieldInternalName_3`with the values provided: + +```json +{ + "elmType": "div", + "txtContent": "[$FieldName]", + "customRowAction":{ + "action": "setValue", + "actionInput": { + "FieldInternalName_1": "FieldValue_1", + "FieldInternalName_2": "FieldValue_2", + "FieldInternalName_3": "=if([$Status] == 'Completed', 'yes', 'no')" + } + } +} +``` + +### Supported Field Types + +- Single line text +- Multiline text (without RTF) +- Number +- DateTime +- Choice and MultiChoice +- User and Multiuser + +### Value Field values in `actionInput`: + +- Text values: + - a valid string like `"Choice 1"` + - value from other columns: `[$ColumnName]` + - an [expression](./formatting-syntax-reference.md#expressions) such as: + + ``` + "if([$column]> 10, "Choice A", "Choice B")" + ``` + + or + + ``` + {operator: "+", operands" : ["Choice", "A"]} + ``` + +- Number: + - a valid number + - value from other columns: `[$ColumnName]` + - an [expression](./formatting-syntax-reference.md#expressions) +- Date values: + - a date string + - `@now` token + - [expressions](./formatting-syntax-reference.md#expressions) that return a date using built-in date functions + - `addDays` and `addMinutes`, two new functions to support [expressions](./formatting-syntax-reference.md#expressions) like seven days from today + - an empty string `""` clears the field value +- Multi-Choice and Multi-Person: + - Multi-value fields are special, as they need an array value to save multiple values. + - `appendTo`, `removeFrom`, and `replace`, three functions that can operate on multivalue fields. + - `appendTo([$MultiChoiceField], 'MyValue')` + - `removeFrom([$MultiUserField], @me)`: removes all occurrences that match the second parameter + - `replace([$MultiChoiceField], 'Choice 1', 'Choice 3')`: replaces all occurrences of the second parameter with the third. +- Person field values: + - user name or email + - An empty string `""` clears the field value + - an [expression](./formatting-syntax-reference.md#expressions) which returns these values + + > [!NOTE] + > A query runs with the string value provided on the people column, and the first person in the returned results is used. diff --git a/docs/declarative-customization/formatting-syntax-reference.md b/docs/declarative-customization/formatting-syntax-reference.md new file mode 100644 index 000000000..bf3f244cf --- /dev/null +++ b/docs/declarative-customization/formatting-syntax-reference.md @@ -0,0 +1,1229 @@ +--- +title: Formatting syntax reference +description: Formatting syntax reference +ms.date: 02/19/2025 +ms.localizationpriority: high +--- + +# Formatting syntax reference + +## elmType + +Specifies the type of element to create. Valid elements include: + +- `div` +- `span` +- `a` +- [`img`](#img-src-security) +- `svg` +- `path` +- `button` +- `p` +- [`filepreview`](#filepreview) + +Any other value will result in an error. + +### filepreview + +Use the special `elmType` `filepreview` with the `src` attribute set to [`@thumbnail.`](#thumbnails) to view thumbnails for files in your document library. + +If the thumbnail loads successfully, a small [brand type icon](https://developer.microsoft.com/fluentui#/styles/web/office-brand-icons) is visible on the bottom left. If the thumbnail fails to load (or if the file type doesn't support thumbnails), a [file type icon](https://developer.microsoft.com/fluentui#/styles/web/file-type-icons) is shown instead. + +```json +"elmType": "filepreview", +"attributes": { + "src": "@thumbnail.medium" +} +``` + +### img src security + +Images from the following domains are allowed: + +- tenant domain, configured multi-geo domains and vanity domains (`company.sharepoint.com`) +- `cdn.office.net`, `akamaihd.net`, `static2.sharepointonline.com` CDNs + +Most other external image sources are blocked by default in custom formatters. To include external images and allow specific domains or CDNs, the domain needs to be added to a site-level setting. For more information see: [Allow or restrict the ability to embed content on SharePoint pages](https://support.microsoft.com/office/allow-or-restrict-the-ability-to-embed-content-on-sharepoint-pages-e7baf83f-09d0-4bd1-9058-4aa483ee137b) + +## txtContent + +An optional property that specifies the text content of the element specified by `elmType`. The value of this property can either be a string (including special strings) or an Expression object. + +## style + +An optional property that specifies style attributes to apply to the element specified by `elmType`. This is an object with name-value pairs that correspond to CSS names and values. The values of each property in the style object can either be a string (including special strings) or an Expression object. The following style attributes are allowed. + +> [!CAUTION] +> Float style prop no longer supported in custom formatter. Users are encouraged to use Gallery View as a more stable alternative. + +```javascript +'background-color' +'fill' +'background-image' +'border' +'border-bottom' +'border-bottom-color' +'border-bottom-style' +'border-bottom-width' +'border-color' +'border-left' +'border-left-color' +'border-left-style' +'border-left-width' +'border-right' +'border-right-color' +'border-right-style' +'border-right-width' +'border-style' +'border-top' +'border-top-color' +'border-top-style' +'border-top-width' +'border-width' +'outline' +'outline-color' +'outline-style' +'outline-width' +'border-bottom-left-radius' +'border-bottom-right-radius' +'border-radius' +'border-top-left-radius' +'border-top-right-radius' +'box-decoration-break' +'box-shadow' +'box-sizing' + +'overflow-x' +'overflow-y' +'overflow-style' +'rotation' +'rotation-point' + +'opacity' +'cursor' + +'height' +'max-height' +'max-width' +'min-height' +'min-width' +'width' + +'flex-grow' +'flex-shrink' +'flex-flow' +'flex-direction' +'flex-wrap' +'flex' +'justify-content' +'align-items' + +'box-align' +'box-direction' +'box-flex' +'box-flex-group' +'box-lines' +'box-ordinal-group' +'box-orient' +'box-pack' + +'font' +'font-family' +'font-size' +'font-style' +'font-variant' +'font-weight' +'font-size-adjust' +'font-stretch' + +'grid-columns' +'grid-rows' + +'margin' +'margin-bottom' +'margin-left' +'margin-right' +'margin-top' + +'column-count' +'column-fill' +'column-gap' +'column-rule' +'column-rule-color' +'column-rule-style' +'column-rule-width' +'column-span' +'column-width' +'columns' + +'padding' +'padding-bottom' +'padding-left' +'padding-right' +'padding-top' + +'bottom' +'clear' +'clip' +'display' +'float' (Deprecated) +'left' +'overflow' +'position' +'right' +'top' +'visibility' +'z-index' + +'border-collapse' +'border-spacing' +'caption-side' +'empty-cells' +'table-layout' + +'color' +'direction' +'letter-spacing' +'line-height' +'text-align' +'text-decoration' +'text-indent' +'text-transform' +'unicode-bidi' +'vertical-align' +'white-space' +'word-spacing' +'hanging-punctuation' +'punctuation-trim' +'text-align-last' +'text-justify' +'text-outline' +'text-overflow' +'text-shadow' +'text-wrap' +'word-break' +'word-wrap' + +'stroke' +'fill-opacity' + +'--inline-editor-border-width' +'--inline-editor-border-style' +'--inline-editor-border-radius' +'--inline-editor-border-color' + +'-webkit-line-clamp' + +'object-fit' +'transform' // Only translate(arg) and translate(arg, arg) are currently supported +``` + +The following example shows the value of a style object. In this example, two style properties (`padding` and `background-color`) will be applied. The `padding` value is a hard-coded string value. The `background-color` value is an Expression that is evaluated to either red (`#ff0000`) or green (`#00ff00`) depending on whether the value of the current field (specified by `@currentField`) is less than 40. For more information, see the [Expression object section](#expressions). + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "style": { + "padding": "4px", + "background-color": { + "operator": "?", + "operands": [ + { + "operator": "<", + "operands": [ + "@currentField", + 40 + ] + }, + "#ff0000", + "#00ff00" + ] + } + } +} +``` + +Here's the same sample from above, using the Excel-style expression syntax: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "style": { + "padding": "4px", + "background-color": "=if(@currentField < 40, '#ff0000', '#00ff00')" + } +} +``` + +## attributes + +The `attributes` optional property specifies more attributes to add to the element specified by `elmType`. This is an object with name-value pairs. Attribute names must be one of the following: + +- href +- rel +- src +- class +- target +- title +- role +- iconName +- d +- aria +- data-interception +- viewBox +- preserveAspectRatio +- draggable + +Any other attribute name will result in an error. Attribute values can either be Expression objects or strings. The following example adds two attributes (`target` and `href`) to the element specified by `elmType`. The `target` attribute is hard-coded to a string. The `href` attribute is an expression that will be evaluated at runtime to `http://finance.yahoo.com/quote/` + the value of the current field (`@currentField`). + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "target": "_blank", + "href": "='http://finance.yahoo.com/quote/' + @currentField" +} +``` + +## children + +The `children` optional property specifies child elements of the element specified by `elmType`. The value is specified as an array of `elm` objects. There can be an arbitrary level of nesting. If an element has the `txtContent` property, the child properties are ignored. + +## debugMode + +The `debugMode` optional property is meant for debugging. It outputs error messages and logs warnings to the console. + +## forEach + +The `forEach` optional property allows an element to duplicate itself for each member of a specific multi-value field or an array. The value of `"forEach"` property should be in the format of either `"iteratorName in @currentField"` or `"iteratorName in [$FieldName]"` or `"iteratorName in Expression-Returning-An-Array"`. + +`iteratorName` represents the name of the iterator variable that is used to represent the current member of the multi-value field. The name of the iterator can be any combination of alphanumeric characters and an underscore (`_`) that doesn't start with a digit. + +The field used in the loop must be in a supported field type with multi-value options enabled: Person, Lookup, and Choice. An expression returning an array can also be used. + +In the element with `forEach` or its children elements, the iterator variable can be referred to as if it's a new field. The index of the iterator can be accessed with `loopIndex` operator. + +`forEach` can't be applied to the root element, and will render no element if there's no value in the field. + +See [Formatting multi-value fields](column-formatting.md#formatting-multi-value-fields) for examples. + +## customRowAction + +`button` elements can be used to launch a specific action on the parent item. Every `button` element has a required property, `customRowAction`, that specifies an `action` that's taken when the button is selected. This action must be one of the following values: + +- **defaultClick**: buttons with this action will do the same thing as clicking the list item in an uncustomized view. The following example demonstrates a button that, when selected, simulates a selection on the item, which results in opening the list item. Adding this example button to a document library simulates a selection on the file or folder, which results in the file or folder being opened. + + ```json + { + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "button", + "txtContent": "Open this item", + "customRowAction": { + "action": "defaultClick" + } + } + ``` + +- **share**: Selecting the button will open the sharing dialog. The following is an example of this type of button: + + ```json + { + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "button", + "txtContent": "Share this item", + "customRowAction": { + "action": "share" + } + } + ``` + +- **delete**: Selecting the button will open the delete confirmation dialog. +- **editProps**: Selecting the button will open the item properties page in edit mode. +- **openContextMenu**: Selecting the button will open the item's default context menu. +- **setValue**: Selecting the element will update the item with the field values provided. + + ```json + { + "elmType": "div", + "txtContent": "[$FieldName]", + "customRowAction":{ + "action": "setValue", + "actionInput": { + "FieldInternalName_1": "FieldValue_1", + "FieldInternalName_2": "FieldValue_2" + } + } + } + ``` + +- **executeFlow**: Selecting the button will launch the specified Flow, specified by ID inside the `actionParams` attribute. For an example of this, see [Create a button to launch a Flow](./formatting-advanced.md#create-a-button-to-launch-a-flow). The following example demonstrates this type of button: + + ```json + { + "$schema": "https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json", + "elmType": "button", + "txtContent": "It's Flow Time!", + "customRowAction": { + "action": "executeFlow", + "actionParams": "{\"id\":\"f7ecec0b-15c5-419f-8211-302a5d4e94f1\", \"headerText\":\"It's Flow Time!\",\"runFlowButtonText\":\"Do it\"}" + } + } + ``` + + The `actionParams` attribute can have the following options when using the `executeFlow` action: + + - **id**: ID of the Flow to launch _(required)_ + - **headerText**: Sets the text at the top of the flow panel _(optional)_ + - **runFlowButtonText**: Sets the text of the primary button in the flow panel _(optional)_ + +- **embed**: Clicking on the button will open a callout with content embedded in it. The content will be determined by the URL provided in the `src` attribute in `actionInput`. You can also control the `height` and `width` of the callout using the `actionInput`. + + > [!NOTE] + > + > - The `src` needs to be just the `url` part of an embeddable code generated by an app (usually found in the `src` attribute of the `iframe` element). + > - This action is only available in the newer version of the Microsoft Lists App. + + For more information about allowing or restricting domains, see [Allow or restrict the ability to embed content on SharePoint Lists using custom formatters](https://go.microsoft.com/fwlink/p/?linkid=2258033). + + + ```json + { + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "button", + "customRowAction": { + "action": "embed", + "actionInput": { + "src": "https://www.relecloud.com/embed/ll00hWQMJxQ", + "height": "350", + "width": "700" + } + }, + "txtContent": "Click here to open recipe video 👩‍🍳" + } + ``` + + The `actionInput` attribute can have the following options when using the `embed` action: + + - **src**: The URL of the content you want to embed. _(required)_ + - **height**: The height of the callout within which the embedded content will render. The default value is 300. _(optional)_ + - **width**: The width of the callout within which the embedded content will render. The default value is 300. _(optional)_ + +## customCardProps + +Add a custom card to the element, that shows up on hover or `click` event. The following customizations are available: + +- `"formatter"`: JSON object that defines formatting for custom cards. +- `"openOnEvent"`: Event on which the customCard should open. + - Valid values: `click`, `hover` +- `"directionalHint"`: Specify the direction relative to the target in which the custom card will be positioned. This is the preferred location but it isn't guaranteed depending on space. + - Valid values: `bottomAutoEdge`, `bottomCenter`, `bottomLeftEdge`, `bottomRightEdge`, `leftBottomEdge`, `leftCenter`, `leftTopEdge`, `rightBottomEdge`, `rightCenter`, `rightTopEdge`, `topAutoEdge`, `topCenter`, `topLeftEdge`, `topRightEdge` +- `"isBeakVisible"`: Specify if the beak is to be shown or not. +- `"beakStyle"`: Specifies the style object for the custom card's beak. + +## defaultHoverField + +Adds the profile card for the people fields or file hovercard for files in the document library. + +- `"defaultHoverField": "[$Editor]"` adds a profile card for the editor field +- `"defaultHoverField": "[$FileLeafRef]"` adds a file hover card in documentLibrary + +## columnFormatterReference + +This will be replaced with the referenced column's formatter JSON. Multi-level reference isn't supported. + +References for multi-choice column formatter templates and column formatters not based on templates are not supported. + +```json +{ + "columnFormatterReference": "[$FieldName]" +} +``` + +## inlineEditField + +Adds the field editor for the referenced column. + +```json +{ + "elmType": "div", + "inlineEditField": "[$FieldName]", + "txtContent": "[$FieldName]" +} +``` + +## filePreviewProps + +The `filePreviewProps` is an optional property that allows overriding the default styles of file type icon and brand type icon in `filepreview`.elmType. + +The `fileTypeIconClass` and `brandTypeIconClass` can be used to provide CSS class names to the file type icon and the brand type icon elements respectively. + +The `fileTypeIconStyle` and `brandTypeIconStyle` can be used to provide [styles](#style) to the file type icon and the brand type icon respectively. These styles will take precedence over the same styles coming from the CSS classes provided by the above two properties. + +```json +"elmType": "filepreview", +"attributes": { + "src": "@thumbnail.medium", + }, +"filePreviewProps": { + "fileTypeIconClass": "sp-css-borderColor-neutralLight", + "fileTypeIconStyle": { + "width": "100px" + }, + "brandTypeIconClass": "sp-css-borderColor-neutralLight", + "brandTypeIconStyle": { + "width": "68px" + } +} +``` + +## Expressions + +Values for `txtContent`, style properties, and attribute properties can be expressed as expressions so that they're evaluated at runtime based on the context of the current field (or row). Expression objects can be nested to contain other Expression objects. + +Expressions can be written using Excel-style expressions in SharePoint Online and SharePoint Server Subscription Edition starting with the 22H2 feature update, or by using Abstract Syntax Tree expressions in SharePoint Online, SharePoint Server Subscription Edition, and SharePoint Server 2019. + +All fields in `ViewFields` can be referred to in expressions, even if it's marked `Explicit`. + +### Excel-style expressions + +All Excel-style expressions begin with an equal (`=`) sign. This style of expression is only available in SharePoint Online and SharePoint Server Subscription Edition starting with the 22H2 feature update. This style of expression isn't available in SharePoint Server 2019 or SharePoint Server Subscription Edition prior to the 22H2 feature update. + +This simple conditional expression evaluates to `none` if `@me` isn't equal to `[$Author.email]`, and evaluates to `''` otherwise: + +```json +=if(@me != [$Author.email], 'none', '') +``` + +More complex if/else statements can be written like the following: + +```json +=if([$Sentiment] <= 0.3, 'sp-field-severity--blocked', if([$Sentiment] < 0.9,'sp-field-severity--warning','sp-field-severity--good')) +``` + +Non-conditional operators that take one or two operands can be written like the following: + +```json +=[$foo] * -7 +``` + +```json +=sin(@currentField) +``` + +```json +=toString(60 + (sin(6.2831853 * @currentField) * 60)) +``` + +### Abstract Syntax Tree expressions + +The following example contains an Expression object that performs the expression: + +`(@currentField > 40) ? '100%' : (((@currentField * 2.5).toString() + '%')` + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "operator": "?", + "operands": [ + { + "operator": ">", + "operands": [ + "@currentField", + "40" + ] + }, + "100%", + { + "operator": "+", + "operands": [ + { + "operator": "toString()", + "operands": [ + { + "operator": "*", + "operands": [ + "@currentField", + 2.5 + ] + } + ] + }, + "%" + ] + } + ] +} +``` + +## Operators + +Operators specify the type of operation to perform. Valid operator values include: + +- `+` +- `-` +- `/` +- `*` +- `<` +- `>` +- `%` +- `==` +- `!=` +- `<=` +- `>=` +- `||` +- `&&` +- `toString()` +- `Number()` +- `Date()` +- `cos` +- `sin` +- `?` +- `:` +- `toLocaleString()` +- `toLocaleDateString()` +- `toLocaleTimeString()` +- `indexOf` +- `toLowerCase` +- `join` +- `length` +- `abs` +- `loopIndex` +- `floor` +- `ceiling` +- `pow` +- `substring` +- `getDate` +- `getMonth` +- `getYear` +- `toUpperCase` +- `lastIndexOf` +- `startsWith` +- `endsWith` +- `replace` +- `replaceAll` +- `padStart` +- `padEnd` +- `getThumbnailImage` +- `getUserImage` +- `addDays` +- `addMinutes` +- `appendTo` +- `removeFrom` +- `split` + +**Binary arithmetic operators** - The standard arithmetic binary operators that expect two operands include are: + +- `+` +- `-` +- `/` +- `*` +- `<` +- `>` +- `%` +- `==` +- `!=` +- `<=` +- `>=` + +**Unary operators** - The standard unary operators that expect only one operand are: + +- `toString()`: returns a string representing the object + - `"txtContent": "=toString(45)"` results in _"45"_ +- `Number()`: returns the numeric value, if the operand isn't a number, NaN is returned + - `"txtContent": "=Number('365')"` results in _365_ + - `"txtContent": "=Number('Wowee')"` results in _NaN_ + - `"txtContent": "=Number(Date('12/26/1981'))"` results in _378190800000_ +- `Date()`: returns a datetime object from the parameter (converts strings or numbers to dates, sensitive to locale) + - `"txtContent": "=Date('12/26/1981')"` results in _12/26/1981, 12:00:00 AM_ +- `cos`: returns the cosine of the specified angle that should be specified in radians + - `"txtContent": "=cos(5)"` results in _0.28366218546322625_ +- `sin`: returns the sine of a number + - `"txtContent": "=sin(90)"` results in _0.8939966636005579_ +- `toDateString()`: returns a date in a short-friendly format + - `"txtContent": "=toDateString(@now)"` result doesn't vary based on the user's locale and it will look like _"Wed Aug 03 2022"_ +- `toLocaleString()`: returns a language-sensitive representation of a date + - `"txtContent":"=toLocaleString(@now)"` results vary based on the user's locale, but en-us looks like _"2/5/2019, 1:22:24 PM"_ +- `toLocaleDateString()`: returns a language-sensitive representation of just the date portion of a date + - `"txtContent":"=toLocaleDateString(@now)"` results vary based on the user's locale, but en-us looks like _"2/5/2019"_ +- `toLocaleTimeString()`: returns a language-sensitive representation of just the time portion of a date + - `"txtContent":"=toLocaleTimeString(@now)"` results vary based on the user's locale, but en-us looks like _"1:22:24 PM"_ +- `toLowerCase`: returns the value converted to lower case (only works on strings) - _Only available in SharePoint Online_ + - `"txtContent":"=toLowerCase('DogFood')"` results in _"dogfood"_ +- `abs`: returns the absolute value for a given number - _Only available in SharePoint Online_ + - `"txtContent":"=abs(-45)"` results in _45_ +- `length`: returns the number of items in an array (multi-select person or choice field), for all other value types it returns 1 when true and 0 when false. It does NOT provide the length of a string value (*see the `indexOf` workaround explained later on for such operation*). - _Only available in SharePoint Online_ + - `"txtContent":"=length(@currentField)"` might result in _2_ if there are two selected values + - `"txtContent":"=length('Some Text')"` results in _1_ + - `"txtContent":"=length('')"` results in _0_ + - `"txtContent":"=length(45)"` results in _1_ + - `"txtContent":"=length(0)"` results in _0_ +- `floor`: returns the largest integer less than or equal to a given number. - _Only available in SharePoint Online_ + - `"txtContent":"=floor(45.5)"` results in _45_ +- `ceiling`: rounds the given number up to the next largest whole number or integer. - _Only available in SharePoint Online_ + - `"txtContent":"=ceiling(45.5)"` results in _46_ +- `getDate`: returns the day of the month of the given date. - _Only available in SharePoint Online_ + - `"txtContent":"=getDate(Date('12/26/1981'))"` results in _26_ +- `getMonth`: returns the month in the specified date according to local time, as a zero-based value (where zero indicates the first month of the year). - _Only available in SharePoint Online_ + - `"txtContent":"=getMonth(Date('12/26/1981'))"` results in _11_ +- `getYear`: returns the year of the given date. - _Only available in SharePoint Online_ + - `"txtContent":"=getYear(Date('12/26/1981'))"` results in _1981_ +- `toUpperCase`: returns the value converted to upper case (only works on strings) - _Only available in SharePoint Online_ + - `"txtContent":"=toUpperCase('DogFood')"` results in _"DOGFOOD"_ + +**Binary operators** - The following are operators that expect two operands: + +- `indexOf`: takes two operands. The first is the text (or array) you would like to search within, the second is the text you would like to search for. Returns the index value of the first occurrence of the search term within the string (or array). Indexes start at 0. If the search term isn't found within the text (or array), -1 is returned. This operator is case-sensitive. - _Only available in SharePoint Online_ + - `"txtContent": "=indexOf('DogFood', 'Dog')"` results in _0_ + - `"txtContent": "=indexOf('DogFood', 'F')"` results in _3_ + - `"txtContent": "=indexOf('DogFood', 'Cat')"` results in _-1_ + - `"txtContent": "=indexOf('DogFood', 'f')"` results in _-1_ +- `join`: takes two operands. The first is an array (multi-select person or choice field) and the second is the separating string. Returns a string concatenation of the array values separated by the separating string. - _Only available in SharePoint Online_ + - `"txtContent": "=join(@currentField, ', ')"` might result in _"Apple, Orange, Cherry"_ (depending on the selected values) + - `"txtContent": "=join(@currentField.title, '|')"` might result in _"Megan Bowen|Alex Wilber"_ (depending on the selected persons) +- `pow`: returns the base to the exponent power. - _Only available in SharePoint Online_ + - `"txtContent":"=pow(2,3)"` results in _8_ +- `lastIndexOf`: returns the position of the last occurrence of a specified value in a string (or array) + - `"txtContent": "=lastIndexOf('DogFood DogFood', 'Dog')"` results in _8_ + - `"txtContent": "=lastIndexOf('DogFood DogFood', 'F')"` results in _11_ + - `"txtContent": "=lastIndexOf('DogFood DogFood', 'Cat')"` results in _-1_ + - `"txtContent": "=lastIndexOf('DogFood DogFood', 'f')"` results in _-1_ +- `startsWith`: determines whether a string begins with the characters of a specified string + - `"txtContent":"=startsWith('DogFood', 'Dog')"` results in _true_ + - `"txtContent":"=startsWith('DogFood', 'Food')"` results in _false_ +- `endsWith`: determines whether a string ends with the characters of a specified string + - `"txtContent":"=endsWith('DogFood', 'Dog')"` results in _false_ + - `"txtContent":"=endsWith('DogFood', 'Food')"` results in _true_ +- `getUserImage`: returns a URL pointing to user's profile image for a given email and preferred size + - `"src":"=getUserImage('kaylat@contoso.com', 'small')"` returns a URL pointing to user's profile picture in small resolution + - `"src":"=getUserImage('kaylat@contoso.com', 's')"` returns a URL pointing to user's profile picture in small resolution + - `"src":"=getUserImage('kaylat@contoso.com', 'medium')"` returns a URL pointing to user's profile picture in medium resolution + - `"src":"=getUserImage('kaylat@contoso.com', 'm')"` returns a URL pointing to user's profile picture in medium resolution + - `"src":"=getUserImage('kaylat@contoso.com', 'large')"` returns a URL pointing to user's profile picture in large resolution + - `"src":"=getUserImage('kaylat@contoso.com', 'l')"` returns a URL pointing to user's profile picture in large resolution +- `appendTo`: returns an array with the given entry appended to the given array + - `"txtContent": "=appendTo(@currentField, 'Choice 4')"` returns an array with 'Choice 4' added to the @currentField array + - `"txtContent": "=appendTo(@currentField, 'kaylat@contoso.com')"` returns an array with 'kaylat@contoso.com' added to the @currentField array +- `removeFrom`: returns an array with the given entry removed from the given array, if present + - `"txtContent": "=removeFrom(@currentField, 'Choice 4')"` returns an array with 'Choice 4' removed from the @currentField array + - `"txtContent": "=removeFrom(@currentField, 'kaylat@contoso.com')"` returns an array with 'kaylat@contoso.com' removed from the @currentField array +- `split`: divides the given string into an ordered list of substrings by searching for the given pattern, and returns an array of these substrings + - `"txtContent": "=split('Hello World', ' ')"` returns an array with two strings - 'Hello' and 'World' +- `addDays`: returns a datetime object with days added (or deducted) from the given datetime value + - `"txtContent": "=addDays(Date('11/14/2021'), 3)"` returns a 11/17/2021, 12:00:00 AM + - `"txtContent": "=addDays(Date('11/14/2021'), -1)"` returns a 11/13/2021, 12:00:00 AM +- `addMinutes`: returns a datetime object with minutes added (or deducted) from the given datetime value + - `"txtContent": "=addMinutes(Date('11/14/2021'), 3)"` returns a 11/14/2021, 12:03:00 AM + - `"txtContent": "=addMinutes(Date('11/14/2021'), -1)"` returns a 11/13/2021, 11:59:00 AM + +**Ternary operators** - The following are operators that expect three operands: + +- `substring`: returns the part of the string between the start and end indices. - _Only available in SharePoint Online_ + - `"txtContent":"=substring('DogFood', 3, 4)"` results in _F_ + - `"txtContent":"=substring('DogFood', 4, 3)"` results in _F_ + - `"txtContent":"=substring('DogFood', 3, 6)"` results in _Foo_ + - `"txtContent":"=substring('DogFood', 6, 3)"` results in _Foo_ + + The substring() method returns the part of the string between the start and end indexes or to the end of the string. + +- `replace`: searches a string (or array) for a specified value and returns a new string (or array) where the specified value is replaced. For strings, only the first instance of the value will be replaced. + - `"txtContent":"=replace('Hello world', 'world', 'everyone')"` results in _Hello everyone_ + - `"txtContent":"=replace([$MultiChoiceField], 'Choice 1', 'Choice 2')"` returns an array replacing Choice 1 with Choice 2 + - `"txtContent":"=replace([$MultiUserField], @me, 'kaylat@contoso.com')"` returns an array replacing @me with 'kaylat@contoso.com' +- `replaceAll`: searches a string for a specified value and returns a new string (or array) where the specified value is replaced. For strings, all instances of the value will be replaced. + - `"txtContent":"=replaceAll('H-e-l-l-o W-o-r-l-d', '-', '')"` results in _Hello World_ +- `padStart`: pads the current string with another string until the resulting string reaches the given length. The padding is applied from the start of the current string. + - `"txtContent":"=padStart('DogFood', 10, 'A')"` results in _AAADogFood_ + - `"txtContent":"=padStart('DogFood', 10, 'AB')"` results in _ABADogFood_ + - `"txtContent":"=padStart('DogFood', 5, 'A')"` results in _DogFood_ +- `padEnd`: pads the current string with a given string until the resulting string reaches the given length. The padding is applied from the end of the current string. + - `"txtContent":"=padEnd('DogFood', 10, 'A')"` results in _DogFoodAAA_ + - `"txtContent":"=padEnd('DogFood', 10, 'AB')"` results in _DogFoodABA_ + - `"txtContent":"=padEnd('DogFood', 5, 'A')"` results in _DogFood_ +- `getThumbnailImage`: returns a URL pointing to an image for a given image field and preferred size. + - `"src":"=getThumbnailImage([$ImageField], 400, 200)"` results in a URL pointing to an image for a given image field with 400 width and 200 height + +**Conditional operator** - The conditional operator is: + +- `?`: Conditional operations written in Abstract Tree Syntax use `?` as the operator. This is to achieve an expression equivalent to `a ? b : c`, where if the expression `a` evaluates to true, then the result is `b`, else the result is `c`. For Excel-style expressions, you write these with an `if` statement. Regardless, there are three operands. The first is the condition to evaluate. The second is the result when the condition is true. The third is the result when the condition is false. + - `"txtContent":"=if(4 < 5, 'yes', 'no')"` results in _"yes"_ + - `"txtContent":"=if(4 > 5, 'yes', 'no')"` results in _"no"_ + +**Multi-value field-related operators** - The following operators are only used in a context with multi-value fields of type Person, Lookup, or Choice. + +- `length` +- `join` +- `loopIndex` + +`length`, when provided with a field name, returns the number of members in a multi-valued field. When a single-value field is provided, `length` will return 1 when there's a value in that field. + +`join` concatenates values in a multi-value field with a specified separator. The first operand shall point to a value in a multi-value field, for example `"@currentField.lookupValue"`, `"[$AssignedTo.title]"`. The second operand shall be a string literal that is the separator that joins the values together. + +`loopIndex`, when provided with the name of the iterator variable, returns the current index (starting from 0) of the iterator. The name of the iterator must be provided as a string literal. `loopIndex` would only work within the element with respective `forEach` enabled or its children elements. + +For examples, see [Formatting multi-value fields](column-formatting.md#formatting-multi-value-fields). + +**String-related operators** - Some of the previously detailed operators can be used when working with string values: + +- `+` +- `indexOf` (*for string length workaround*) + +`+` can be used when there's a need to concatenate strings, for instance: + +```txt +"txtContent": "=[$column1] + ' ' + [$column2] + 'some other text'" +``` + +`indexOf` Since the operator `length` doesn't work for string value types (it will return 1 or 0), `indexOf` can serve us as a nice workaround to get the length of a string, for instance: `indexOf([$column1] + '^', '^')`. We'll use `'^'` or any other character to use to find out the end of the string. + +## Operands + +Specifies the parameters, or operands for an expression. This is an array of Expression objects or base values. + +## Special string values + +The values for `txtContent`, styles, and attributes can be either strings or Expression objects. A few special string patterns for retrieving values from the fields in the list and the user's context are supported. + +### "@currentField" + +Will evaluate the value of the current field. + +Some field types are represented as objects. To output a value from an object, refer to a particular property inside that object. For example, if the current field is a person/group field, specify `@currentField.title` to retrieve the person's name, which is normally displayed in list views. The following are the field types that are represented as objects with a list of their properties. + +> [!NOTE] +> The `@currentField.title` returns a person's name by default. However, if the person field's Show Field has been adjusted, it may change the value of the `title` property. For example, a person field with the Show Field configured as Department will have the person's department for the `title` property. + +**People fields** + +The people field object has the following properties (with example values): + +```json +{ + "id": "122", + "title": "Kalya Tucker", + "email": "kaylat@contoso.com", + "sip": "kaylat@contoso.com", + "picture": "https://contoso.sharepoint.com/kaylat_contoso_com_MThumb.jpg?t=63576928822", + "department":"Human Resources", + "jobTitle":"HR Manager" +} +``` + +People field can have profile hover cards along with formatting: + +```json +{ + "elmType": "div", + "txtContent": "[$Editor.title]", + "defaultHoverField": "[$Editor]" +} +``` + +**Date/Time fields** + +The value of Date/Time fields can be retrieved a few different ways, depending on the date format you'd like to display. The following methods for converting date values to specific formats are supported: + +- `toLocaleString()` - Displays a date type fully expanded with date and time. +- `toLocaleDateString()` - Displays a date type with just the date. +- `toLocaleTimeString()` - Displays a date type with just the time. + +For example, the following JSON will display the current field (assuming it's a date field) as a date and time string. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "txtContent": { + "operator": "toLocaleString()", + "operands" : ["@currentField"] + } +} +``` + +Here's the same sample from above, using the Excel-style expression syntax: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "txtContent": "=toLocaleString(@currentField)" +} +``` + +**Location fields** + +The location field object has the following properties (with example values): + +```json +{ + "Address": { + "City": "Knoxville", + "CountryOrRegion": "United States", + "State": "TN", + "Street": "963 Worlds Fair Park Dr" + }, + "Coordinates": { + "Latitude": "35.961673736572266", + "Longitude": "-83.92420959472656" + }, + "DisplayName": "World's Fair Park", + "LocationUri": "https://www.bingapis.com/api/v6/localentities/8346bf26-6da4-104c-6ba5-2334b83f6ac8?setLang=en" +} +``` + +The following example shows how a location field might be used on a current field. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json", + "elmType": "div", + "style": { + "display": "block" + }, + "children": [ + { + "elmType": "a", + "txtContent": "@currentField.DisplayName", + "attributes": { + "href": "='https://www.bing.com/maps?cp=' + @currentField.Coordinates.Latitude + '~' + @currentField.Coordinates.Longitude + '&lvl=17&sV=2'", + "target": "_blank", + "title": "=@currentField.Coordinates.Latitude + ', ' + @currentField.Coordinates.Longitude" + }, + "style": { + "display": "block" + } + }, + { + "elmType": "div", + "txtContent": "@currentField.Address.Street" + }, + { + "elmType": "div", + "txtContent": "=@currentField.Address.City + ', ' + @currentField.Address.State" + }, + { + "elmType": "div", + "txtContent": "@currentField.Address.CountryOrRegion" + } + ] +} +``` + +**Lookup fields** + +The lookup field object has the following properties (with example values): + +```json +{ + "lookupId": "100", + "lookupValue": "North America", +} +``` + +The following example shows how a lookup field might be used on a current field. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "a", + "txtContent": "@currentField.lookupValue", + "attributes": { + "href": { + "operator": "+", + "operands": [ + "https://contoso.sharepoint.com/teams/Discovery/Lists/Regions/DispForm.aspx?ID=", + "@currentField.lookupId" + ] + }, + "target": "_blank" + } +} +``` + +**Hyperlink fields** + +The hyperlink field object has the following property (with example value): + +```json +{ + "desc": "SharePoint Patterns and Practices", +} +``` + +To reference the URL value, use `@currentField`. + +The following example shows how a hyperlink field might be used on a current field. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "a", + "txtContent": "@currentField.desc", + "attributes": { + "href": "@currentField", + "target": "_blank" + } +} +``` + +**Image fields** + +The image field object has the following `fileName` property: + +```json +{ + "fileName": "image.png", +} +``` +> [!NOTE] +> As of July 2024, just the `fileName` property has a value. + + +The following example shows how an image field can be used on a current field. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "img", + "attributes": { + "src": "=getThumbnailImage(@currentField, 400, 300)", + "alt": "@currentField.fileName" + }, + "style": { + "width": "100%", + "max-width": "100%" + } +} +``` + +**Approval Status fields** + +The Approval Status field object has the following property (with example value): + +```json +{ + "displayValue": "Approved", + "numeric": 0 +} +``` + +`displayValue` is a localized string of the approval status. + +`@currentField` or `[$__ModerationStatus]` will also internally map to the following internal numeric value: + +- 0: Approved +- 1: Denied +- 2: Pending +- 3: Draft +- 4: Scheduled + +`[$_ModerationStatus]` field supports comparisons to both strings and the numeric value. The numeric comparisons work across locales and languages which will be the recommended way for this field. + +The following expressions evaluate to the output on the right, for when the status is `Pending`: + +```javascript +// reading field value +"[$_ModerationStatus]" => "Pending" + +// obtaining the internal numeric value: +"=Number([$_ModerationStatus])" => 2 +"=[$_ModerationStatus.numeric]" => 2 + +// addition results in string concatenation: +"='status:'+[$_ModerationStatus]" => 'status:Pending' + +// numeric comparisons +"=([$_ModerationStatus] == 2)" => true +"=([$_ModerationStatus] != 1)" => true + +// other comparators are rarely useful, for cases where you want might want to exclude Draft & Scheduled +"=([$_ModerationStatus] < 3)" => true + +// localized string comparison, works only with one locale (en-us here) +"=if([$_ModerationStatus]=='Pending','This Works too!', 'Nope!')" => 'This Works too!' +``` + +The following example shows how an approval status field might be used on a current field: + +```json +{ + "elmType": "div", + "txtContent": "@currentField.displayValue", + "style": { + "color": "=if(@currentField == 2, 'red', '')" + } +} +``` + +### "[$FieldName]" + +The column is formatted within the context of the entire row. You can use this context to reference the values of other fields within the same row by specifying the **internal name** of the field surrounded by square brackets and preceded by a dollar sign: `[$InternalName]`. For example, to get the value of a field with an internal name of "MarchSales", use `[$MarchSales]`. + +> [!NOTE] +> Reference to other fields will work only if they are included in the same view. + +If the value of a field is an object, the object's properties can be accessed. For example, to access the "Title" property of a person field named "SalesLead", use "[$SalesLead.title]". + +### "[!FieldName]" + +In column and view formatting, you can refer to any field's metadata by specifying the **internal name** of the field surrounded by square brackets and preceded by an exclamation mark: `[!InternalName]`. + +Currently field's display name is available in this metadata, and can be accessed using `DisplayName` property: `[!SalesLead.DisplayName]`. + +### "@currentWeb" + +This will evaluate the absolute URL for the site. This is equivalent to the `webAbsoluteUrl` value within the page context. This value is only available in SharePoint Online. + +### "@me" + +This will evaluate the email address of the currently logged-in user. + +This field can be used to display the current user's email address, but more likely it will be used within conditions. The following is an example of setting the color for a person field to red when it's equal to the currently logged-in user and blue otherwise: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "txtContent": "@currentField.title", + "style": { + "color": { + "operator": "?", + "operands": [ + { + "operator": "==", + "operands": [ + "@me", + "@currentField.email" + ] + }, + "red", + "blue" + ] + } + } +} +``` + +Here's the same sample from above, using the Excel-style expression syntax: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "txtContent": "@currentField.title", + "style": { + "color": "=if(@me == @currentField.email, 'red', 'blue')" + } +} +``` + +### "@now" + +This will evaluate the current date and time. + +### "@rowIndex" + +This will evaluate the rendered index of a row within a view. This value is based on render position and will remain consistent based on position even as views are sorted and filtered. Indexes start at 0. This value is only available in SharePoint Online. + +Here's an example of using the value within a view format to apply alternating styles to rows: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", + "additionalRowClass": "=if(@rowIndex % 2 == 0,'ms-bgColor-themeLighter ms-bgColor-themeLight--hover','')" +} +``` + +### "@window.innerHeight" + +This will be evaluated to a number equal to the height of the browser window (in pixels) when the list is rendered. + +### "@window.innerWidth" + +This will evaluate to a number equal to the width of the browser window (in pixels) when the list was rendered. + +### Thumbnails + +In a document library, there's a series of tokens that can be used to retrieve the URL to the thumbnail of a file, including: + +- `@thumbnail.small`, `@thumbnail.medium`, and `@thumbnail.large` evaluate the thumbnail URL in three predefined sizes. +- `@thumbnail.` evaluates the URL to the largest thumbnail that isn't larger than the bounding size in both width and height. For example, `@thumbnail.150` evaluates to the URL to a thumbnail not larger than 150×150 pixels. +- `@thumbnail.x` evaluates the URL to the largest thumbnail that isn't larger than the bounding width and bounding height. For example, `@thumbnail.100x200` evaluates to the URL to a thumbnail not wider than 100 pixels and not higher than 200 pixels. + +These tokens will yield no value on non-file items including folders. + +> [!NOTE] +> The aspect ratio of the thumbnail generated is the same as how the file looks, changing the bounding sizes will not affect the aspect ratio of the thumbnail. + +> [!TIP] +> Thumbnails are only available for a list of supported file formats. It means that sometimes the URL generated is not accessible due to lack of support on certain formats. However, if a valid thumbnail token is set as the _only_ `src` attribute of an `img` tag, we will take care of it and hide the image when it is not available. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "img", + "attributes": { + "src": "@thumbnail.200x150", + "alt": "='Thumbnail of file ' + [$FileLeafRef]" + }, + "style": { + "width": "100%", + "max-width": "100%" + } +} +``` + +Default file hover card using FileLeafRef + +```json +{ + "elmType": "img", + "style": { + "width": "100%", + "height": "100%", + "display": "=if([$File_x0020_Type] == '', 'none', '')" + }, + "attributes": { + "src": "@thumbnail.300x300" + }, + "defaultHoverField": "[$FileLeafRef]" +} +``` + +### displayValue + +The following column types can use `displayValue` property to get the default-rendered value, based on the column setting: + +- Date/Time +- Number +- Yes/No +- Currency +- Approval Status + +```json +{ + "elmType": "div", + "txtContent": "@currentField.displayValue" +} +``` + +This also works with field name: + +```json +{ + "elmType": "div", + "txtContent": "[$FieldName.displayValue]" +} +``` + +### "@isSelected" + +This will evaluate to `true` for the selected item(s) in a view and `false` otherwise. + +### "@lcid" + +This will evaluate to the LCID of the current culture. This can be used to format the date, time, and numbers. + +### "@UIlcid" + +This will evaluate to the LCID of the current UI culture. This can be used to show localized display strings. diff --git a/docs/declarative-customization/get-started-create-site-design.md b/docs/declarative-customization/get-started-create-site-design.md index e8e45a0ad..92b22361c 100644 --- a/docs/declarative-customization/get-started-create-site-design.md +++ b/docs/declarative-customization/get-started-create-site-design.md @@ -1,145 +1,162 @@ ---- -title: Get started creating SharePoint site designs and site scripts -description: Create site designs to provide reusable lists, themes, layouts, pages, or custom actions so that your users can quickly build new SharePoint sites with the features they need. -ms.date: 04/17/2020 -localization_priority: Priority ---- - -# Get started creating site designs and site scripts - -You can create site designs to provide reusable lists, themes, layouts, pages, or custom actions so that your users can quickly build new SharePoint sites with the features they need. - -This article describes how to build a simple site design that adds a SharePoint list for tracking customer orders. You'll use the site design to create a new SharePoint site with the custom list. You'll learn how to use SharePoint PowerShell cmdlets to create site scripts and site designs. You can also use REST APIs to perform the same actions. The corresponding REST calls are shown for reference in each step. - -## Create the site script in JSON - -A site design is a collection of actions that SharePoint runs when creating a new site. Actions describe changes to apply to the new site, such as creating a new list or applying a theme. The actions are specified in a JSON script, which is a list of all actions to apply. When a script runs, SharePoint completes each action in the order listed. - -Each action is specified by the "verb" value in the JSON script. Also, actions can have subactions that are also "verb" values. In the following JSON, the script specifies to create a new list named **Customer Tracking**, and then subactions set the description and add several fields to define the list. - -1. Download and install the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588). If you already have a previous version of the shell installed, uninstall it first and then install the latest version. -1. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. -1. Create - and assign the JSON that describes the new script - to a variable as shown in the following PowerShell code. You can view and reference the latest JSON schema file here: https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json - - ```powershell - $site_script = ' - { - "$schema": "schema.json", - "actions": [ - { - "verb": "createSPList", - "listName": "Customer Tracking", - "templateType": 100, - "subactions": [ - { - "verb": "setDescription", - "description": "List of Customers and Orders" - }, - { - "verb": "addSPField", - "fieldType": "Text", - "displayName": "Customer Name", - "isRequired": false, - "addToDefaultView": true - }, - { - "verb": "addSPField", - "fieldType": "Number", - "displayName": "Requisition Total", - "addToDefaultView": true, - "isRequired": true - }, - { - "verb": "addSPField", - "fieldType": "User", - "displayName": "Contact", - "addToDefaultView": true, - "isRequired": true - }, - { - "verb": "addSPField", - "fieldType": "Note", - "displayName": "Meeting Notes", - "isRequired": false - } - ] - } - ], - "bindata": { }, - "version": 1 - } - ' - ``` - -The previous script creates a new SharePoint list named **Customer Tracking**. It sets the description and adds four fields to the list. Note that each of these are considered an action. Site scripts are limited to 30 cumulative actions (across one or more scripts that may be called in a site design) if applied programmatically using the Invoke-SPOSiteDesign command. If they are applied through the UX or using the Add-SPOSiteDesignTask command then the limit is 300 cumulative actions (or 100K characters). - -## Add the site script - -Each site script must be registered in SharePoint so that it is available to use. Add a new site script by using the **Add-SPOSiteScript** cmdlet. The following example shows how to add the JSON script described previously. - -```powershell -C:\> Add-SPOSiteScript - -Title "Create customer tracking list" - -Content $site_script - -Description "Creates list for tracking customer contact information" -``` - -After running the cmdlet, you get a result that lists the site script **ID** of the added script. Keep track of this ID somewhere because you will need it later when you create the site design. - -The REST API to add a new site script is **CreateSiteScript**. - -## Create the site design - -Next, you need to create the site design. The site design appears in a drop-down list when someone creates a new site from one of the templates. It can run one or more site scripts that have already been added. - -- Run the following cmdlet to add a new site design. Replace `` with the site script ID from when you added the site script. - -```powershell -C:\> Add-SPOSiteDesign - -Title "Contoso customer tracking" - -WebTemplate "64" - -SiteScripts "" - -Description "Tracks key customer data in a list" -``` - -The previous cmdlet creates a new site design named Contoso customer tracking. The `-WebTemplate` value selects which base template to associate with. The value `"64"` indicates Team site template, and the value `"68"` indicates the Communication site template. If you have disabled modern Group creation (or restricted to a subset of users) and wish to still allow your users to apply site designs to the "group-less" modern Team site template, publish your site designs using the `-WebTemplate` value `"1"`. - -The JSON response displays the **ID** of the new site design. You can use it in subsequent cmdlets to update or modify the site design. - -The REST API to add a new site design is **CreateSiteDesign**. - -## Use the new site design - -Now that you've added a site script and site design, you can use it to create new sites through the self-service site creation experience or apply the site design to an existing site using the **Invoke-SPOSiteDesign** command in PowerShell. If you are using hub sites you can even associate a site design to a hub so it gets applied to all joining sites. - -### New site creation - -1. Go to the home page of the SharePoint site that you are using for development. -1. Choose **Create site**. -1. Choose **Team site**. -1. In the **Choose a design** drop-down, select your site design **customer orders**. -1. In **Site name**, enter a name for the new site **Customer order tracking**. -1. Choose **Next**. -1. Choose **Finish**. -1. A notification bar will be displayed indicating that your script is being applied. To invoke the site design information panel, click the **View progress** link. Once the script(s) have completed the notification banner message will change to **Site Design applied. Refresh this site to see the changes.**, allowing you to either invoke the panel or refresh the page. -1. You will see the custom list on the page. - -### Apply to an existing site collection - -You can also apply a published site design to an existing site collection using the [Invoke-SPOSiteDesign](/powershell/module/sharepoint-online/Invoke-SPOSiteDesign) cmdlet. - -You can apply a published site design to: - -1. Group-connected Team site -1. Team site not connected to a Microsoft 365 group -1. Communication site -1. Classic team site -1. Classic publishing site - -### Associate with a hub site - -You can also associate a published site design to a hub site in hub site settings so it can be applied to all joining sites. For details on how to associate the site design either through the UI or using the `Set-SPOHubSite` cmdlet please review the [PowerShell cmdlets for SharePoint hub sites](../features/hub-site/hub-site-powershell.md) article. - -## See also - -- [SharePoint site design and site script overview](site-design-overview.md) +--- +title: Get started creating SharePoint site templates and site scripts +description: Create site templates to provide reusable lists, themes, layouts, pages, or custom actions so that your users can quickly build new SharePoint sites with the features they need. +ms.date: 09/30/2022 +ms.localizationpriority: high +--- + +# Get started creating site templates and site scripts + +You can create site templates to provide reusable lists, themes, layouts, or custom actions so that your users can quickly build new SharePoint sites with the features they need. + +This article describes how to build a simple site template that adds a SharePoint list for tracking customer orders. You'll use the site template to create a new SharePoint site with the custom list. You'll learn how to use SharePoint PowerShell cmdlets to create site scripts and site templates. You can also use REST APIs to perform the same actions. The corresponding REST calls are shown for reference in each step. + +## Create the site script in JSON + +A site script is a collection of actions that SharePoint runs when creating a new site. Actions describe changes to apply to the new site, such as creating a new list or applying a theme. The actions are specified in a JSON script, which is a list of all actions to apply. When a script runs, SharePoint completes each action in the order listed. + +Each action is specified by the "verb" value in the JSON script. Also, actions can have subactions that are also "verb" values. In the following JSON, the script specifies to create a new list named **Customer Tracking**, and then subactions set the description and add several fields to define the list. + +1. Download and install the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588). If you already have a previous version of the shell installed, uninstall it first and then install the latest version. +1. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. +1. Create - and assign the JSON that describes the new script - to a variable as shown in the following PowerShell code. You can view and reference the latest JSON schema file: [https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json](https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json) + + ```powershell + $site_script = ' + { + "$schema": "https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json", + "actions": [ + { + "verb": "createSPList", + "listName": "Customer Tracking", + "templateType": 100, + "subactions": [ + { + "verb": "setDescription", + "description": "List of Customers and Orders" + }, + { + "verb": "addSPField", + "fieldType": "Text", + "displayName": "Customer Name", + "isRequired": false, + "addToDefaultView": true + }, + { + "verb": "addSPField", + "fieldType": "Number", + "displayName": "Requisition Total", + "addToDefaultView": true, + "isRequired": true + }, + { + "verb": "addSPField", + "fieldType": "User", + "displayName": "Contact", + "addToDefaultView": true, + "isRequired": true + }, + { + "verb": "addSPField", + "fieldType": "Note", + "displayName": "Meeting Notes", + "isRequired": false + } + ] + } + ] + } + ' + ``` + +The previous script creates a new SharePoint list named **Customer Tracking**. It sets the description and adds four fields to the list. Note that each of these are considered an action. Site scripts are limited to 30 cumulative actions (across one or more scripts that may be called in a site template) if applied programmatically using the `Invoke-SPOSiteDesign` command. If they are applied through the UI or using the `Add-SPOSiteDesignTask` command then the limit is 300 cumulative actions (or 100K characters). + +## Add the site script + +Each site script must be registered in SharePoint so that it is available to use. Add a new site script by using the **Add-SPOSiteScript** cmdlet. The following example shows how to add the JSON script described previously. + +```powershell +C:\> Add-SPOSiteScript + -Title "Create customer tracking list" + -Content $site_script + -Description "Creates list for tracking customer contact information" +``` + +After running the cmdlet, you get a result that lists the site script **ID** of the added script. Keep track of this ID somewhere because you will need it later when you create the site template. + +The REST API to add a new site script is **CreateSiteScript**. + +## Create the site template + +Next, you need to create the site template. The site template appears in a drop-down list when someone creates a new site from one of the templates. It can run one or more site scripts that have already been added. + +- Run the following cmdlet to add a new site template. Replace `` with the site script ID from when you added the site script. + +```powershell +C:\> Add-SPOSiteDesign + -Title "Contoso customer tracking" + -WebTemplate "64" + -SiteScripts "" + -Description "Tracks key customer data in a list" +``` + +The previous cmdlet creates a new site template named Contoso customer tracking. + +| Parameter | Value | Site template type | +| :---------- | :---- | :--------------------------------------- | +| WebTemplate | 64 | Team site template | +| WebTemplate | 1 | Team site (with group creation disabled) | +| WebTemplate | 68 | Communication site template | +| WebTemplate | 69 | Channel site template | + +The JSON response displays the **ID** of the new site template. You can use it in subsequent cmdlets to update or modify the site template. + +The REST API to add a new site template is **CreateSiteDesign**. + +## Use the new site template + +Now that you've added a site script and site template, you can use it to create new sites through the self-service site creation experience or apply the site template to an existing site using the **Invoke-SPOSiteDesign** command in PowerShell. If you are using hub sites you can even associate a site template to a hub so it gets applied to all joining sites. + +### New site creation + +1. Go to the home page of the SharePoint site that you are using for development. +1. Choose **Create site**. +1. Choose the type of site you need to use. SharePoint will create a team site using the Microsoft **Team collaboration template** or a communication site using the Microsoft **Topic** template unless another custom site template is set as default. +1. Choose **Next**. +1. In **Site name**, enter a name for the new site **Customer order tracking**. +1. Choose **Finish**. +1. Next, go to **Settings** and select **Apply a site template**. +1. Select the site template you just created. +1. Once applied, your new template will display under the tab in the template viewer titled **From your organization.** +1. When the new template has been applied, you will see the custom list on the page. + +### Apply to an existing site + +You can also apply a published site template to existing sites. On the home page of the site, site owners can navigate to **Settings** and then **Apply a site template** to browse and apply templates provided by your organization and Microsoft. + +You can apply templates to existing site collections in bulk by using the [Invoke-SPOSiteDesign](/powershell/module/sharepoint-online/Invoke-SPOSiteDesign) cmdlet. + +**Published site templates can be applied to:** + +1. Group-connected team sites +1. Team sites that not connected to a Microsoft 365 group +1. Communication sites +1. Channel sites +1. Classic team sites +1. Classic publishing sites + +The REST API to apply a site template to an existing site collection is **ApplySiteDesign**. + +### Associate with a hub site + +Apply a published site template to a new or existing hub site. Then, all associated sites will inherit the hub site template and theme. Navigate to the home page of the hub and go to **Settings** and then **Apply a site template**. Learn more about how to [enable site associations for your hub site](https://support.microsoft.com/office/set-up-your-sharepoint-hub-site-e2daed64-658c-4462-aeaf-7d1a92eba098). + +You can also use the `Set-SPOHubSite` cmdlet. Review the [PowerShell cmdlets for SharePoint hub sites](../features/hub-site/hub-site-powershell.md) article. + +>[!NOTE] +> [Channel sites](/sharepoint/teams-connected-sites) are automatically blocked from joining a hub site. + +## See also + +- [SharePoint site template and site script overview](site-design-overview.md) +- [How to apply and customize SharePoint site templates](https://support.microsoft.com/office/apply-and-customize-sharepoint-site-templates-39382463-0e45-4d1b-be27-0e96aeec8398) diff --git a/docs/declarative-customization/list-form-conditional-show-hide.md b/docs/declarative-customization/list-form-conditional-show-hide.md index 09f8d4a3f..1d4afe455 100644 --- a/docs/declarative-customization/list-form-conditional-show-hide.md +++ b/docs/declarative-customization/list-form-conditional-show-hide.md @@ -1,8 +1,8 @@ --- title: Show or hide columns in a list form description: Customize which columns to show or hide using a conditional formula in the list form by constructing a simple formula that are equations performing conditional checks on values in a SharePoint list or library. -ms.date: 05/07/2021 -localization_priority: Priority +ms.date: 07/28/2025 +ms.localizationpriority: high --- # Show or hide columns in a list or library form @@ -27,7 +27,7 @@ To show or hide a column in a list or library form: 1. In the **Edit columns** pane, check (to show) or uncheck (to hide) the checkbox for the column or columns as needed. > [!NOTE] - > If you want to re-arrange the order of the columns, either drag-and-drop the column name, or first select the far right hand edge of the column name to display the options menu **(...)** and then select Move Up or Move Down as preferred. + > If you want to re-arrange the order of the columns, either drag-and-drop the column name or first select the far right-hand edge of the column name to display the options menu **(...)** and then select Move Up or Move Down as preferred. 1. When you're finished, select **Save**. @@ -38,7 +38,7 @@ You can show or hide columns in a list form based on another column's value by s To specify a conditional formula for a column, in the **Edit columns** pane: 1. Navigate to the desired column for which you want to set a conditional formula -1. Select the far right hand edge of the column name to display the options menu **(...)** +1. Select the far right-hand edge of the column name to display the options menu **(...)** 1. In the more options, select **Edit conditional formula**. 1. In the **Edit conditional formula** dialog: - To determine whether this column is shown or hidden, specify a conditional formula based on the value of another column. @@ -56,21 +56,22 @@ For example, the following formula checks if the value for the *Category* column =if([$Category] == 'Product Management', 'true', 'false') ``` -Returning _true_ results in showing the column on the form while returning _false_ hides the column. +Returning _true_ shows the column on the form while returning _false_ hides the column. -The column is represented by specifying the **internal name** of the field surrounded by square brackets and preceded by a dollar sign: `[$InternalName]`. For example, to get the value of a field with an internal name of "ProductName", use `[$ProductName]`. +The column is represented by specifying the **internal name** of the field preceded by a dollar sign and surrounded by square brackets: `[$InternalName]`. For example, to get the value of a field with an internal name of "ProductName", use `[$ProductName]`. #### Unsupported column types in conditional formulas While the formula supports many of the available column types, we do not currently support the following column types: -* Person or Group with multiple selections -* Choice with multiple selections -* Time calculations in Date and Time column -* Currency columns -* Location columns -* Calculated columns -* Managed Metadata columns +- Person or Group with multiple selections +- Choice with multiple selections +- Lookup with multiple selections +- Time calculations in **Date and Time** column +- Currency columns +- Location columns +- Calculated columns +- Managed Metadata columns #### Quick formula reference @@ -98,7 +99,7 @@ You can also do arithmetic calculations, such as adding the value of two columns ##### Date column -The following formula checks if the date column `[$StartDate]` is equal to a specific date. To do so, it uses the *Date()* function to convert a given string into a date: +The following formula checks if the date column `[$StartDate]` equals a specific date. To do so, it uses the *Date()* function to convert a given string into a date: ``` =if([$StartDate] == Date('4/6/2020'), 'true', 'false') @@ -126,17 +127,26 @@ The following formula checks if an email of person column `[$Owner]` is equal to ##### Boolean (Yes/No) column -The following formula checks if the Yes/No column `[$Promoted]` is equal to a Yes. To do so, it checks for the value _true_ which maps to _Yes_ for users. +The following formula checks if the Yes/No column `[$Promoted]` equals a Yes. To do so, it checks for the value _true_ which maps to _Yes_ for users. ``` =if([$Promoted] == true, 'true', 'false') ``` +The following are also valid: + +``` +=if([$Promoted], 'true', 'false') +``` + +``` +=[$Promoted] +``` + ##### Lookup column > [!NOTE] -> When accessing lookup columns in column or view formatting, you have access to the lookup value and lookup id as separate values. In form formatting and conditional field expressions, both values are returned as a single line of text. For instance, a lookup column referencing an item with item ID 1 (in the source list) with a value of `Toronto` will have a value of `1;#Toronto` when used in form formatting or conditional field expressions. - +> When accessing lookup columns in a column or view formatting, you can access the lookup value and lookup id as separate values. In form formatting and conditional field expressions, both values are returned as a single line of text. For instance, a lookup column referencing an item with item ID 1 (in the source list) with a value of `Toronto` will have a value of `1;#Toronto` when used in form formatting or conditional field expressions. The following formula checks if the lookup column `[$City]` has a value equal to *Toronto*. To do so, it splits the lookup value result by the separator and checks against the value. diff --git a/docs/declarative-customization/list-form-configuration.md b/docs/declarative-customization/list-form-configuration.md index 9238a0176..ab641654f 100644 --- a/docs/declarative-customization/list-form-configuration.md +++ b/docs/declarative-customization/list-form-configuration.md @@ -1,15 +1,15 @@ --- title: Configure the list form description: Configure list form with a custom header, footer and body with one or more sections. -ms.date: 04/23/2021 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Configure the list form -You can configure the list form in a list or library with a custom header, footer and the form body with one or more sections with fields in each of those sections. The form configuration does not change the data in the list item or file; it only changes how the form is displayed to users who browse the list or library. Anyone who can create and manage views in a list can use form configuration to configure the form with header, footer and body with sections. +You can configure the list form in a list or library with a custom header, footer and the form body with one or more sections with fields in each of those sections. The form configuration does not change the data in the list item or file; it only changes how the form is displayed to users who browse the list or library. Anyone who can create and manage views in a list can use form configuration to configure the form with header, footer, and body with sections. -To configure a form, you will use JSON formatters that you are already familiar with when formatting a [column](column-formatting.md) or a [view](view-formatting.md) in a list or library. Form configuration allows for certain predefined elements and attributes to build the custom header, footer and body with one or more sections. +To configure a form, you will use JSON formatters that you are already familiar with when formatting a [column](column-formatting.md) or a [view](view-formatting.md) in a list or library. Form configuration allows for certain predefined elements and attributes to build the custom header, footer, and body with one or more sections. ## Get started @@ -18,23 +18,24 @@ To configure the form in a list or library: 1. Go to the list or library for which you want to configure the form. 1. If you are in a list: - - Open an item to view the item details in the display form. + - Open an item to view the item details in the display form. 1. If you are in a document library: - - Select a file. - - Select ... - - Select More - - Select Properties + - Select a file. + - Select ... + - Select More + - Select Properties 1. At the top of the form, expand **Edit Form** icon and then select **Configure layout** ![Configure list form](images/list-form-configuration-menu.png) 1. In the **Format** pane, you can choose to apply formatting to the following form sections: - - Header - - Body - - Footer + + - Header + - Body + - Footer ## Configure custom header @@ -50,66 +51,67 @@ To configure the form in a list or library: ```JSON { - "elmType": "div", - "attributes": { - "class": "ms-borderColor-neutralTertiary" - }, - "style": { - "width": "99%", - "border-top-width": "0px", - "border-bottom-width": "1px", - "border-left-width": "0px", - "border-right-width": "0px", - "border-style": "solid", - "margin-bottom": "16px" - }, - "children": [ + "elmType": "div", + "attributes": { + "class": "ms-borderColor-neutralTertiary" + }, + "style": { + "width": "99%", + "border-top-width": "0px", + "border-bottom-width": "1px", + "border-left-width": "0px", + "border-right-width": "0px", + "border-style": "solid", + "margin-bottom": "16px" + }, + "children": [ + { + "elmType": "div", + "style": { + "display": "flex", + "box-sizing": "border-box", + "align-items": "center" + }, + "children": [ { - "elmType": "div", - "style": { - "display": "flex", - "box-sizing": "border-box", - "align-items": "center" - }, - "children": [ - { - "elmType": "div", - "attributes": { - "iconName": "Group", - "class": "ms-fontSize-42 ms-fontWeight-regular ms-fontColor-themePrimary", - "title": "Details" - }, - "style": { - "flex": "none", - "padding": "0px", - "padding-left": "0px", - "height": "36px" - } - } - ] - }, + "elmType": "div", + "attributes": { + "iconName": "Group", + "class": "ms-fontSize-42 ms-fontWeight-regular ms-fontColor-themePrimary", + "title": "Details" + }, + "style": { + "flex": "none", + "padding": "0px", + "padding-left": "0px", + "height": "36px" + } + } + ] + }, + { + "elmType": "div", + "attributes": { + "class": "ms-fontColor-neutralSecondary ms-fontWeight-bold ms-fontSize-24" + }, + "style": { + "box-sizing": "border-box", + "width": "100%", + "text-align": "left", + "padding": "21px 12px", + "overflow": "hidden" + }, + "children": [ { - "elmType": "div", - "attributes": { - "class": "ms-fontColor-neutralSecondary ms-fontWeight-bold ms-fontSize-24" - }, - "style": { - "box-sizing": "border-box", - "width": "100%", - "text-align": "left", - "padding": "21px 12px", - "overflow": "hidden" - }, - "children": [ - { - "elmType": "div", - "txtContent": "='Contact details for ' + [$Title]" - } - ] + "elmType": "div", + "txtContent": "='Contact details for ' + [$Title]" } - ] + ] + } + ] } ``` + 1. To preview your changes, click the **Preview** button. 1. To save your changes, click the **Save** button. 1. Close and open the form again to view the custom header. @@ -172,7 +174,7 @@ To configure the form in a list or library: - One or more sections can be defined for a body. - Each section can reference one or more columns in the list or library. - A column can be referenced only in one section. - - If a column is referenced in multiple sections, the first section where the column is referenced will take the precedence. + - If a column is referenced in multiple sections, the first section where the column is referenced will take precedence. - A column not referenced in any of the sections will be automatically referenced in the last section. - New columns added will be automatically referenced in the last section. @@ -180,23 +182,23 @@ To configure the form in a list or library: ```JSON { - "sections": [ - { - //give a display name for the section - "displayname": "", - "fields": [ - //reference your fields here using their display name - "Title" - ] - }, - { - //give a display name for the section - "displayname": "", - "fields": [ - //reference your fields here using their display name - ] - } - ] + "sections": [ + { + //give a display name for the section + "displayname": "", + "fields": [ + //reference your fields here using their display name + "Title" + ] + }, + { + //give a display name for the section + "displayname": "", + "fields": [ + //reference your fields here using their display name + ] + } + ] } ``` @@ -204,30 +206,30 @@ To configure the form in a list or library: ```JSON { - "sections": [ - { - "displayname": "", - "fields": [ - "Title" - ] - }, - { - "displayname": "Details", - "fields": [ - "Department", - "Email", - "Country" - ] - }, - { - "displayname": "Application", - "fields": [ - "Application Id", - "Approver", - "Reviewer" - ] - } - ] + "sections": [ + { + "displayname": "", + "fields": [ + "Title" + ] + }, + { + "displayname": "Details", + "fields": [ + "Department", + "Email", + "Country" + ] + }, + { + "displayname": "Application", + "fields": [ + "Application Id", + "Approver", + "Reviewer" + ] + } + ] } ``` @@ -241,3 +243,60 @@ To configure the form in a list or library: 1. To preview your changes, click the **Preview** button. 1. To save your changes, click the **Save** button. 1. Close and open the form again to view the custom body. + + +## Custom Formatter for Read-Only Fields + +### Introduction + +Microsoft Lists offers a powerful way to organize information and collaborate with your team. With the rise of AI-based list item creation, users often need to view but not edit certain fields — like system-generated data or bot-added details. To meet this need, a new custom formatter feature is proposed to allow fields to appear as read-only in list forms. + +### Why Read-Only Fields Matter + +Currently, read-only fields are hidden from New Item and Edit forms. This creates challenges when AI bots or automated processes create items containing critical data that users need to see but not modify. For example: + +- A bot creates a customer service ticket with Issue details Issue Title, Issue Description. +- Users should see this information to take actions (e.g., send an email), but not be able to change it. + +The new custom formatter solves this by allowing these fields to display as read-only. + +### How the Custom Formatter Works + +The custom formatter introduces a new JSON configuration to mark fields as read-only in the form views. + +### JSON Structure + +```json +{ + "sections": [{}], + "fieldsettings": [ + { + "name": "fieldName", + "readonly": true + } + ] +} +``` + +- name: The internal name of the field. +- readonly: When set to true, the field is displayed as read-only. + +### Behavior in Different Form Views + +The custom formatter ensures a consistent user experience: + +- New Item form: The read-only field will not be shown. +- Edit form: The field is displayed without an editable textbox, similar to a Calculated Column. +- Edit all mode: The field remains visible and uneditable. + +The Save button works as expected — no accidental modifications to the read-only fields. + +### Example Use Case + +Imagine a CRM bot creating tickets with pre-filled Issue details. Using this formatted: + +- Issue Title (read-only): Users can see and copy the Issue Title but can't modify it. +- Issue Description (read-only): Users can see and copy the Issue Description but can't modify it. +- Issue Source (read-only): Users can click on the Issue source link but can't modify it. + +![image](https://github.com/user-attachments/assets/74c21844-a966-4930-93bb-cce10d69fa0e) diff --git a/docs/declarative-customization/site-design-json-schema.md b/docs/declarative-customization/site-design-json-schema.md index f9636ff8c..2ed0397a6 100644 --- a/docs/declarative-customization/site-design-json-schema.md +++ b/docs/declarative-customization/site-design-json-schema.md @@ -1,13 +1,13 @@ --- -title: Site design JSON schema -description: JSON schema reference for building site designs for SharePoint. -ms.date: 10/09/2020 -localization_priority: Priority +title: Site template JSON schema +description: JSON schema reference for building site templates for SharePoint. +ms.date: 11/18/2024 +ms.localizationpriority: high --- -# Site design JSON schema +# Site template JSON schema -The site design is a list of **actions**. For more complex actions, such as creating a list, there are also **subactions**. Each action is specified by a "verb" value. Verb actions are run in the order they appear in the JSON script. Only the verb actions listed here can be used; otherwise, an "unable to handle action" error will be thrown when trying to upload a site script. More actions will be added over time. +The site template is a list of **actions**. For more complex actions, such as creating a list, there are also **subactions**. Each action is specified by a "verb" value. Verb actions are run in the order they appear in the JSON script. Only the verb actions listed here can be used; otherwise, an "unable to handle action" error will be thrown when trying to upload a site script. More actions will be added over time. The overall JSON structure is specified as follows: @@ -18,44 +18,65 @@ The overall JSON structure is specified as follows: ... ... - ], - "bindata": { }, - "version": 1 + ] } ``` -You can view - and reference - the latest schema here: https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json +> [!TIP] +> You can view - and reference - the latest schema here: https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json + +> [!NOTE] +> **Actions** can be run more than once on a site. Rerunning **actions** on the same site with the same parameters will result in an update to the existing schema and not duplication of schema. + + + +## addContentTypesFromHub + +Use the **addContentTypesFromHub** verb to sync content types from a content type hub to the site. -#### Applying site designs multiple times +> [!NOTE] +> Once **addContentTypesFromHub** is applied on a site, the **addContentType** subaction on a list will be able to add it to the list by name. + +### JSON value + +- `ids`: An array of the content type IDs that need to be synced. + +#### Example + +```json +{ + "verb": "addContentTypesFromHub", + "ids": ["0x01007CE30DD1206047728BAFD1C39A850120"] +} +``` -**Actions** can be run more than once on a site. Rerunning **actions** on the same site with the same parameters will result in an update to the existing schema and not duplication of schema. ## Create a new SharePoint list Use the **createSPList** verb to create a new SharePoint list. > [!NOTE] -> Once **createSPList** is applied on a site, runnning the **createSPList** with the same list name will act as an update to the existing list. +> Once **createSPList** is applied on a site, running the **createSPList** with the same list name will act as an update to the existing list. -#### JSON values +### JSON values - `listName`: The name of the list. -- `templateType`: Which template to apply to the list. Typically you would use value 100. The full list of template type values is documented in [SPListTemplateType enumeration](/previous-versions/office/sharepoint-server/ms413878(v=office.15)) - but the ones we currently support include: +- `templateType`: Which template to apply to the list. Typically, you would use value 100. The full list of template type values is documented in [SPListTemplateType enumeration](/previous-versions/office/sharepoint-server/ms413878(v=office.15)) - but the ones we currently support include: | List Template Name | Enum | - |--------------|---------| - Generic List | 100 - Document Library | 101 - Survey | 102 - Links | 103 - Announcements | 104 - Contacts | 105 - Events | 106 - Tasks | 107 - Discussion Board | 108 - PictureLibrary | 109 - Site Pages | 119 - Issue Tracking | 1100 + | ------------------ | ---- | + | Generic List | 100 | + | Document Library | 101 | + | Survey | 102 | + | Links | 103 | + | Announcements | 104 | + | Contacts | 105 | + | Events | 106 | + | Tasks | 107 | + | Discussion Board | 108 | + | PictureLibrary | 109 | + | Site Pages | 119 | + | Issue Tracking | 1100 | If you use 101 or 119 and reference the default names ("Documents" or "Site Pages"), you can modify the library created with the template. See example below. - `subactions`: An array of actions that run in the order listed to create your list. @@ -152,7 +173,7 @@ Deletes a default field that was provided by the selected template type. ### addSPFieldXml -Enables defining fields and their elements using Collaborative Application Markup Language (CAML). For reference, see [Field element (Field)](https://docs.microsoft.com/sharepoint/dev/schema/field-element-field). Providing the ID attribute in the field schemaXml is important in order to prevent the field from being created multiple times if the script is run more than once. +Enables defining fields and their elements using Collaborative Application Markup Language (CAML). For reference, see [Field element (Field)](/sharepoint/dev/schema/field-element-field). Providing the ID attribute in the field schemaXml is important in order to prevent the field from being created multiple times if the script is run more than once. Currently these field constructs can't be designated as site columns nor added to content types. To create site columns with Field XML, use the **createSiteColumnXml** action. @@ -172,7 +193,7 @@ Currently these field constructs can't be designated as site columns nor added t ### addSPLookupFieldXml -Enables defining lookup fields and their dependent lists element using Collaborative Application Markup Language (CAML). For reference, see [Field element (Field)](https://docs.microsoft.com/sharepoint/dev/schema/field-element-field). Providing the ID attribute in the field schemaXml is important in order to prevent the field from being created multiple times if the script is run more than once. +Enables defining lookup fields and their dependent lists element using Collaborative Application Markup Language (CAML). For reference, see [Field element (Field)](/sharepoint/dev/schema/field-element-field). Providing the ID attribute in the field schemaXml is important in order to prevent the field from being created multiple times if the script is run more than once. #### JSON value @@ -198,7 +219,7 @@ Subaction to add a previously defined site column directly to a list (existing o #### JSON value - `internalName`: The internal name of the site column to add. -- `addToDefaultView`: Optional attribute that defaults to false. If true, the newly added field will also be added to the default view. +- `addToDefaultView`: Optional attribute that defaults to **False**. If **True**, the newly added field will also be added to the default view. #### Example @@ -218,12 +239,12 @@ Defines and adds a view to the list. Use this action to specify the desired colu - `name`: The name of the view. - `viewFields`: An array of the internal names of the fields in your view. -- `query`: A CAML query string that contains the `where` clause for the view's query. See [CAML schemas] (https://docs.microsoft.com/sharepoint/dev/schema/collaborative-application-markup-language-caml-schemas). +- `query`: A CAML query string that contains the `where` clause for the view's query. See [CAML schemas](/sharepoint/dev/schema/collaborative-application-markup-language-caml-schemas). - `rowLimit`: The row limit of the view. - `isPaged`: Specifies whether the view is paged. - `makeDefault`: If **True**, the view will be made the default for the list; otherwise, **False**. - `scope`: An optional setting to specify the scope of the view. For more information, see [SPViewScope enumeration](/previous-versions/office/sharepoint-server/ms458474(v=office.15)). -- `formatterJSON`: An optional setting to specify the JSON formatting for the view +- `formatterJSON`: An optional setting to specify the JSON formatting for the view. #### Example @@ -357,7 +378,7 @@ In this example, we are formatting a number column as a data bar. ### associateFieldCustomizer -Registers field extension for a list field. For more information on these client-side extensions, see [Build field customizer](https://docs.microsoft.com/sharepoint/dev/spfx/extensions/get-started/building-simple-field-customizer) tutorial. +Registers field extension for a list field. For more information on these client-side extensions, see [Build field customizer](/sharepoint/dev/spfx/extensions/get-started/building-simple-field-customizer) tutorial. #### JSON values @@ -396,7 +417,7 @@ Registers field extension for a list field. For more information on these client "verb": "associateFieldCustomizer", "internalName": "ElectricSlide", "clientSideComponentId": "35944670-3111-4482-b152-9e9d1sean9f7", - "clientSideComponentProperties": "{\"sampleText\":\"Yes - added by a site design, what?\"}" + "clientSideComponentProperties": "{\"sampleText\":\"Yes - added by a site template, what?\"}" } ] } @@ -409,7 +430,7 @@ Associates a ListViewCommandSet to the list #### JSON values - `title`: The title of the extension. -- `location`: A required parameter to specify where the command is displayed. Options are: ContextMenu or CommandBar. +- `location`: A required parameter to specify where the command is displayed. Options are: ClientSideExtension.ListViewCommandSet.ContextMenu or ClientSideExtension.ListViewCommandSet.CommandBar. - `clientSideComponentId`: The identifier (GUID) of the extension in the App Catalog. This property value can be found in the manifest.json file or in the elements.xml file. - `clientSideComponentProperties`: An optional parameter, which can be used to provide properties for the extension instance. @@ -443,9 +464,9 @@ Associates a ListViewCommandSet to the list { "verb": "associateListViewCommandSet", "title": "HelloWorld", - "location": "CommandBar", + "location": "ClientSideExtension.ListViewCommandSet.CommandBar", "clientSideComponentId": "13234283-d6c2-408f-a9ef-31a920c8ae78", - "clientSideComponentProperties": "{\"sampleText\":\"added by a site design\"}" + "clientSideComponentProperties": "{\"sampleText\":\"added by a site template\"}" } ] } @@ -456,7 +477,7 @@ Associates a ListViewCommandSet to the list Renames the list. To create a new list with a specific name, instead of using setTitle use the `listName` parameter in the `CreateSPList` action. > [!NOTE] -> Using `setTitle` will rename the list, preventing the list from updating if the site design is reapplied. +> Using `setTitle` will rename the list, preventing the list from updating if the site template is reapplied. #### JSON value @@ -600,13 +621,13 @@ Use the `addNavLink` verb to add a new navigation link to the site QuickLaunch o #### JSON values -- `url`: The url of the link to add. +- `url`: The URL of the link to add. - `displayName`: The display name of the link. - `navComponent`: The component where to add the link, QuickLaunch, Hub, or Footer. The default is **QuickLaunch**. - `isWebRelative`: **True** if the link is web relative; otherwise, **False**. The default is **False**. - `parentDisplayName`: An optional parameter. If provided, it makes this navigation link a child (sub link) of the navigation link with this displayName. If both this and parentUrl are provided, it searches for a link that matches both to be the parent. -- `parentUrl`: An optional parameter. If provided, it makes this navigation link a child (sub link) of the navigation link with this url. If both this and parentDisplayName are provided, it searches for a link that matches both to be the parent. -- `isParentUrlWebRelative`: An optional parameter. **True** if the link is web relative; otherwise, **False**. The default is **False**. +- `parentUrl`: An optional parameter. If provided, it makes this navigation link a child (sub link) of the navigation link with this URL. If both this and parentDisplayName are provided, it searches for a link that matches both to be the parent. +- `isParentUrlWebRelative`: An optional parameter. **True** if the link is web relative; otherwise, **False**. The default value is **False**. #### Example @@ -629,13 +650,13 @@ Use the `addNavLink` verb to add a new navigation link to the site QuickLaunch o }, { "verb": "addNavLink", - "url": "https://docs.microsoft.com/sharepoint/dev/declarative-customization/site-design-overview", + "url": "https://learn.microsoft.com/sharepoint/dev/declarative-customization/site-design-overview", "displayName": "SharePoint Site Design Overview", "parentDisplayName": "Documents" }, { "verb": "addNavLink", - "url": "https://docs.microsoft.com/sharepoint/dev/declarative-customization/site-design-json-schema#add-a-navigation-link", + "url": "https://learn.microsoft.com/sharepoint/dev/declarative-customization/site-design-json-schema#add-a-navigation-link", "displayName": "About Site Footer", "navComponent":"Footer" }, @@ -653,7 +674,7 @@ Use the `removeNavLink` verb to remove a navigation link from the site. #### JSON values -- `url`: The url of the link to remove. +- `url`: The URL of the link to remove. - `displayName`: The display name of the link. - `navComponent`: The component where to remove the link from, QuickLaunch, Hub, or Footer. The default is **QuickLaunch**. - `isWebRelative`: **True** if the link is web relative; otherwise, **False**. @@ -661,7 +682,7 @@ Use the `removeNavLink` verb to remove a navigation link from the site. #### Example > [!NOTE] -> This action can be used to remove site links added by the collaboration and communication site templates (for example, "home", "documents", "pages", "conversations", etc.). +> This action can be used to remove site links added by the collaboration and communication site templates (for example, "home", "documents", "pages", and "conversations"). ```json { @@ -699,6 +720,9 @@ Get-Content '\site-script.json' -Raw -Encoding U Use the `applyTheme` verb to add a custom theme to the site. For more information about how to construct and upload these themes, see [SharePoint site theming](site-theming/sharepoint-site-theming-overview.md). This site action only works for applying custom themes; to apply one of our in-product SharePoint themes, create a copy as a custom one and reference that one. +> [!NOTE] +> This action is automatically blocked for [channel sites](/sharepoint/teams-connected-sites). + #### JSON value - `themeName`: The name of the theme to apply. @@ -756,6 +780,7 @@ Use the `setSiteBranding` verb to specify the navigation layout, the header layo > [!NOTE] > Setting the navigation layout only works on the communication site template and for the hub navigation. +> This action is automatically blocked for [channel sites](/sharepoint/teams-connected-sites). #### JSON value @@ -785,7 +810,7 @@ Use the `setSiteLogo` verb to specify a logo for your site. #### JSON value -- `url`: The url of the logo image to use. +- `url`: The URL of the logo image to use. #### Example @@ -798,6 +823,9 @@ Use the `setSiteLogo` verb to specify a logo for your site. ## Join a hub site +> [!NOTE] +> This action is automatically blocked for [channel sites](/sharepoint/teams-connected-sites). + Use the `joinHubSite` verb to join the site to a designated hub site. #### JSON value @@ -807,7 +835,8 @@ Use the `joinHubSite` verb to join the site to a designated hub site. #### Example -[!NOTE] To get the hubSiteId, sign in to a site by using the Connect-PnPOnline cmdlet, and then run: +> [!NOTE] +> To get the `hubSiteId`, sign in to a site by using the **Connect-PnPOnline** cmdlet, and then run: ```PowerShell $hubSiteName = "My Hub Site" @@ -849,10 +878,10 @@ Use the `associateExtension` action to register a deployed SharePoint Framework #### JSON values - `title`: The title of the extension in the App Catalog. -- `location`: Used to specify the extension type. If its used to create commands, then where the command would be displayed; otherwise this should be set to ClientSideExtension.ApplicationCustomizer. +- `location`: Used to specify the extension type. If it's used to create commands, then where the command would be displayed; otherwise this should be set to ClientSideExtension.ApplicationCustomizer. - `clientSideComponentId`: The identifier (GUID) of the extension in the App Catalog. This property value can be found in the manifest.json file or in the elements.xml file. - `clientSideComponentProperties`: An optional parameter, which can be used to provide properties for the extension instance. -- `registrationId`: An optional parameter, which indicates the type of the list the extension is associated to (if its a list extension). +- `registrationId`: An optional parameter, which indicates the type of the list the extension is associated to (if it's a list extension). - `registrationType`: An optional parameter, which should be specified if the extension is associated with a list. - `scope`: Indicates whether the extension is associated with a `Web` or a `Site`. @@ -895,6 +924,9 @@ To enable the web scoped feature that allows for Events Lists to be created (fea Use the `triggerFlow` verb to kick off a custom flow. +> [!TIP] +> The article [Calling Power Automate from a site script](/sharepoint/dev/declarative-customization/site-design-trigger-flow-tutorial) provides an end-to-end example. + #### JSON values - `url`: A trigger URL of the flow. @@ -917,6 +949,9 @@ Use the `triggerFlow` verb to kick off a custom flow. ## Configure regional settings +> [!NOTE] +> This action is automatically blocked for [channel sites](/sharepoint/teams-connected-sites). + Use the `setRegionalSettings` action to configure the regional settings of the site (*/_layouts/15/regionalsetng.aspx*). #### JSON values @@ -940,6 +975,9 @@ Use the `setRegionalSettings` action to configure the regional settings of the s ## Add users (principals) to SharePoint Groups +> [!NOTE] +> This action is automatically blocked for [channel sites](/sharepoint/teams-connected-sites). + Use the `addPrincipalToSPGroup` action to manage addition of users and groups to select default SharePoint groups. For more information, see [Understanding SharePoint Groups](https://support.office.com/article/Understanding-SharePoint-groups-94D9B261-161E-4ACE-829E-ECA1C8CD2EB8). This action can be used for licensed users, security groups, and Microsoft 365 groups. #### JSON values @@ -977,6 +1015,9 @@ Use the `addPrincipalToSPGroup` action to manage addition of users and groups to ## Manage guest access +> [!NOTE] +> This action is automatically blocked for [channel sites](/sharepoint/teams-connected-sites). + Use the `setSiteExternalSharingCapability` action to manage guest access. For more information, see [Manage external sharing for your SharePoint Online environment](https://support.office.com/article/Manage-external-sharing-for-your-SharePoint-Online-environment-C8A462EB-0723-4B0B-8D0A-70FEAFE4BE85). @@ -996,4 +1037,4 @@ Use the `setSiteExternalSharingCapability` action to manage guest access. For mo ## See also -- [SharePoint site design and site script overview](site-design-overview.md) +- [SharePoint site template and site script overview](site-design-overview.md) diff --git a/docs/declarative-customization/site-design-o365cli.md b/docs/declarative-customization/site-design-o365cli.md index 879770cbe..6282f7491 100644 --- a/docs/declarative-customization/site-design-o365cli.md +++ b/docs/declarative-customization/site-design-o365cli.md @@ -1,8 +1,8 @@ --- title: SharePoint site design - CLI for Microsoft 365 commands description: Use the CLI for Microsoft 365 to create, retrieve, and remove site designs and site scripts. -ms.date: 09/02/2020 -localization_priority: Priority +ms.date: 06/27/2024 +ms.localizationpriority: high --- # SharePoint site design: CLI for Microsoft 365 commands @@ -16,10 +16,8 @@ Use the CLI for Microsoft 365 to create, retrieve, update, and remove site desig To run the CLI for Microsoft 365 commands, you'll need to do the following: 1. Download and install [NodeJS LTS version](https://nodejs.org/en/) - -2. Follow the instructions at [Installing the CLI](https://pnp.github.io/cli-microsoft365/user-guide/installing-cli/) to install the CLI for Microsoft 365 on your machine - -3. Follow the instructions at [Logging in to Office 365](https://pnp.github.io/cli-microsoft365/user-guide/connecting-office-365/) to connect to your SharePoint tenant. +1. Follow the instructions at [Installing the CLI](https://pnp.github.io/cli-microsoft365/user-guide/installing-cli/) to install the CLI for Microsoft 365 on your machine +1. Follow the instructions at [Logging in to Office 365](https://pnp.github.io/cli-microsoft365/user-guide/connecting-microsoft-365) to connect to your SharePoint tenant. To verify your setup and connection, try using the [sitedesign list](https://pnp.github.io/cli-microsoft365/cmd/spo/sitedesign/sitedesign-list) command to read the current list of site designs. If the cmdlet runs and returns with no errors, you're ready to proceed. diff --git a/docs/declarative-customization/site-design-overview.md b/docs/declarative-customization/site-design-overview.md index 959a1c6b5..701efedc2 100644 --- a/docs/declarative-customization/site-design-overview.md +++ b/docs/declarative-customization/site-design-overview.md @@ -1,308 +1,222 @@ ---- -title: SharePoint site design and site script overview -description: Use SharePoint site scripts and site designs to provide custom configurations to apply when new sites are created. -ms.date: 06/14/2021 -localization_priority: Priority ---- - -# SharePoint site design and site script overview - -> [!NOTE] -> - Site designs and site scripts are currently only supported by SharePoint Online. -> - In previous versions of SharePoint, site templates were called site designs but will be referred to as site templates moving forward. -> - SharePoint has a new site template experience that will be available to all SharePoint user with permissions to create SharePoint sites. [Learn more about the new site template experience](https://support.microsoft.com/office/apply-and-customize-sharepoint-site-templates-39382463-0e45-4d1b-be27-0e96aeec8398?ui=en-US&rs=en-US&ad=US). -> - As of today, the site template experience cannot be disabled. -> - Site templates created by your organization and set as the default template will automatically apply when new sites are created but can be updated by the site owner by selecting **Settings** and then **Apply a site template.** -> - Site template version history is not currently available for the new site template experience but will be included in future iterations. - -Use site templates and site scripts to automate provisioning new or existing modern SharePoint sites that use your own custom configurations. - -When people in your organization create new SharePoint sites, you often need to ensure some level of consistency. For example, you may need proper branding and theming applied to each new site. You may also have detailed site provisioning scripts, such as using the PnP provisioning engine, that need to be applied each time a new site is created. - -This article describes how you can use site templates and site scripts to provide custom configurations to apply when new sites are created. - -## How site templates work - -Site templates can be used each time a new site is created to apply a consistent set of actions. They can also be applied to existing modern sites (group-connected Team and Communication sites). Most actions typically affect the site itself, such as setting the theme or creating lists. But a site template can also include other actions, such as recording the new site URL to a log, or sending a tweet. - -You create site templates and register them in SharePoint to one of the modern template sites: the Team site or the Communication site. You can see how this works in the following steps. - -1. Go to the SharePoint start page on your developer tenant. - -2. Choose **Create site**. - - You'll see the two modern template sites: **Team site** and **Communication site**. - -3. Choose **Communication site**. - -The Communication site has a **Choose a design** box, which comes with the following site templates: - -- Topic -- Showcase -- Blank - -These are the default site templates. For each site template, there is a title, description, and image. - -![Default site design title, description, and image on Communication site template](images/site-designs-listed-on-communication-site-template.png) - -Had you chosen the Team site template, it contains only one default site template named **Team site**. - -For more information about how you can change the default site templates, see [Customize a default site design](customize-default-site-design.md). - -When a site template is selected, SharePoint creates the new site, and runs site scripts for the site design. The site scripts detail the work such as creating new lists or applying a theme. These script actions are run in the background. A notification bar will be displayed, which the site creator can click to view the status of the actions being applied. - -![Notification bar showing application of script actions in progress](images/site-design-notification-bar-in-progress-state.png) - -When the scripts are complete the notification bar message will change - allowing the site creator to either refresh the page to see the results of the applied scripts or to view the site script details. - -![Notification bar showing application of script actions is complete](images/site-design-notification-bar-completed-state.png) - -The site template information panel can be invoked by a site owner at any time to see what site templates have been applied to the site (and their script details) as well as to apply new or updated site templates. - -When the actions in the scripts are completed, SharePoint displays detailed results of those actions in a progress pane. - -![Site Design Information Panel](images/site-design-information-panel-applied-site-designs.png) - -> [!NOTE] -> Site templates can now be applied to previously created modern site collections. For more information, see the [REST API](site-design-rest-api.md) and [PowerShell](site-design-powershell.md) articles. - -## Anatomy of a site script - -Site scripts are JSON files that specify an ordered list of actions to run when creating the new site. The actions are run in the order listed. - -The following example is a script that has two top-level actions. First, it applies a theme that was previously created named **Contoso Explorers**. It then creates a **Customer Tracking** list. - -```json -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json", - "actions": [ - { - "verb": "applyTheme", - "themeName": "Contoso Explorers" - }, - { - "verb": "createSPList", - "listName": "Customer Tracking", - "templateType": 100, - "subactions": [ - { - "verb": "setDescription", - "description": "List of Customers and Orders" - }, - { - "verb": "addSPField", - "fieldType": "Text", - "displayName": "Customer Name", - "isRequired": false, - "addToDefaultView": true - }, - { - "verb": "addSPField", - "fieldType": "Number", - "displayName": "Requisition Total", - "addToDefaultView": true, - "isRequired": true - }, - { - "verb": "addSPField", - "fieldType": "User", - "displayName": "Contact", - "addToDefaultView": true, - "isRequired": true - }, - { - "verb": "addSPField", - "fieldType": "Note", - "displayName": "Meeting Notes", - "isRequired": false - } - ] - } - ], - "version": 1 -} -``` - -
- -Each action in a site script is specified by a **verb** value in the JSON. In the previous script, the first action is specified by the **applyTheme** verb. Next, the **createSPList** verb creates the list. Notice that the **createSPList** verb contains its own set of verbs that run additional actions on only the list. - -Available actions include: - -- Creating a new list or library (or modifying the default one created with the site) -- Creating site columns, content types, and configuring other list settings -- Set site branding properties like navigation layout, header layout and header background -- Applying a theme -- Setting a site logo -- Adding links to quick launch or hub navigation -- Triggering a Power Automate flow -- Installing a deployed solution from the app catalog -- Setting regional settings for the site -- Adding principals (users and groups) to SharePoint roles -- Setting external sharing capability for the site - -For a complete list of available actions and their parameters, see the [JSON schema](site-design-json-schema.md). - -> [!NOTE] -> For libraries and lists, use the PowerShell command [Get-SPOSiteScriptFromList](/powershell/module/sharepoint-online/Get-SPOSiteScriptFromList) to create the site script syntax from an existing SharePoint list. - -Site scripts can be run again on the same site after provisioning. Site scripts are non-destructive, so when they run again, they ensure that the site matches the configuration in the script. - -For example, if the site already has a list with the same name that the site script is creating, the site script will only add missing fields to the existing list. - -We'd previously capped the limit of site script actions to 30. This remains the limit for scripts applied synchronously using the [Invoke-SPOSiteDesign](/powershell/module/sharepoint-online/Invoke-SPOSiteDesign) command, but based on customer feedback and support for additional actions we have bumped this limit to 300 actions (or 100,000 characters) when the scripts are applied asynchronously (either through the UI or using the [Add-SPOSiteDesignTask](/powershell/module/sharepoint-online/Add-SPOSiteDesignTask) command). - -There is also a limit of 100 site scripts and 100 site templates per tenant. - -## Using PowerShell or REST to work with site templates and site scripts - -You can create site templates and site scripts by using PowerShell or the REST API. The following example creates a site script and a site template that uses the site script. - - - -```powershell -C:\> Get-Content 'c:\scripts\site-script.json' ` - -Raw | ` - Add-SPOSiteScript ` - -Title "Contoso theme and list" - -Id : 2756067f-d818-4933-a514-2a2b2c50fb06 -Title : Contoso theme and list -Description : -Content : -Version : 0 - -C:\> Add-SPOSiteDesign ` - -Title "Contoso customer tracking" ` - -WebTemplate "64" ` - -SiteScripts "2756067f-d818-4933-a514-2a2b2c50fb06" ` - -Description "Creates customer list and applies standard theme" -``` - - - -
- -In the previous example, the **Add-SPOSiteScript** cmdlet or **CreateSiteScript** REST API returns a site script id. This is used for the **SiteScripts** parameter in the subsequent call to the **Add-SPOSiteDesign** cmdlet or **CreateSiteDesign** REST API. - -The **WebTemplate** parameter set to the value 64 indicates registering this site design with the Team site template. If you have disabled modern Group creation, then publish your site designs using WebTemplate 1 so that they display for the "Group-less" Team site template. The value 68 would indicate registering with the Communication site template. The **Title** and **Description** parameters are displayed when a user views site designs as they create a new Team site. - -> [!NOTE] -> A site template can run multiple scripts. The script IDs are passed in an array, and they run in the order listed. - -For step-by-step information about creating a site template, see [Get started creating site designs](get-started-create-site-design.md). - -## PnP provisioning and customization using Power Automate - -One action provided by site scripts is the ability to trigger a Power Automate flow. This allows you to specify any custom action that you need beyond the actions provided natively in site scripts. - -If you use the PnP provisioning engine to automate site creation, you can use a Power Automate flow to integrate with site templates. You can maintain all your existing provisioning scripts as well as create new custom provisioning scripts by using this technique. - -
- -![Process of triggering a Microsoft Flow](images/process-for-triggering-a-custom-flow.png) - -The process works as follows: - -1. The script instantiates your Power Automate flow using a URL with additional details. - -2. The flow sends a message to an Azure storage queue that you have configured. - -3. The message triggers a call to an Azure function that you have configured. - -4. The Azure function runs your custom script, such as the PnP provisioning engine, to apply your custom configurations. - -For a step-by-step tutorial about how to configure your own Power Automate flow with PnP provisioning, see [Build a complete site design using the PnP provisioning engine](site-design-pnp-provisioning.md). - -## Scoping - -You can configure site templates to only appear for specific groups or people in your organization. This is useful to ensure that people only see the site templates intended for them. For example, you might want the accounting department to only see site templates specifically for them. And the accounting site templates may not make sense to show to anyone else. - -By default, a site template can be viewed by everyone when it is created. Scopes are applied by using the **Grant-SPOSiteDesignRights** cmdlet or the **GrantSiteDesignRights** REST API. You can specify the scope by user or a mail-enabled security group. - -The following example shows how to add Nestor (a user at the fictional Contoso site) view rights on a site template. - -```powershell -Grant-SPOSiteDesignRights ` - -Identity 44252d09-62c4-4913-9eb0-a2a8b8d7f863 ` - -Principals "nestorw@contoso.onmicrosoft.com" ` - -Rights View -``` - - - -For more information about working with scopes, see [Scoping access to site designs](site-design-scoping.md). - -## See also - -- [Get started creating site template](get-started-create-site-design.md) -- [Apply a scope to your site design](site-design-scoping.md) -- [Site design JSON schema](site-design-json-schema.md) -- [PowerShell cmdlets for SharePoint site designs and site scripts](site-design-powershell.md) -- [Site design and site script REST API](site-design-rest-api.md) -- [Site design examples](https://github.com/SharePoint/sp-dev-site-scripts) +--- +title: SharePoint site template and site script overview +description: Use SharePoint site scripts and site templates to provide custom configurations to apply when new sites are created. +ms.date: 01/22/2025 +ms.localizationpriority: high +--- + +# SharePoint site template and site script overview + +> [!NOTE] +> - Site templates and site scripts are currently only supported by SharePoint Online. +> - In previous versions of SharePoint, site templates were called site designs but will be referred to as site templates moving forward. +> - SharePoint has a new site template experience that will be available to all SharePoint users with permission to create SharePoint sites. [Learn more about the new site template experience](https://support.microsoft.com/office/apply-and-customize-sharepoint-site-templates-39382463-0e45-4d1b-be27-0e96aeec8398?ui=en-US&rs=en-US&ad=US). +> - As of today, the site template experience cannot be disabled. +> - Site templates created by your organization and set as the default template will automatically apply when new sites are created but can be updated by the site owner by selecting **Settings** and then **Apply a site template.** +> - Site template version history is not currently available for the new site template experience but will be included in future iterations. + +Use site templates and site scripts to automate the provisioning of new or existing modern SharePoint sites that use your own custom configurations. + +When people in your organization create new SharePoint sites, you often need to ensure some level of consistency. For example, you may need proper branding and theming applied to each new site. You may also have detailed site provisioning scripts, such as using the PnP provisioning engine, that need to be applied each time a new site is created. + +This article describes how you can use site templates and site scripts to provide custom configurations to apply when new sites are created. + +## How site templates work + +Site templates can be used each time a new site is created to apply a consistent set of actions. They can also be applied to existing modern sites (group-connected Team and Communication sites). Most actions typically affect the site itself, such as setting the theme or creating lists. But a site template can also include other actions, such as recording the new site URL to a log or sending a tweet. + +> [!NOTE] +> - Site templates created using custom site scripts will display in the **From your organization** tab in the site template gallery. +> - Custom site templates made by your organization will be displayed in the site template gallery based on the type of site chosen by the user - either a communication site or a team site. Therefore, it is likely users will not see all site templates from your organization in the site template gallery. Soon, users will have the ability to browse all site templates provided by your organization regardless of which type of site was chosen. + +You create site templates and register them in SharePoint to one of the modern template sites: the Team site or the Communication site. You can see how this works in the following steps. + +1. Go to the SharePoint start page on your developer tenant. +1. Choose **Create site**. + + You'll see the two modern template sites: **Team site** and **Communication site**. + +1. Choose the type of site needed. + + - SharePoint will automatically create a communication site using the **Standard communication** site template. + - Had you chosen the default Team site, SharePoint will create a new site using the **Standard team** template. + + For more information about how you can change the default site templates, see [Customize a default site template](customize-default-site-design.md). + +1. Navigate to the **Settings** icon, and select **Apply site template** to review Microsoft-provided site templates based on the type of site you chose in step three. + +When a site template is selected, SharePoint creates the new site and runs site scripts for the site template. The site scripts provide the details for the template such as creating new lists or applying a theme. These script actions are run in the background. When the scripts are complete the page will refresh to display the site script details. + +> [!NOTE] +> Site templates can now be applied to previously created modern site collections. For more information, see the [REST API](site-design-rest-api.md) and [PowerShell](site-design-powershell.md) articles. + +## Anatomy of a site script + +Site scripts are JSON files that specify an ordered list of actions to run when creating the new site. The actions are run in the order listed. + +The following example is a script that has two top-level actions. First, it applies a theme that was previously created named **Contoso Explorers**. It then creates a **Customer Tracking** list. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json", + "actions": [ + { + "verb": "applyTheme", + "themeName": "Contoso Explorers" + }, + { + "verb": "createSPList", + "listName": "Customer Tracking", + "templateType": 100, + "subactions": [ + { + "verb": "setDescription", + "description": "List of Customers and Orders" + }, + { + "verb": "addSPField", + "fieldType": "Text", + "displayName": "Customer Name", + "isRequired": false, + "addToDefaultView": true + }, + { + "verb": "addSPField", + "fieldType": "Number", + "displayName": "Requisition Total", + "addToDefaultView": true, + "isRequired": true + }, + { + "verb": "addSPField", + "fieldType": "User", + "displayName": "Contact", + "addToDefaultView": true, + "isRequired": true + }, + { + "verb": "addSPField", + "fieldType": "Note", + "displayName": "Meeting Notes", + "isRequired": false + } + ] + } + ] +} +``` + +Each action in a site script is specified by a **verb** value in the JSON. In the previous script, the first action is specified by the **applyTheme** verb. Next, the **createSPList** verb creates the list. Notice that the **createSPList** verb contains its own set of verbs that run additional actions on only the list. + +**Available actions include:** + +- Creating a new list or library (or modifying the default one created with the site) +- Creating site columns, content types, and configuring other list settings +- Set site branding properties like navigation layout, header layout, and header background +- Applying a theme** +- Setting a site logo +- Adding links to quick launch or hub navigation** +- Triggering a Power Automate flow +- Installing a deployed solution from the app catalog +- Setting regional settings for the site** +- Adding principals (users and groups) to SharePoint roles** +- Setting external sharing capability for the site** + +For a complete list of available actions and their parameters, see the [JSON schema](site-design-json-schema.md). + +> [!NOTE] +> +> - Actions marked with ** are automatically blocked for [channel sites](/sharepoint/teams-connected-sites). +> - For libraries and lists, use the PowerShell command [Get-SPOSiteScriptFromList](/powershell/module/sharepoint-online/Get-SPOSiteScriptFromList) to create the site script syntax from an existing SharePoint list. + +Site scripts can be run again on the same site after provisioning. They are non-destructive, so when they are run again, they ensure that the site matches the configuration in the script. + +For example, if the site already has a list with the same name that the site script is creating, the site script will only add missing fields to the existing list. + +We'd previously capped the limit of site script actions to 30. This remains the limit for scripts applied synchronously using the [Invoke-SPOSiteDesign](/powershell/module/sharepoint-online/Invoke-SPOSiteDesign) command, but based on customer feedback and support for additional actions we have bumped this limit to 300 actions (or 100,000 characters) when the scripts are applied asynchronously (either through the UI or using the [Add-SPOSiteDesignTask](/powershell/module/sharepoint-online/Add-SPOSiteDesignTask) command). + +There is also a limit of 100 site scripts and 100 site templates per tenant. + +## Using PowerShell or REST to work with site templates and site scripts + +You can create site templates and scripts using PowerShell or the REST API. The following example creates a site script and a site template that uses the script. + + + +```powershell +C:\> Get-Content 'c:\scripts\site-script.json' ` + -Raw | ` + Add-SPOSiteScript ` + -Title "Contoso theme and list" + +Id : 2756067f-d818-4933-a514-2a2b2c50fb06 +Title : Contoso theme and list +Description : +Content : +Version : 0 + +C:\> Add-SPOSiteDesign ` + -Title "Contoso customer tracking" ` + -WebTemplate "64" ` + -SiteScripts "2756067f-d818-4933-a514-2a2b2c50fb06" ` + -Description "Creates customer list and applies standard theme" +``` + +In the previous example, the **Add-SPOSiteScript** cmdlet or **CreateSiteScript** REST API returns a site script ID. This is used for the **SiteScripts** parameter in the subsequent call to the **Add-SPOSiteDesign** cmdlet or **CreateSiteDesign** REST API. + +| Parameter | Value | Site template type | +| :------------------- | :------------------- |:----------------| +| WebTemplate | 64 | Team site template | +| WebTemplate | 1 | Team site (with group creation disabled) | +| WebTemplate | 68 | Communication site template | +| WebTemplate | 69 | Channel site template | + +For step-by-step information about creating a site template, see [Get started creating site templates.](get-started-create-site-design.md) + +> [!NOTE] +> +> - A site template can run multiple scripts. The script IDs are passed in an array, and they run in the order listed. +> - The former term for site templates may still appear in certain cmdlet and script labels as "site design." + +## PnP provisioning and customization using Power Automate + +One action provided by site scripts is the ability to trigger a Power Automate flow. This allows you to specify any custom action that you need beyond the actions provided natively in site scripts. + +If you use the PnP provisioning engine to automate site creation, you can use a Power Automate flow to integrate with site templates. You can maintain all your existing provisioning scripts as well as create new custom provisioning scripts by using this technique. + +![Process of triggering a Microsoft Flow](images/process-for-triggering-a-custom-flow.png) + +The process works as follows: + +1. The script instantiates your Power Automate flow using a URL with additional details. +1. The flow sends a message to an Azure storage queue that you have configured. +1. The message triggers a call to an Azure function that you have configured. +1. The Azure function runs your custom script, such as the PnP provisioning engine, to apply your custom configurations. + +For a step-by-step tutorial about how to configure your own Power Automate flow with PnP provisioning, see [Build a complete site template using the PnP provisioning engine](site-design-pnp-provisioning.md). + +## Scoping + +You can configure site templates to only appear for specific groups or people in your organization. This is useful to ensure that people only see the site templates intended for them. For example, you might want the accounting department to only see site templates specifically for them. And the accounting site templates may not make sense to show to anyone else. + +By default, a site template can be viewed by everyone when it is created. Scopes are applied by using the **Grant-SPOSiteDesignRights** cmdlet or the **GrantSiteDesignRights** REST API. You can specify the scope by user or a mail-enabled security group. + +The following example shows how to add Nestor (a user at the fictional Contoso site) view rights on a site template. + +```powershell +Grant-SPOSiteDesignRights ` + -Identity 44252d09-62c4-4913-9eb0-a2a8b8d7f863 ` + -Principals "nestorw@onmicrosoft.com" ` + -Rights View +``` + +For more information about working with scopes, see [Scoping access to site templates](site-design-scoping.md). + +## See also + +- [Get started creating site template](get-started-create-site-design.md) +- [Apply a scope to your site template](site-design-scoping.md) +- [Site template JSON schema](site-design-json-schema.md) +- [PowerShell cmdlets for SharePoint site templates and site scripts](site-design-powershell.md) +- [Site template and site script REST API](site-design-rest-api.md) +- [Site template examples](https://github.com/SharePoint/sp-dev-site-scripts) diff --git a/docs/declarative-customization/site-design-pnp-provisioning.md b/docs/declarative-customization/site-design-pnp-provisioning.md index 7bcdc34f4..74a7db6ef 100644 --- a/docs/declarative-customization/site-design-pnp-provisioning.md +++ b/docs/declarative-customization/site-design-pnp-provisioning.md @@ -1,8 +1,8 @@ --- title: Calling the PnP provisioning engine from a site script description: Build a complete SharePoint site design using the PnP provisioning engine -ms.date: 03/23/2021 -localization_priority: Priority +ms.date: 08/31/2023 +ms.localizationpriority: high --- # Calling the PnP provisioning engine from a site script @@ -10,7 +10,7 @@ localization_priority: Priority > [!NOTE] > This article uses the newest version of PnP PowerShell that is released in January 2021. As Azure Functions run PowerShell Core, you'll have to use this version of PnP PowerShell in your Azure Function. For more information about this version of PnP PowerShell see https://pnp.github.io/powershell. -Site designs offer a great way to standardize the look and feel of your site collections. However, you can't do some things with site designs, like add a footer to every page. You can use the PnP provisioning engine to create a template that you can use to provision an Application Customizer to a site. This Application Customizer can then update your page design, for example to register a footer on every page. +Site designs offer a great way to standardize the look and feel of your site collections. However, you can't do some things with site designs, like add a footer to every page. You can use the PnP provisioning engine to create a template that you can use to provision an Application Customizer to a site. This Application Customizer can then update your page design, for example, to register a footer on every page. This article describes how to create a site design that applies a PnP provisioning template to a site. The template will add an Application Customizer to render a footer. @@ -31,7 +31,7 @@ You'll use these components to trigger the PnP provisioning code after you creat ## Set up app-only access to your tenant -We are going to use authentication with a clientid and a certificate in this tutorial. +We are going to use authentication with a client id and a certificate in this tutorial. 1. Create a new self-signed certificate with PnP PowerShell on your computer: @@ -64,11 +64,14 @@ To set up the Azure Queue storage: ## Create the flow +> [!NOTE] +> The **Request** trigger used below is now **Premium** and will therefore require additional licensing. + To put a message in the queue, you need to create a flow. 1. Go to the [Power Automate](https://flow.microsoft.com) site, sign in, and choose **Create from Blank** at the top of the page. 1. Choose **Search hundreds of connectors and triggers** to select your trigger. -1. Search for **Request**, and select **Request - When a HTTP Request is received**. +1. Search for **Request**, and select **Request - When an HTTP Request is received [Premium]**. 1. Enter the following JSON as your request body: ```json @@ -176,7 +179,7 @@ Copy the following provisioning template XML to a new file and save the file as } ``` - Save the file. Notice, that if you do no intent to use the Azure PowerShell Cmdlets you can remove that entry from this file. The requirements.psd1 file makes sure that specific PowerShell modules will be available to all functions. At the first execution of the Azure Function these modules will be downloaded and made available. You can also use wildcard references for the version. See for more information about this file here: https://docs.microsoft.com/azure/azure-functions/functions-reference-powershell?tabs=portal#dependency-management + Save the file. Notice, that if you do no intent to use the Azure PowerShell Cmdlets you can remove that entry from this file. The requirements.psd1 file makes sure that specific PowerShell modules will be available to all functions. At the first execution of the Azure Function these modules will be downloaded and made available. You can also use wildcard references for the version. [See for more information about this file](/azure/azure-functions/functions-reference-powershell?tabs=portal#dependency-management). 1. Create a new Azure Function **Functions** > **Add**: @@ -216,7 +219,7 @@ Copy the following provisioning template XML to a new file and save the file as ``` Replace **[insertyourAppIdHere]** with the value that the `Register-PnPAzureApp` cmdlet returned for AzureAppId. - + Replace **'contoso.onmicrosoft.com'** with your tenant details. ## Create the site design diff --git a/docs/declarative-customization/site-design-pnppowershell.md b/docs/declarative-customization/site-design-pnppowershell.md index 25d9b64d1..8faccf981 100644 --- a/docs/declarative-customization/site-design-pnppowershell.md +++ b/docs/declarative-customization/site-design-pnppowershell.md @@ -1,8 +1,8 @@ --- title: SharePoint site design - PnP PowerShell cmdlets description: Use PnP PowerShell cmdlets to create, retrieve, and remove site designs and site scripts. -ms.date: 03/09/2021 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint site design: PnP PowerShell cmdlets @@ -17,15 +17,15 @@ To run the PnP PowerShell cmdlets, you'll need to do the following: 1. Download and install the PnP PowerShell Module by running: -```PowerShell -Install-Module PnP.PowerShell -``` + ```PowerShell + Install-Module PnP.PowerShell + ``` -2. Connect to the SharePoint Online Admin Center of your tenant: +1. Connect to the SharePoint Online Admin Center of your tenant: -```PowerShell -Connect-PnPOnline -Url https://tenant-admin.sharepoint.com -Interactive -``` + ```PowerShell + Connect-PnPOnline -Url https://tenant-admin.sharepoint.com -Interactive + ``` To verify your setup and connection, try using the `Get-PnPSiteScript` cmdlet to read the current list of site scripts. If the cmdlet runs and returns with no errors, you're ready to proceed. @@ -33,27 +33,27 @@ To verify your setup and connection, try using the `Get-PnPSiteScript` cmdlet to The following cmdlets are available for managing site designs and site scripts from PnP PowerShell: -- [Add-PnPSiteDesign](/powershell/module/sharepoint-pnp/Add-PnPSiteDesign) -- [Add-PnPSiteDesignTask](/powershell/module/sharepoint-pnp/Add-PnPSiteDesignTask) -- [Add-PnPSiteScript](/powershell/module/sharepoint-pnp/Add-PnPSiteScript) -- [Add-PnPSiteScriptPackage](/powershell/module/sharepoint-pnp/Add-PnPSiteScriptPackage) -- [Get-PnPSiteDesign](/powershell/module/sharepoint-pnp/Get-PnPSiteDesign) -- [Get-PnPSiteDesignRights](/powershell/module/sharepoint-pnp/Get-PnPSiteDesignRights) -- [Get-PnPSiteDesignRun](/powershell/module/sharepoint-pnp/Get-PnPSiteDesignRun) -- [Get-PnPSiteDesignRunStatus](/powershell/module/sharepoint-pnp/Get-PnPSiteDesignRunStatus) -- [Get-PnPSiteDesignTask](/powershell/module/sharepoint-pnp/Get-PnPSiteDesignTask) -- [Get-PnPSiteScript](/powershell/module/sharepoint-pnp/Get-PnPSiteScript) -- [Get-PnPSiteScriptFromList](/powershell/module/sharepoint-pnp/Get-PnPSiteScriptFromList) -- [Get-PnPSiteScriptFromWeb](/powershell/module/sharepoint-pnp/Get-PnPSiteScriptFromWeb) -- [Grant-PnPSiteDesignRights](/powershell/module/sharepoint-pnp/Grant-PnPSiteDesignRights) -- [Invoke-PnPSiteDesign](/powershell/module/sharepoint-pnp/Invoke-PnPSiteDesign) -- [Remove-PnPSiteDesign](/powershell/module/sharepoint-pnp/Remove-PnPSiteDesign) -- [Remove-PnPSiteDesignTask](/powershell/module/sharepoint-pnp/Remove-PnPSiteDesignTask) -- [Remove-PnPSiteScript](/powershell/module/sharepoint-pnp/Remove-PnPSiteScript) -- [Revoke-PnPSiteDesignRights](/powershell/module/sharepoint-pnp/Revoke-PnPSiteDesignRights) -- [Set-PnPSiteDesign](/powershell/module/sharepoint-pnp/Set-PnPSiteDesign) -- [Set-PnPSiteScript](/powershell/module/sharepoint-pnp/Set-PnPSiteScript) -- [Set-PnPSiteScriptPackage](/powershell/module/sharepoint-pnp/Set-PnPSiteScriptPackage) +- [Add-PnPSiteDesign](https://pnp.github.io/powershell/cmdlets/Add-PnPSiteDesign.html) +- [Add-PnPSiteDesignTask](https://pnp.github.io/powershell/cmdlets/Add-PnPSiteDesignTask.html) +- [Add-PnPSiteScript](https://pnp.github.io/powershell/cmdlets/Add-PnPSiteScript.html) +- [Add-PnPSiteScriptPackage](https://pnp.github.io/powershell/cmdlets/Add-PnPSiteScriptPackage.html) +- [Get-PnPSiteDesign](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteDesign.html) +- [Get-PnPSiteDesignRights](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteDesignRights.html) +- [Get-PnPSiteDesignRun](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteDesignRun.html) +- [Get-PnPSiteDesignRunStatus](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteDesignRunStatus.html) +- [Get-PnPSiteDesignTask](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteDesignTask.html) +- [Get-PnPSiteScript](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteScript.html) +- [Get-PnPSiteScriptFromList](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteScriptFromList.html) +- [Get-PnPSiteScriptFromWeb](https://pnp.github.io/powershell/cmdlets/Get-PnPSiteScriptFromWeb.html) +- [Grant-PnPSiteDesignRights](https://pnp.github.io/powershell/cmdlets/Grant-PnPSiteDesignRights.html) +- [Invoke-PnPSiteDesign](https://pnp.github.io/powershell/cmdlets/Invoke-PnPSiteDesign.html) +- [Remove-PnPSiteDesign](https://pnp.github.io/powershell/cmdlets/Remove-PnPSiteDesign.html) +- [Remove-PnPSiteDesignTask](https://pnp.github.io/powershell/cmdlets/Remove-PnPSiteDesignTask.html) +- [Remove-PnPSiteScript](https://pnp.github.io/powershell/cmdlets/Remove-PnPSiteScript.html) +- [Revoke-PnPSiteDesignRights](https://pnp.github.io/powershell/cmdlets/Revoke-PnPSiteDesignRights.html) +- [Set-PnPSiteDesign](https://pnp.github.io/powershell/cmdlets/Set-PnPSiteDesign.html) +- [Set-PnPSiteScript](https://pnp.github.io/powershell/cmdlets/Set-PnPSiteScript.html) +- [Set-PnPSiteScriptPackage](https://pnp.github.io/powershell/cmdlets/Set-PnPSiteScriptPackage.html) ## See also diff --git a/docs/declarative-customization/site-design-powershell.md b/docs/declarative-customization/site-design-powershell.md index 1a82121ae..085f6ac92 100644 --- a/docs/declarative-customization/site-design-powershell.md +++ b/docs/declarative-customization/site-design-powershell.md @@ -1,8 +1,8 @@ --- title: SharePoint site design - PowerShell cmdlets description: Use PowerShell cmdlets to create, retrieve, and remove site designs and site scripts. -ms.date: 09/28/2020 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint site design: PowerShell cmdlets @@ -14,8 +14,7 @@ Use PowerShell cmdlets to create, retrieve, update, and remove site designs and To run the PowerShell cmdlets, you'll need to do the following: 1. Download and install the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588). If you already have a previous version of the shell installed, uninstall it first and then install the latest version. - -2. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. +1. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. To verify your setup, try using the [Get-SPOSiteScript](/powershell/module/sharepoint-online/Get-SPOSiteScript) cmdlet to read the current list of site scripts. If the cmdlet runs and returns with no errors, you're ready to proceed. diff --git a/docs/declarative-customization/site-design-rest-api.md b/docs/declarative-customization/site-design-rest-api.md index 9aee0368d..e017ef341 100644 --- a/docs/declarative-customization/site-design-rest-api.md +++ b/docs/declarative-customization/site-design-rest-api.md @@ -1,8 +1,8 @@ --- title: SharePoint site design REST API description: Work with SharePoint site designs through the SharePoint REST interface to perform basic create, read, update, and delete (CRUD) operations. -ms.date: 04/07/2021 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Site design and site script REST API @@ -15,7 +15,7 @@ The SharePoint Online (and SharePoint 2016 and later on-premises) REST service s Before you get started, make sure that you're familiar with the following: -- [Get to know the SharePoint REST service](../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) +- [Get to know the SharePoint REST service](../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) - [Complete basic operations using SharePoint REST endpoints](../sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints.md) ## REST commands @@ -81,7 +81,7 @@ Creates a new site script. The following example creates a new site script that applies a custom theme. ```javascript -var site_script = +var site_script = { "$schema": "schema.json", "actions": [ @@ -178,11 +178,11 @@ Gets the site script syntax for a specific SharePoint site. Here is an example of retrieving a site script JSON object from the Contoso site collection. ```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteScriptFromWeb", { +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteScriptFromWeb", { "webUrl":"https://contoso.sharepoint.com/", - "info":{ + "info":{ "IncludeBranding":true, - "IncludedLists":[ + "IncludedLists":[ "Lists/Contoso customer list" ], "IncludeRegionalSettings":true, @@ -367,7 +367,7 @@ Updates a site script with new values. In the REST call, all parameters are opti Here's an example of updating an existing site script with a new JSON script and values. ```javascript -var updated_site_script = +var updated_site_script = { "$schema": "schema.json", "actions": [ @@ -380,12 +380,12 @@ var updated_site_script = "version": 2 }; -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.UpdateSiteScript", +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.UpdateSiteScript", {updateInfo:{ Id:"07702c07-0485-426f-b710-4704241caad9", - Title:"New Contoso theme", - Description:"Updated Contoso site script", - Version: 2, + Title:"New Contoso theme", + Description:"Updated Contoso site script", + Version: 2, Content: JSON.stringify(updated_site_script)}}); ``` @@ -419,7 +419,7 @@ Deletes a site script. Here's an example of deleting a site script. ```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteScript", +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteScript", {id:"07702c07-0485-426f-b710-4704241caad9"}); ``` @@ -491,7 +491,7 @@ Applies a site design to an existing site collection. Here's an example of applying a site design to the ProjectGo site collection. ```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.ApplySiteDesign", {siteDesignId: "614f9b28-3e85-4ec9-a961-5971ea086cca", "webUrl":"https://contoso.sharepoint.com/sites/projectgo"}); +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.ApplySiteDesign", {"siteDesignId": "614f9b28-3e85-4ec9-a961-5971ea086cca", "webUrl":"https://contoso.sharepoint.com/sites/projectgo"}); ``` ## AddSiteDesignTaskToCurrentWeb @@ -579,7 +579,7 @@ Gets information about a specific site design. Here's an example of getting information about a specific site design by ID. ```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteDesignMetadata", +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteDesignMetadata", {id:"614f9b28-3e85-4ec9-a961-5971ea086cca"}); ``` @@ -605,10 +605,10 @@ Here is an example of the JSON returned after calling **GetSiteDesignMetadata**. ## UpdateSiteDesign -Updates a site design with new values. In the REST call, all parameters are optional except the site script Id. +Updates a site design with new values. In the REST call, all parameters are optional except the site script Id. -> [!NOTE] -> If you had previously set the IsDefault parameter to **TRUE** and wish it to remain true, you must pass in this parameter again (otherwise it will be reset to **FALSE**). +> [!NOTE] +> If you had previously set the IsDefault parameter to **TRUE** and wish it to remain true, you must pass in this parameter again (otherwise it will be reset to **FALSE**). ### Parameters @@ -630,14 +630,14 @@ Here's an example that updates every value on an existing site design. ```javascript RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.UpdateSiteDesign", {updateInfo:{ - Id:"614f9b28-3e85-4ec9-a961-5971ea086cca", - Title:"Contoso customer site", - Description:"Creates site with customer theme and list", - SiteScriptIds:["6b2b79e4-5da3-4352-8565-42a896fabd57","2b997981-258b-4e1e-81ff-f6fbf7235a1f"], + Id:"614f9b28-3e85-4ec9-a961-5971ea086cca", + Title:"Contoso customer site", + Description:"Creates site with customer theme and list", + SiteScriptIds:["6b2b79e4-5da3-4352-8565-42a896fabd57","2b997981-258b-4e1e-81ff-f6fbf7235a1f"], PreviewImageUrl:"https://contoso.sharepoint.com/SiteAssets/customer_site.png", - PreviewImageAltText:"Customer site with list and theme", - WebTemplate:"68", - Version: 7, + PreviewImageAltText:"Customer site with list and theme", + WebTemplate:"68", + Version: 7, IsDefault: false}}); ``` @@ -675,7 +675,7 @@ Deletes a site design. Here's an example of deleting a site design. ```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteDesign", +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteDesign", {id:"f9e76746-5076-4bd2-bad3-e611c488fa85"}); ``` @@ -695,7 +695,7 @@ Gets a list of principals that have access to a site design. Here's an example of getting view rights for a specific site design. ```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteDesignRights", +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteDesignRights", {id:"dc076f7b-6c15-4d76-8f85-948a17f5dd18"}); ``` @@ -767,7 +767,7 @@ Revokes access from a site design for one or more principals. Here's an example of revoking view rights from a site design for Patti (fictional user at Contoso). ```javascript -RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.RevokeSiteDesignRights", +RestRequest("/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.RevokeSiteDesignRights", {id:"5d4756e9-e1f5-42f7-afa7-5fa5aac170aa", principalNames:["PattiF@contoso.onmicrosoft.com"] }); ``` diff --git a/docs/declarative-customization/site-design-scoping.md b/docs/declarative-customization/site-design-scoping.md index 54ae7de9d..3d697e7d1 100644 --- a/docs/declarative-customization/site-design-scoping.md +++ b/docs/declarative-customization/site-design-scoping.md @@ -1,26 +1,29 @@ --- -title: Scoping access to SharePoint site designs -description: Set scope on SharePoint site designs to control who can view and access them. -ms.date: 04/20/2018 -localization_priority: Priority +title: Select audiences for SharePoint site templates +description: Determine which audiences can access certain site templates. +ms.date: 06/28/2022 +ms.localizationpriority: high --- -# Scoping access to site designs +# Scoping access to site templates -Site designs are available to everyone by default. You can also scope site designs so that they are only available to specific users or groups. For example, the accounting department may have specific site designs they use, but it may not make sense to share those site designs with everyone. +Site templates are available to everyone by default. You can also scope site templates so that they are only available to specific users or groups. For example, the accounting department may have specific site designs they use, but it may not make sense to share those site templates with everyone. -This article explains how you can control which users and groups can see specific site designs. +This article explains how you can control which users and groups can see specific site templates. -## Grant rights to a site design +> [!NOTE] +> Users with the SharePoint Admin role assigned will see all site templates, regardless of scoping. + +## Grant rights to a site template -When a site design is first created, it is available to everyone. You can grant **View** rights to the site design. After rights are granted, only the users or groups (principals) specified have access. You can continue granting rights to more principals with subsequent API calls. +When a site template is first created, it is available to everyone. You can grant **View** rights to the site template. After rights are granted, only the users or groups (principals) specified have access. You can continue granting rights to more principals with subsequent API calls. > [!NOTE] > Scoping is currently only available for mail-enabled security groups and users. We are planning to provide support for Microsoft 365 groups in the future. ## Grant rights to security groups -The following example shows how to scope an existing site design so that only the mail-enabled security group **accounting** can view and use the site design. +The following example shows how to scope an existing site template so that only the mail-enabled security group **accounting** can view and use the site template. ```powershell Grant-SPOSiteDesignRights ` @@ -31,7 +34,7 @@ Grant-SPOSiteDesignRights `
-You might want to create a new site design and grant rights at the same time, as shown in the next example. +You might want to create a new site template and grant rights at the same time, as shown in the next example. ```powershell Add-SPOSiteDesign ` @@ -47,7 +50,7 @@ Add-SPOSiteDesign ` ## Grant rights to users -The following example shows how to grant view rights on a site design to Nestor (a user at the fictional Contoso site). +The following example shows how to grant view rights on a site template to Nestor (a user at the fictional Contoso site). ```powershell PS C:\> Grant-SPOSiteDesignRights ` @@ -56,7 +59,7 @@ PS C:\> Grant-SPOSiteDesignRights ` -Rights View ``` -## View rights assigned to a site design +## View rights assigned to a site template To view rights, use the **Get-SPOSiteDesignRights** cmdlet. The following example shows how to use this cmdlet and a response in the case where only Nestor has view rights. @@ -70,16 +73,16 @@ DisplayName PrincipalName Rights Nestor Wilke i:0#.f|membership|nestorw@contoso.onmicrosoft.com View ``` -## Revoke rights from a site design +## Revoke rights from a site template -You can revoke rights for any principal. If you revoke view rights for all principles, the site design will again be available to everyone. +You can revoke rights for any principal. If you revoke view rights for all principles, the site template will again be available to everyone. The following example revokes access for the accounting mail-enabled security group and Nestor. ```powershell Revoke-SPOSiteDesignRights ` -Identity db752673-18fd-44db-865a-aa3e0b28698e ` - -Principals ("accounting@contoso.sharepoint.com","nestorw@spdfcontosodemo2.onmicrosoft.com") ` + -Principals ("accounting@contoso.sharepoint.com","nestorw@contoso.onmicrosoft.com") ` ``` ## See also diff --git a/docs/declarative-customization/site-design-trigger-flow-tutorial.md b/docs/declarative-customization/site-design-trigger-flow-tutorial.md index a46038a61..285da5ad0 100644 --- a/docs/declarative-customization/site-design-trigger-flow-tutorial.md +++ b/docs/declarative-customization/site-design-trigger-flow-tutorial.md @@ -1,133 +1,119 @@ --- title: Using site designs and Power Automate to track site creation requests description: Invoke a Power Automate flow using the site script triggerFlow action to capture the site creation event and build a site directory. This tutorial is intended to illustrate a simple example of using site designs and Power Automate. -ms.date: 06/05/2020 -localization_priority: Priority +ms.date: 06/05/2024 +ms.localizationpriority: high --- # Calling Power Automate from a site script Site designs are a powerful extensibility mechanism for customizing - and standardizing - the look and feel of your site collections. One of the script actions - **triggerFlow** - can be used to call custom solutions to apply configurations we don't support natively. Power Automate flows can also be used for business automation - in this case, used with site designs to track the creation of sites! -This article describes how to build a simple site directory using a site design and Power Automate. Whenever a site is created using this site design, details of the site are captured and written to a SharePoint list. +This article describes how to build a simple site directory using a site design and Power Automate. Whenever a site is created using this site design, details of the site are captured and written to a SharePoint list. The steps in this article illustrate the following components: -- A SharePoint list +- A SharePoint list - A site design and a site script - Power Automate -You'll first create the SharePoint list and then it will be referenced in your Power Automate flow - which will be triggered by the site design applied after the site is created. +You'll first create the SharePoint list and then it will be referenced in your Power Automate flow - which will be triggered by the site design applied after the site is created. ## Create your site directory list -You need to first set up the list that will be used to record all the sites created using this site design. +You need to first set up the list that will be used to record all the sites created using this site design. -1. Select a site collection to host your list. +1. Select a site collection to host your list. +1. Create a new list named "Site Directory" +1. Configure the following fields: -2. Create a new list named "Site Directory" - -3. Configure the following fields: - webUrl (Hyperlink or Picture) - webDescription (Single line of text) - creatorName (Single line of text) - creatorEmail (Single line of text) - createdTimeUTC (Single line of text) - ## Create the flow -In order to capture the site creation event and create the corresponding list item, you need to create a flow - which can then be referenced in your site design's site script: +In order to capture the site creation event and create the corresponding list item, you need to create a flow - which can then be referenced in your site design's site script: 1. Go to the [Power Automate](https://flow.microsoft.com) site, sign in, and choose **+ Automated—from blank* at the top of the page. +1. Click **Skip** on the next screen +1. Choose **Search connectors and triggers** to select your trigger +1. Search for **Request**, and then choose **Request - When a HTTP Request is received [PREMIUM]**. **NOTE**: The **Request** trigger is now **PREMIUM** and will therefore require additional licensing. +1. Enter the following JSON as your request body: -2. Click **Skip** on the next screen - -2. Choose **Search connectors and triggers** to select your trigger - -3. Search for **Request**, and then choose **Request - When a HTTP Request is received [PREMIUM]**. **NOTE**: The **Request** trigger is now **PREMIUM** and will therefore require additional licensing. - -4. Enter the following JSON as your request body: - - ```json - { - "type": "object", - "properties": { - "webUrl": { - "type": "string" - }, - "parameters": { - "type": "object", - "properties": { - "event": { - "type": "string" - }, - "product": { - "type": "string" + ```json + { + "type": "object", + "properties": { + "webUrl": { + "type": "string" + }, + "parameters": { + "type": "object", + "properties": { + "event": { + "type": "string" + }, + "product": { + "type": "string" + } } + }, + "webDescription": { + "type": "string" + }, + "creatorName": { + "type": "string" + }, + "creatorEmail": { + "type": ["string", "null"] + }, + "createdTimeUTC": { + "type": "string" } - }, - "webDescription": { - "type": "string" - }, - "creatorName": { - "type": "string" - }, - "creatorEmail": { - "type": "string" - }, - "createdTimeUTC": { - "type": "string" } } - } - ``` - -5. Select **+ New Step**. - -6. Search for **Create item**, and select **SharePoint - Create item**. - -7. Enter the site address where the list above was created. - -8. Select the "Site Directory" list you created in the previous step. - -9. Enter a value for the **Title** field - this will be the same value for each list item. For example: "Contoso Travel: New Project Site Created". - -10. For each field in your list form, add the corresponding element from the Dynamic Content picker. When you are done your action should look something like this: + ``` -![Screenshot of a flow named 'When an HTTP request is received', showing the URL, Request body, Queue name, and Message fields](images/site-directory-flow-configuration.png) +1. Select **+ New Step**. +1. Search for **Create item**, and select **SharePoint - Create item**. +1. Enter the site address where the list above was created. +1. Select the "Site Directory" list you created in the previous step. +1. Enter a value for the **Title** field - this will be the same value for each list item. For example: "Contoso Travel: New Project Site Created". +1. For each field in your list form, add the corresponding element from the Dynamic Content picker. When you are done your action should look something like this: -11. Choose **Save**. This generates the HTTP Post URL that you will need to copy for your site script `triggerFlow` action. + ![Screenshot of a flow named 'When an HTTP request is received', showing the URL, Request body, Queue name, and Message fields](images/site-directory-flow-configuration.png) -14. Choose the first step in your flow ('When an HTTP request is received') and copy the URL. - -15. Save your flow. +1. Choose **Save**. This generates the HTTP Post URL that you will need to copy for your site script `triggerFlow` action. +1. Choose the first step in your flow ('When an HTTP request is received') and copy the URL. +1. Save your flow. ## Create the site design 1. Open PowerShell and make sure that you have the latest [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588) installed. +1. Connect to your tenant using **Connect-SPOService**. -2. Connect to your tenant using **Connect-SPOService**. - - ```powershell + ```powershell Connect-SPOService -Url https://[yourtenant]-admin.sharepoint.com - ``` + ``` -3. Now you can get the existing site designs. +1. Now you can get the existing site designs. - ```powershell + ```powershell Get-SPOSiteDesign - ``` + ``` -
+ To create a site design, you first need to create a site script. A site design is a container that refers to one or more site scripts. -To create a site design, you first need to create a site script. A site design is a container that refers to one or more site scripts. +1. Copy the following JSON code to your clipboard and modify it. Set the **url** property to the value that you copied when you created the flow. The URL looks similar to the following: -1. Copy the following JSON code to your clipboard and modify it. Set the `url` property to the value that you copied when you created the flow. The URL looks similar to the following: + ```http + https://prod-27.westus.logic.azure.com:443/workflows/ef7434cf0d704dd48ef5fb6...oke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun + ``` - `https://prod-27.westus.logic.azure.com:443/workflows/ef7434cf0d704dd48ef5fb6...oke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun` - - ```json + ```json { "$schema": "schema.json", "actions": [ @@ -142,25 +128,24 @@ To create a site design, you first need to create a site script. A site design i } ] } - ``` - -2. Select the JSON again and copy it again to your clipboard. + ``` -3. Open PowerShell and enter the following to copy the script into a variable and create the site script: +1. Select the JSON again and copy it again to your clipboard. +1. Open PowerShell and enter the following to copy the script into a variable and create the site script: - ```powershell + ```powershell $script = Get-Clipboard -Raw Add-SPOSiteScript -Title "Site Script to record site creation event" -Content $script Get-SPOSiteScript - ``` + ``` -4. You will see a list of one or more site scripts, including the site script you just created. Select the ID of the site script that you created, and copy it to the clipboard. +1. You will see a list of one or more site scripts, including the site script you just created. Select the ID of the site script that you created, and copy it to the clipboard. +1. Use the following command to create the site design: -5. Use the following command to create the site design: - - ```powershell + ```powershell Add-SPOSiteDesign -Title "Record site creation" -Description "The creation of this site will be recorded in the site directory list" -SiteScripts [Paste the ID of the Site Script here] -WebTemplate "64" - ``` + ``` + > [!NOTE] > The **Add-SPOSiteDesign** cmdlet associates the site design with the Team site. If you want to associate the design with a Communication site, use `-WebTemplate "68"`. @@ -170,9 +155,7 @@ To test the results, create a new site. In your SharePoint tenant, select **Shar Your new site design should show up as a design option. Notice that the site design is applied after the site is created. If you configured it correctly, your flow will be triggered. You can check the run history of the flow to verify that it ran correctly. - ## See also - [SharePoint site design and site script overview](site-design-overview.md) - [Calling the PnP provisioning engine from a site script](site-design-pnp-provisioning.md) - diff --git a/docs/declarative-customization/site-theming/sharepoint-site-theming-csom.md b/docs/declarative-customization/site-theming/sharepoint-site-theming-csom.md index 6daee60ec..a15b25f9c 100644 --- a/docs/declarative-customization/site-theming/sharepoint-site-theming-csom.md +++ b/docs/declarative-customization/site-theming/sharepoint-site-theming-csom.md @@ -1,13 +1,13 @@ --- title: SharePoint site theming - CSOM development -description: The SharePoint client-side object model (CSOM) provides access to the SharePoint object model from code that is running locally or on a different server than SharePoint. -ms.date: 04/19/2018 -localization_priority: Priority +description: The SharePoint client-side object model (CSOM) provides access to the SharePoint object model from code that is running locally or on a different server than SharePoint. +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint site theming: CSOM development -The SharePoint client-side object model (CSOM) provides access to the SharePoint object model from code that is running locally or on a different server than SharePoint. +The SharePoint client-side object model (CSOM) provides access to the SharePoint object model from code that is running locally or on a different server than SharePoint. ## Prerequisites @@ -20,7 +20,7 @@ You also need to reference the [Microsoft.SharePointOnline.CSOM](https://www.nug ## CSOM code example -The following example shows how to create a __Microsoft.Online.SharePoint.TenantAdministration.Tenant__ object and call the __GetAllTenantThemes__ method to return a list of themes. +The following example shows how to create a __Microsoft.Online.SharePoint.TenantAdministration.Tenant__ object and call the __GetAllTenantThemes__ method to return a list of themes. > [!NOTE] > * The URL used to create the context object includes the _-admin_ suffix because **TenantAdministration** methods work with the admin site. @@ -80,7 +80,7 @@ public class SPOTheme  ## Applying a theme -There's currently no supported CSOM API to programmatically apply a theme to a specific site. For information on applying custom themes to individual site collections see [SharePoint site design and site script overview](https://docs.microsoft.com/sharepoint/dev/declarative-customization/site-design-overview) +There's currently no supported CSOM API to programmatically apply a theme to a specific site. For information on applying custom themes to individual site collections see [SharePoint site design and site script overview](/sharepoint/dev/declarative-customization/site-design-overview) ## Methods/properties of the Microsoft.Online.SharePoint.TenantAdministration.Tenant class @@ -92,7 +92,7 @@ Add a theme to the tenant. __Namespace:__ Microsoft.Online.SharePoint.TenantAdministration.Tenant
__Parameters:__ string name, string themeJson
-__Return type:__ ClientResult +__Return type:__ ClientResult\ ### DeleteTenantTheme public method @@ -108,7 +108,7 @@ Retrieve all the themes that are currently available in the tenant, including an __Namespace:__ Microsoft.Online.SharePoint.TenantAdministration.Tenant
__Parameters:__ none
-__Return type:__ ClientObjectList +__Return type:__ ClientObjectList\ ### GetTenantTheme public method @@ -131,7 +131,7 @@ Update the settings for an existing theme. __Namespace:__ Microsoft.Online.SharePoint.TenantAdministration.Tenant
__Parameters:__ string name, string themeJson
-__Return type:__ ClientResult +__Return type:__ ClientResult\ ## Methods of the Microsoft.Online.SharePoint.TenantManagement.Tenant class @@ -143,7 +143,7 @@ Add a theme to the tenant. __Namespace:__ Microsoft.Online.SharePoint.TenantManagement.Tenant
__Parameters:__ string name, string themeJson
-__Return type:__ ClientResult +__Return type:__ ClientResult\ ### GetAllTenantThemes public method @@ -151,7 +151,7 @@ Retrieve all the themes that are currently available in the tenant, including an __Namespace:__ Microsoft.Online.SharePoint.TenantManagement.Tenant
__Parameters:__ none
-__Return type:__ ClientObjectList +__Return type:__ ClientObjectList\ ### GetHideDefaultThemes public method @@ -159,7 +159,7 @@ Read the current setting for whether to hide default themes in the theme picker __Namespace:__ Microsoft.Online.SharePoint.TenantManagement.Tenant
__Parameters:__ none
-__Return type:__ ClientResult +__Return type:__ ClientResult\ ### GetTenantTheme public method @@ -183,7 +183,7 @@ Update the settings for an existing theme. __Namespace:__ Microsoft.Online.SharePoint.TenantManagement.Tenant
__Parameters:__ string name, string themeJson
-__Return type:__ ClientResult +__Return type:__ ClientResult\ ## See also @@ -191,4 +191,3 @@ __Return type:__ ClientResult * [SharePoint site theming: JSON schema](sharepoint-site-theming-json-schema.md) * [SharePoint site theming: PowerShell cmdlets](sharepoint-site-theming-powershell.md) * [SharePoint site theming: REST API](sharepoint-site-theming-rest-api.md) - diff --git a/docs/declarative-customization/site-theming/sharepoint-site-theming-json-schema.md b/docs/declarative-customization/site-theming/sharepoint-site-theming-json-schema.md index f282c180f..db182d93b 100644 --- a/docs/declarative-customization/site-theming/sharepoint-site-theming-json-schema.md +++ b/docs/declarative-customization/site-theming/sharepoint-site-theming-json-schema.md @@ -1,8 +1,8 @@ --- title: SharePoint site theming - JSON schema description: The new SharePoint site theming features use a JSON schema to store color settings and other information about each theme. -ms.date: 05/09/2020 -localization_priority: Priority +ms.date: 08/08/2024 +ms.localizationpriority: high --- # SharePoint site theming: JSON schema @@ -95,7 +95,18 @@ The SharePoint Framework includes eight built-in themes: six on light background Another option is to use the [Theme Generator tool](https://aka.ms/themedesigner) to build a custom theme. It provides an interactive UI for selecting theme colors, and automatically generates the JSON, SASS, and PowerShell definitions for your custom theme. > [!NOTE] -> The theme generator definitions do not currently include the "error" or "accent" color slots. These can be manually added to your generated definition before uploading to the tenant. +> The theme generator definitions do not currently include the following color slots and key/value pairs: +> +> - "primaryBackground" +> - "primaryText" +> - "bodyBackground" +> - "bodyText" +> - "disabledBackground" +> - "disabledText" +> - "error" +> - "accent" +> +> These can be manually added to your generated definition before uploading to the tenant. ![Theme Generator tool](../../images/theme-generator-tool.png) @@ -105,80 +116,50 @@ The following is a summary of the built-in themes, including JSON definitions fo The following table shows the color palette used by the Teal theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #014446black: #000000
themeDark: #025c5fneutralDark: #212121
themeDarkAlt: #026d70neutralPrimary: #333
themePrimary: #03787cneutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
themeSecondary: #13898dneutralTertiaryAlt: #c8c8c8
themeTertiary: #49aeb1neutralLight: #eaeaea
themeLight: #98d6d8neutralLighter: #f4f4f4
themeLighter: #c5e9eaneutralLighterAlt: #f8f8f8
themeLighterAlt: #f0f9fawhite: #fff
- -The following code shows how to define a dictionary in PowerShell for the Red theme's color palette. +| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #014446 | black: #000000 | +| themeDark: #025c5f | neutralDark: #212121 | +| themeDarkAlt: #026d70 | neutralPrimary: #333 | +| themePrimary: #03787c | neutralPrimaryAlt: #3c3c3c | +| | neutralSecondary: #666666 | +| | neutralTertiary: #a6a6a6 | +| themeSecondary: #13898d | neutralTertiaryAlt: #c8c8c8 | +| themeTertiary: #49aeb1 | neutralLight: #eaeaea | +| themeLight: #98d6d8 | neutralLighter: #f4f4f4 | +| themeLighter: #c5e9ea | neutralLighterAlt: #f8f8f8 | +| themeLighterAlt: #f0f9fa | white: #fff | + +The following code shows how to define a dictionary in PowerShell for the Teal theme's color palette. ```powershell {  -    themeDarker: '#014446',  -    themeDark: '#025c5f',  -    themeDarkAlt: '#026d70',  -    themePrimary: '#03787c',  -    themeSecondary: '#13898d',  -    themeTertiary: '#49aeb1',  -    themeLight: '#98d6d8',  -    themeLighter: '#c5e9ea',  -    themeLighterAlt: '#f0f9fa',  -    black: '#000000',  -    neutralDark: '#212121',  -    neutralPrimary: '#333',  -    neutralPrimaryAlt: '#3c3c3c',  -    neutralSecondary: '#666666',  -    neutralTertiary: '#a6a6a6',  -    neutralTertiaryAlt: '#c8c8c8',  -    neutralLight: '#eaeaea',  -    neutralLighter: '#f4f4f4',  -    neutralLighterAlt: '#f8f8f8',  -    white: '#fff',  -    neutralQuaternaryAlt: '#dadada',  -    neutralQuaternary: '#d0d0d0',  -    neutralSecondaryAlt: '#767676',  -    primaryBackground: '#fff',  -    primaryText: '#333', - accent: '#4f6bed' + themeDarker: '#014446',  + themeDark: '#025c5f',  + themeDarkAlt: '#026d70',  + themePrimary: '#03787c',  + themeSecondary: '#13898d',  + themeTertiary: '#49aeb1',  + themeLight: '#98d6d8',  + themeLighter: '#c5e9ea',  + themeLighterAlt: '#f0f9fa',  + black: '#000000',  + neutralDark: '#212121',  + neutralPrimary: '#333',  + neutralPrimaryAlt: '#3c3c3c',  + neutralSecondary: '#666666',  + neutralTertiary: '#a6a6a6',  + neutralTertiaryAlt: '#c8c8c8',  + neutralLight: '#eaeaea',  + neutralLighter: '#f4f4f4',  + neutralLighterAlt: '#f8f8f8',  + white: '#fff',  + neutralQuaternaryAlt: '#dadada',  + neutralQuaternary: '#d0d0d0',  + neutralSecondaryAlt: '#767676',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#4f6bed' } ``` @@ -186,80 +167,50 @@ The following code shows how to define a dictionary in PowerShell for the Red th The following table shows the color palette used by the Red theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #751b1eblack: #000000
themeDark: #952226neutralDark: #212121
themeDarkAlt: #c02b30neutralPrimary: #333
themePrimary: #d13438neutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
themeSecondary: #d6494dneutralTertiaryAlt: #c8c8c8
themeTertiary: #ecaaacneutralLight: #eaeaea
themeLight: #f6d6d8neutralLighter: #f4f4f4
themeLighter: #faebebneutralLighterAlt: #f8f8f8
themeLighterAlt: #fdf5f5white: #fff
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #751b1e | black: #000000 | +| themeDark: #952226 | neutralDark: #212121 | +| themeDarkAlt: #c02b30 | neutralPrimary: #333 | +| themePrimary: #d13438 | neutralPrimaryAlt: #3c3c3c | +| | neutralSecondary: #666666 | +| | neutralTertiary: #a6a6a6 | +| themeSecondary: #d6494d | neutralTertiaryAlt: #c8c8c8 | +| themeTertiary: #ecaaac | neutralLight: #eaeaea | +| themeLight: #f6d6d8 | neutralLighter:#f4f4f4 | +| themeLighter: #faebeb | neutralLighterAlt: #f8f8f8 | +| themeLighterAlt: #fdf5f5 | white: #fff | The following code shows how to define a dictionary in PowerShell for the Red theme's color palette. ```powershell {  -    themeDarker: '#751b1e',  -    themeDark: '#952226',  -    themeDarkAlt: '#c02b30',  -    themePrimary: '#d13438',  -    themeSecondary: '#d6494d',  -    themeTertiary: '#ecaaac',  -    themeLight: '#f6d6d8',  -    themeLighter: '#faebeb',  -    themeLighterAlt: '#fdf5f5',  -    black: '#000000',  -    neutralDark: '#212121',  -    neutralPrimary: '#333',  -    neutralPrimaryAlt: '#3c3c3c',  -    neutralSecondary: '#666666',  -    neutralTertiary: '#a6a6a6',  -    neutralTertiaryAlt: '#c8c8c8',  -    neutralLight: '#eaeaea',  -    neutralLighter: '#f4f4f4',  -    neutralLighterAlt: '#f8f8f8',  -    white: '#fff',  -    neutralQuaternaryAlt: '#dadada',  -    neutralQuaternary: '#d0d0d0',  -    neutralSecondaryAlt: '#767676',  -    primaryBackground: '#fff',  -    primaryText: '#333', - accent: '#ca5010' + themeDarker: '#751b1e',  + themeDark: '#952226',  + themeDarkAlt: '#c02b30',  + themePrimary: '#d13438',  + themeSecondary: '#d6494d',  + themeTertiary: '#ecaaac',  + themeLight: '#f6d6d8',  + themeLighter: '#faebeb',  + themeLighterAlt: '#fdf5f5',  + black: '#000000',  + neutralDark: '#212121',  + neutralPrimary: '#333',  + neutralPrimaryAlt: '#3c3c3c',  +  neutralSecondary: '#666666',  + neutralTertiary: '#a6a6a6',  + neutralTertiaryAlt: '#c8c8c8',  + neutralLight: '#eaeaea',  + neutralLighter: '#f4f4f4',  + neutralLighterAlt: '#f8f8f8',  + white: '#fff',  + neutralQuaternaryAlt: '#dadada',  + neutralQuaternary: '#d0d0d0',  + neutralSecondaryAlt: '#767676',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#ca5010' } ``` @@ -267,81 +218,50 @@ The following code shows how to define a dictionary in PowerShell for the Red th The following table shows the color palette used by the Orange theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #6f2d09black: #000000
themeDark: #8d390bneutralDark: #212121
themeDarkAlt: #b5490fneutralPrimary: #333
themePrimary: #ca5010neutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
themeSecondary: #e55c12neutralTertiaryAlt: #c8c8c8
themeTertiary: #f6b28dneutralLight: #eaeaea
themeLight: #fbdac9neutralLighter: #f4f4f4
themeLighter: #fdede4neutralLighterAlt: #f8f8f8
themeLighterAlt: #fef6f1white: #fff
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #6f2d09 | black: #000000 | +| themeDark: #8d390b | neutralDark: #212121 | +| themeDarkAlt: #b5490f | neutralPrimary: #333 | +| themePrimary: #ca5010 | neutralPrimaryAlt: #3c3c3c | +| | neutralSecondary: #666666 | +| | neutralTertiary: #a6a6a6 | +| themeSecondary: #e55c12 | neutralTertiaryAlt: #c8c8c8 | +| themeTertiary: #f6b28d | neutralLight: #eaeaea | +| themeLight: #fbdac9 | neutralLighter: #f4f4f4 | +| themeLighter: #fdede4 | neutralLighterAlt: #f8f8f8 | +| themeLighterAlt: #fef6f1 | white: #fff | The following code shows how to define a dictionary in PowerShell for the Orange theme's color palette. ```powershell {  -    themeDarker: '#6f2d09',  -    themeDark: '#8d390b',  -    themeDarkAlt: '#b5490f',  -    themePrimary: '#ca5010',  -    themeSecondary: '#e55c12',  -    themeTertiary: '#f6b28d',  -    themeLight: '#fbdac9',  -    themeLighter: '#fdede4',  -    themeLighterAlt: '#fef6f1',  -    black: '#000000',  -    neutralDark: '#212121',  -    neutralPrimary: '#333',  -    neutralPrimaryAlt: '#3c3c3c',  -    neutralSecondary: '#666666',  -    neutralTertiary: '#a6a6a6',  -    neutralTertiaryAlt: '#c8c8c8',  -    neutralLight: '#eaeaea',  -    neutralLighter: '#f4f4f4',  -    neutralLighterAlt: '#f8f8f8',  -    white: '#fff',  -    neutralQuaternaryAlt: '#dadada',  -    neutralQuaternary: '#d0d0d0',  -    neutralSecondaryAlt: '#767676',  -    primaryBackground: '#fff',  -    primaryText: '#333', - accent: '#986f0b' + themeDarker: '#6f2d09',  + themeDark: '#8d390b',  + themeDarkAlt: '#b5490f',  + themePrimary: '#ca5010',  + themeSecondary: '#e55c12',  + themeTertiary: '#f6b28d',  + themeLight: '#fbdac9',  + themeLighter: '#fdede4',  + themeLighterAlt: '#fef6f1',  + black: '#000000',  + neutralDark: '#212121',  + neutralPrimary: '#333',  + neutralPrimaryAlt: '#3c3c3c',  + neutralSecondary: '#666666',  + neutralTertiary: '#a6a6a6',  + neutralTertiaryAlt: '#c8c8c8',  + neutralLight: '#eaeaea',  + neutralLighter: '#f4f4f4',  + neutralLighterAlt: '#f8f8f8',  + white: '#fff',  + neutralQuaternaryAlt: '#dadada',  + neutralQuaternary: '#d0d0d0',  + neutralSecondaryAlt: '#767676',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#986f0b' } ``` @@ -349,81 +269,50 @@ The following code shows how to define a dictionary in PowerShell for the Orange The following table shows the color palette used by the Green theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #094c23black: #000000
themeDark: #0c602cneutralDark: #212121
themeDarkAlt: #0f7c39neutralPrimary: #333
themePrimary: #10893eneutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
themeSecondary: #14a94eneutralTertiaryAlt: #c8c8c8
themeTertiary: #7aefa7neutralLight: #eaeaea
themeLight: #bff7d5neutralLighter: #f4f4f4
themeLighter: #dffbeaneutralLighterAlt: #f8f8f8
themeLighterAlt: #effdf4white: #fff
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #294903 | black: #000000 | +| themeDark: #386304 | neutralDark: #201f1e | +| themeDarkAlt: #427505 | neutralPrimary: #323130 | +| themePrimary: #498205 | neutralPrimaryAlt: #3b3a39 | +| | neutralSecondary: #605e5c | +| | neutralTertiary: #a19f9d | +| themeSecondary: #5a9117 | neutralTertiaryAlt: #c8c6c4 | +| themeTertiary: #85b44c | neutralLight: #edebe9 | +| themeLight: #bdda9b | neutralLighter: #f3f2f1 | +| themeLighter: #dbebc7 | neutralLighterAlt: #faf9f8 | +| themeLighterAlt: #f6faf0 | white: #fff | The following code shows how to define a dictionary in PowerShell for the Green theme's color palette. ```powershell {  -    themePrimary: '#10893e',  -    themeLighterAlt: '#effdf4',  -    themeLighter: '#dffbea',  -    themeLight: '#bff7d5',  -    themeTertiary: '#7aefa7',  -    themeSecondary: '#14a94e',  -    themeDarkAlt: '#0f7c39',  -    themeDark: '#0c602c',  -    themeDarker: '#094c23',  -    neutralLighterAlt: '#f8f8f8',  -    neutralLighter: '#f4f4f4',  -    neutralLight: '#eaeaea',  -    neutralQuaternaryAlt: '#dadada',  -    neutralQuaternary: '#d0d0d0',  -    neutralTertiaryAlt: '#c8c8c8',  -    neutralTertiary: '#a6a6a6',  -    neutralSecondaryAlt: '#767676',  -    neutralSecondary: '#666666',  -    neutralPrimary: '#333',  -    neutralPrimaryAlt: '#3c3c3c',  -    neutralDark: '#212121',  -    black: '#000000',  -    white: '#fff',  -    primaryBackground: '#fff',  -    primaryText: '#333', - accent: '#038387' + themePrimary: '#498205',  + themeLighterAlt: '#f6faf0',  + themeLighter: '#dbebc7',  + themeLight: '#bdda9b',  + themeTertiary: '#85b44c',  + themeSecondary: '#5a9117',  + themeDarkAlt: '#427505',  + themeDark: '#386304',  + themeDarker: '#294903',  + neutralLighterAlt: '#faf9f8',  + neutralLighter: '#f3f2f1',  + neutralLight: '#edebe9',  + neutralQuaternaryAlt: '#e1dfdd',  + neutralQuaternary: '#d2d0ce',  + neutralTertiaryAlt: '#c8c6c4',  + neutralTertiary: '#a19f9d',  + neutralSecondaryAlt: '#8a8886',  + neutralSecondary: '#605e5c',  + neutralPrimary: '#323130',  + neutralPrimaryAlt: '#3b3a39',  + neutralDark: '#201f1e',  + black: '#000000',  + white: '#fff',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#03787c' } ``` @@ -431,81 +320,50 @@ The following code shows how to define a dictionary in PowerShell for the Green The following table shows the color palette used by the Blue theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #004578black: #000000
themeDark: #005a9eneutralDark: #212121
themeDarkAlt: #106ebeneutralPrimary: #333
themePrimary: #0078d7neutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
themeSecondary: #2b88d8neutralTertiaryAlt: #c8c8c8
themeTertiary: #71afe5neutralLight: #eaeaea
themeLight: #c7e0f4neutralLighter: #f4f4f4
themeLighter: #deecf9neutralLighterAlt: #f8f8f8
themeLighterAlt: #eff6fcwhite: #fff
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #004578 | black: #000000 | +| themeDark: #005a9e | neutralDark: #212121 | +| themeDarkAlt: #106ebe | neutralPrimary: #333 | +| themePrimary: #0078d7 | neutralPrimaryAlt: #3c3c3c | +| | neutralSecondary: #666666 | +| | neutralTertiary: #a6a6a6 | +| themeSecondary: #2b88d8 | neutralTertiaryAlt: #c8c8c8 | +| themeTertiary: #71afe5 | neutralLight: #eaeaea | +| themeLight: #c7e0f4 | neutralLighter: #f4f4f4 | +| themeLighter: #deecf9 | neutralLighterAlt: #f8f8f8 | +| themeLighterAlt: #eff6fc | white: #fff | The following code shows how to define a dictionary in PowerShell for the Blue theme's color palette. ```powershell {  -    themePrimary: '#0078d7',  -    themeLighterAlt: '#eff6fc',  -    themeLighter: '#deecf9',  -    themeLight: '#c7e0f4',  -    themeTertiary: '#71afe5',  -    themeSecondary: '#2b88d8',  -    themeDarkAlt: '#106ebe',  -    themeDark: '#005a9e',  -    themeDarker: '#004578',  -    neutralLighterAlt: '#f8f8f8',  -    neutralLighter: '#f4f4f4',  -    neutralLight: '#eaeaea',  -    neutralQuaternaryAlt: '#dadada',  -    neutralQuaternary: '#d0d0d0',  -    neutralTertiaryAlt: '#c8c8c8',  -    neutralTertiary: '#a6a6a6',  -    neutralSecondaryAlt: '#767676',  -    neutralSecondary: '#666666',  -    neutralPrimary: '#333',  -    neutralPrimaryAlt: '#3c3c3c',  -    neutralDark: '#212121',  -    black: '#000000',  -    white: '#fff',  -    primaryBackground: '#fff',  -    primaryText: '#333', - accent: '#8764b8' + themePrimary: '#0078d7',  + themeLighterAlt: '#eff6fc',  + themeLighter: '#deecf9',  + themeLight: '#c7e0f4',  + themeTertiary: '#71afe5',  + themeSecondary: '#2b88d8',  + themeDarkAlt: '#106ebe',  + themeDark: '#005a9e',  + themeDarker: '#004578',  + neutralLighterAlt: '#f8f8f8',  + neutralLighter: '#f4f4f4',  + neutralLight: '#eaeaea',  + neutralQuaternaryAlt: '#dadada',  + neutralQuaternary: '#d0d0d0',  + neutralTertiaryAlt: '#c8c8c8',  + neutralTertiary: '#a6a6a6',  + neutralSecondaryAlt: '#767676',  + neutralSecondary: '#666666',  + neutralPrimary: '#333',  + neutralPrimaryAlt: '#3c3c3c',  + neutralDark: '#212121',  + black: '#000000',  + white: '#fff',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#8764b8' } ``` @@ -513,81 +371,50 @@ The following code shows how to define a dictionary in PowerShell for the Blue t The following table shows the color palette used by the Purple theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #27268ablack: #000000
themeDark: #3230b0neutralDark: #212121
themeDarkAlt: #5250cfneutralPrimary: #333
themePrimary: #6b69d6neutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
themeSecondary: #7a78daneutralTertiaryAlt: #c8c8c8
themeTertiary: #c1c0eeneutralLight: #eaeaea
themeLight: #e1e1f7neutralLighter: #f4f4f4
themeLighter: #f0f0fbneutralLighterAlt: #f8f8f8
themeLighterAlt: #f8f7fdwhite: #fff
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #27268a | black: #000000 | +| themeDark: #3230b0 | neutralDark: #212121 | +| themeDarkAlt: #5250cf | neutralPrimary: #333 | +| themePrimary: #6b69d6 | neutralPrimaryAlt: #3c3c3c | +| | neutralSecondary: #666666 | +| | neutralTertiary: #a6a6a6 | +| themeSecondary: #7a78da | neutralTertiaryAlt: #c8c8c8 | +| themeTertiary: #c1c0ee | neutralLight: #eaeaea | +| themeLight: #e1e1f7 | neutralLighter: #f4f4f4 | +| themeLighter: #f0f0fb | neutralLighterAlt: #f8f8f8 | +| themeLighterAlt: #f8f7fd | white: #fff | The following code shows how to define a dictionary in PowerShell for the Purple theme's color palette. ```powershell {  -    themePrimary: '#6b69d6',  -    themeLighterAlt: '#f8f7fd',  -    themeLighter: '#f0f0fb',  -    themeLight: '#e1e1f7',  -    themeTertiary: '#c1c0ee',  -    themeSecondary: '#7a78da',  -    themeDarkAlt: '#5250cf',  -    themeDark: '#3230b0',  -    themeDarker: '#27268a',  -    neutralLighterAlt: '#f8f8f8',  -    neutralLighter: '#f4f4f4',  -    neutralLight: '#eaeaea',  -    neutralQuaternaryAlt: '#dadada',  -    neutralQuaternary: '#d0d0d0',  -    neutralTertiaryAlt: '#c8c8c8',  -    neutralTertiary: '#a6a6a6',  -    neutralSecondaryAlt: '#767676',  -    neutralSecondary: '#666666',  -    neutralPrimary: '#333',  -    neutralPrimaryAlt: '#3c3c3c',  -    neutralDark: '#212121',  -    black: '#000000',  -    white: '#fff',  -    primaryBackground: '#fff',  -    primaryText: '#333', - accent: '#038387' + themePrimary: '#6b69d6',  + themeLighterAlt: '#f8f7fd',  + themeLighter: '#f0f0fb',  + themeLight: '#e1e1f7',  + themeTertiary: '#c1c0ee',  + themeSecondary: '#7a78da',  + themeDarkAlt: '#5250cf',  + themeDark: '#3230b0',  + themeDarker: '#27268a',  + neutralLighterAlt: '#f8f8f8',  + neutralLighter: '#f4f4f4',  + neutralLight: '#eaeaea',  + neutralQuaternaryAlt: '#dadada',  + neutralQuaternary: '#d0d0d0',  + neutralTertiaryAlt: '#c8c8c8',  + neutralTertiary: '#a6a6a6',  + neutralSecondaryAlt: '#767676',  + neutralSecondary: '#666666',  + neutralPrimary: '#333',  + neutralPrimaryAlt: '#3c3c3c',  + neutralDark: '#212121',  + black: '#000000',  + white: '#fff',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#038387' } ``` @@ -595,164 +422,154 @@ The following code shows how to define a dictionary in PowerShell for the Purple The following table shows the color palette used by the Gray theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #323130black: #000000
themeDark: #403e3dneutralDark: #212121
themeDarkAlt: #53504eneutralPrimary: #333
themePrimary: #5d5a58neutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
themeSecondary: #6d6a67neutralTertiaryAlt: #c8c8c8
themeTertiary: #bbb9b8neutralLight: #eaeaea
themeLight: #dfdeddneutralLighter: #f4f4f4
themeLighter: #efeeeeneutralLighterAlt: #f8f8f8
themeLighterAlt: #f7f7f7white: #fff
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #323130 | black: #000000 | +| themeDark: #403e3d | neutralDark: #212121 | +| themeDarkAlt: #53504e | neutralPrimary: #333 | +| themePrimary: #5d5a58 | neutralPrimaryAlt: #3c3c3c | +| | neutralSecondary: #666666 | +| | neutralTertiary: #a6a6a6 | +| themeSecondary: #6d6a67 | neutralTertiaryAlt: #c8c8c8 | +| themeTertiary: #bbb9b8 | neutralLight: #eaeaea | +| themeLight: #dfdedd | neutralLighter: #f4f4f4 | +| themeLighter: #efeeee | neutralLighterAlt: #f8f8f8 | +| themeLighterAlt: #f7f7f7 | white: #fff | The following code shows how to define a dictionary in PowerShell for the Gray theme's color palette. ```powershell {  -    themePrimary: '#5d5a58',  -    themeLighterAlt: '#f7f7f7',  -    themeLighter: '#efeeee',  -    themeLight: '#dfdedd',  -    themeTertiary: '#bbb9b8',  -    themeSecondary: '#6d6a67',  -    themeDarkAlt: '#53504e',  -    themeDark: '#403e3d',  -    themeDarker: '#323130',  -    neutralLighterAlt: '#f8f8f8',  -    neutralLighter: '#f4f4f4',  -    neutralLight: '#eaeaea',  -    neutralQuaternaryAlt: '#dadada',  -    neutralQuaternary: '#d0d0d0',  -    neutralTertiaryAlt: '#c8c8c8',  -    neutralTertiary: '#a6a6a6',  -    neutralSecondaryAlt: '#767676',  -    neutralSecondary: '#666666',  -    neutralPrimary: '#333',  -    neutralPrimaryAlt: '#3c3c3c',  -    neutralDark: '#212121',  -    black: '#000000',  -    white: '#fff',  -    primaryBackground: '#fff',  -    primaryText: '#333', - accent: '#0078d4' + themePrimary: '#5d5a58',  + themeLighterAlt: '#f7f7f7',  + themeLighter: '#efeeee',  + themeLight: '#dfdedd',  + themeTertiary: '#bbb9b8',  + themeSecondary: '#6d6a67',  + themeDarkAlt: '#53504e',  + themeDark: '#403e3d',  + themeDarker: '#323130',  + neutralLighterAlt: '#f8f8f8',  + neutralLighter: '#f4f4f4',  + neutralLight: '#eaeaea',  + neutralQuaternaryAlt: '#dadada',  + neutralQuaternary: '#d0d0d0',  + neutralTertiaryAlt: '#c8c8c8',  + neutralTertiary: '#a6a6a6',  + neutralSecondaryAlt: '#767676',  + neutralSecondary: '#666666',  + neutralPrimary: '#333',  + neutralPrimaryAlt: '#3c3c3c',  + neutralDark: '#212121',  + black: '#000000',  + white: '#fff',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#0078d4' +} +``` + +## Periwinkle theme + +The following table shows the color palette used by the Periwinkle theme. + +| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #383966 | black: #000000 | +| themeDark: #3D3E78 | neutralDark: #201f1e | +| themeDarkAlt: #444791 | neutralPrimary: #323130 | +| themePrimary: #5B5FC7 | neutralPrimaryAlt: #3b3a39 | +| | neutralSecondary: #605e5c | +| | neutralTertiary: #a19f9d | +| themeSecondary: #7579EB | neutralTertiaryAlt: #c8c6c4 | +| themeTertiary: #7F85F5 | neutralLight: #edebe9 | +| themeLight: #AAB1FA | neutralLighter: #f3f2f1 | +| themeLighter: #B6BCFA | neutralLighterAlt: #faf9f8 | +| themeLighterAlt: #C5CBFA | white: #fff | + +The following code shows how to define a dictionary in PowerShell for the Periwinkle theme's color palette. + +```powershell +{  + themeDarker: '#383966',  + themeDark: '#3D3E78',  + themeDarkAlt: '#444791',  + themePrimary: '#5B5FC7',  + themeSecondary: '#7579EB',  + themeTertiary: '#7F85F5',  + themeLight: '#AAB1FA',  + themeLighter: '#B6BCFA',  + themeLighterAlt: '#C5CBFA',  + black: '#000000',  + neutralDark: '#201f1e',  + neutralPrimary: '#323130',  + neutralPrimaryAlt: '#3b3a39',  + neutralSecondary: '#605e5c',  + neutralTertiary: '#a19f9d',  + neutralTertiaryAlt: '#c8c6c4',  + neutralLight: '#edebe9',  + neutralLighter: '#f3f2f1',  + neutralLighterAlt: '#faf9f8',  + white: '#fff',  + neutralQuaternaryAlt: '#dadada',  + neutralQuaternary: '#d0d0d0',  + neutralSecondaryAlt: '#767676',  + primaryBackground: '#fff',  + primaryText: '#333', + accent: '#5B5FC7' } ``` + ## Dark Yellow theme The following table shows the color palette used by the Dark Yellow theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #fff171black: #f8f8f8
themeDark: #ffed4bneutralDark: #f4f4f4
themeDarkAlt: #ffe817neutralPrimary: #ffffff
themePrimary: #fce100neutralPrimaryAlt: #eaeaea
neutralSecondary: #dadada
neutralTertiary: #c8c8c8
themeSecondary: #e3cc00neutralTertiaryAlt: #6d6d6d
themeTertiary: #6a5f00neutralLight: #3f3f3f
themeLight: #322d00neutralLighter: #313131
themeLighter: #191700neutralLighterAlt: #282828
themeLighterAlt: #0d0b00white: #1f1f1f
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #fff171 | black: #f8f8f8 | +| themeDark: #ffed4b | neutralDark: #f4f4f4 | +| themeDarkAlt: #ffe817 | neutralPrimary: #ffffff | +| themePrimary: #fce100 | neutralPrimaryAlt: #eaeaea | +| | neutralSecondary: #dadada | +| | neutralTertiary: #c8c8c8 | +| themeSecondary: #e3cc00 | neutralTertiaryAlt: #6d6d6d | +| themeTertiary: #6a5f00 | neutralLight: #3f3f3f | +| themeLight: #322d00 | neutralLighter: #313131 | +| themeLighter: #191700 | neutralLighterAlt: #282828 | +| themeLighterAlt: #0d0b00 | white: #1f1f1f | The following code shows how to define a dictionary in PowerShell for the Dark Yellow theme's color palette. ```powershell {  -    themePrimary: '#fce100',  -    themeLighterAlt: '#0d0b00',  -    themeLighter: '#191700',  -    themeLight: '#322d00',  -    themeTertiary: '#6a5f00',  -    themeSecondary: '#e3cc00',  -    themeDarkAlt: '#ffe817',  -    themeDark: '#ffed4b',  -    themeDarker: '#fff171',  -    neutralLighterAlt: '#282828',  -    neutralLighter: '#313131',  -    neutralLight: '#3f3f3f',  -    neutralQuaternaryAlt: '#484848',  -    neutralQuaternary: '#4f4f4f',  -    neutralTertiaryAlt: '#6d6d6d',  -    neutralTertiary: '#c8c8c8',  -    neutralSecondaryAlt: '#d0d0d0',  -    neutralSecondary: '#dadada',  -    neutralPrimaryAlt: '#eaeaea',  -    neutralPrimary: '#ffffff',  -    neutralDark: '#f4f4f4',  -    black: '#f8f8f8',  -    white: '#1f1f1f',  -    primaryBackground: '#1f1f1f',  -    primaryText: '#ffffff',  -    error: '#ff5f5f', - accent: '#ffc83d' + themePrimary: '#fce100',  + themeLighterAlt: '#0d0b00',  + themeLighter: '#191700',  + themeLight: '#322d00',  + themeTertiary: '#6a5f00',  + themeSecondary: '#e3cc00',  + themeDarkAlt: '#ffe817',  + themeDark: '#ffed4b',  + themeDarker: '#fff171',  + neutralLighterAlt: '#282828',  + neutralLighter: '#313131',  + neutralLight: '#3f3f3f',  + neutralQuaternaryAlt: '#484848',  + neutralQuaternary: '#4f4f4f',  + neutralTertiaryAlt: '#6d6d6d',  + neutralTertiary: '#c8c8c8',  + neutralSecondaryAlt: '#d0d0d0',  + neutralSecondary: '#dadada',  + neutralPrimaryAlt: '#eaeaea',  + neutralPrimary: '#ffffff',  + neutralDark: '#f4f4f4',  + black: '#f8f8f8',  + white: '#1f1f1f',  + primaryBackground: '#1f1f1f',  + primaryText: '#ffffff',  + error: '#ff5f5f', + accent: '#ffc83d' } ``` @@ -760,82 +577,51 @@ The following code shows how to define a dictionary in PowerShell for the Dark Y The following table shows the color palette used by the Dark Blue theme. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
themeDarker: #6cdfffblack: #f8f8f8
themeDark: #44d6ffneutralDark: #f4f4f4
themeDarkAlt: #0ecbffneutralPrimary: #ffffff
themePrimary: #00bcf2neutralPrimaryAlt: #eaeaea
neutralSecondary: #dadada
neutralTertiary: #c8c8c8
themeSecondary: #00abdaneutralTertiaryAlt: #646e8a
themeTertiary: #005066neutralLight: #404759
themeLight: #002630neutralLighter: #353a49
themeLighter: #001318neutralLighterAlt: #2e3340
themeLighterAlt: #00090cwhite: #262a35
+| Theme colors | Neutral colors | +| ------------------------ | --------------------------- | +| themeDarker: #6cdfff | black: #f8f8f8 | +| themeDark: #44d6ff | neutralDark: #f4f4f4 | +| themeDarkAlt: #0ecbff | neutralPrimary: #ffffff | +| themePrimary: #00bcf2 | neutralPrimaryAlt: #eaeaea | +| | neutralSecondary: #dadada | +| | neutralTertiary: #c8c8c8 | +| themeSecondary: #00abda | neutralTertiaryAlt: #646e8a | +| themeTertiary: #005066 | neutralLight: #404759 | +| themeLight: #002630 | neutralLighter: #353a49 | +| themeLighter: #001318 | neutralLighterAlt: #2e3340 | +| themeLighterAlt: #00090c | white: #262a35 | The following code shows how to define a dictionary in PowerShell for the Dark Blue theme's color palette. ```powershell {  -    themePrimary: '#00bcf2',  -    themeLighterAlt: '#00090c',  -    themeLighter: '#001318',  -    themeLight: '#002630',  -    themeTertiary: '#005066',  -    themeSecondary: '#00abda',  -    themeDarkAlt: '#0ecbff',  -    themeDark: '#44d6ff',  -    themeDarker: '#6cdfff',  -    neutralLighterAlt: '#2e3340',  -    neutralLighter: '#353a49',  -    neutralLight: '#404759',  -    neutralQuaternaryAlt: '#474e62',  -    neutralQuaternary: '#4c546a',  -    neutralTertiaryAlt: '#646e8a',  -    neutralTertiary: '#c8c8c8',  -    neutralSecondaryAlt: '#d0d0d0',  -    neutralSecondary: '#dadada',  -    neutralPrimaryAlt: '#eaeaea',  -    neutralPrimary: '#ffffff',  -    neutralDark: '#f4f4f4',  -    black: '#f8f8f8',  -    white: '#262a35',  -    primaryBackground: '#262a35',  -    primaryText: '#ffffff', -    error: '#ff5f5f', - accent: '#3a96dd' + themePrimary: '#00bcf2',  + themeLighterAlt: '#00090c',  + themeLighter: '#001318',  + themeLight: '#002630',  + themeTertiary: '#005066',  + themeSecondary: '#00abda',  + themeDarkAlt: '#0ecbff',  + themeDark: '#44d6ff',  + themeDarker: '#6cdfff',  + neutralLighterAlt: '#2e3340',  + neutralLighter: '#353a49',  + neutralLight: '#404759',  + neutralQuaternaryAlt: '#474e62',  + neutralQuaternary: '#4c546a',  + neutralTertiaryAlt: '#646e8a',  + neutralTertiary: '#c8c8c8',  + neutralSecondaryAlt: '#d0d0d0',  + neutralSecondary: '#dadada',  + neutralPrimaryAlt: '#eaeaea',  + neutralPrimary: '#ffffff',  + neutralDark: '#f4f4f4',  + black: '#f8f8f8',  + white: '#262a35',  + primaryBackground: '#262a35',  + primaryText: '#ffffff', + error: '#ff5f5f', + accent: '#3a96dd' } ``` diff --git a/docs/declarative-customization/site-theming/sharepoint-site-theming-overview.md b/docs/declarative-customization/site-theming/sharepoint-site-theming-overview.md index 81f209df8..5762ad676 100644 --- a/docs/declarative-customization/site-theming/sharepoint-site-theming-overview.md +++ b/docs/declarative-customization/site-theming/sharepoint-site-theming-overview.md @@ -1,8 +1,8 @@ --- title: SharePoint site theming description: New options for applying custom styles and colors to sites that make it easier to define and manage themes across site collections. -ms.date: 06/05/2020 -localization_priority: Priority +ms.date: 04/23/2025 +ms.localizationpriority: high --- # SharePoint site theming @@ -32,6 +32,7 @@ The following predefined themes are available by default: * __Purple__ * __Green__ * __Gray__ +* __Periwinkle__ * __Dark Yellow__ (inverted theme) * __Dark Blue__ (inverted theme) @@ -46,7 +47,7 @@ In addition to the default themes, you can select from supplementary themes. The -To select from the available themes for a SharePoint site, choose the __gear icon (⚙️)__ in the top right corner of the screen, and then select __Change the look__. You'll be presented with a list of themes to choose from, which might include default themes and/or custom themes depending on how your site has been configured. +To select from the available themes for a SharePoint site, choose the __gear icon (⚙️)__ in the top right corner of the screen, select __Change the look__, then select __theme__. You'll be presented with a list of themes to choose from, which might include default themes and/or custom themes depending on how your site has been configured. The following image shows how the default themes are presented in the theme picker dialog box. @@ -54,11 +55,11 @@ The following image shows how the default themes are presented in the theme pick When you choose a theme in the list, those color settings are instantly applied to the page so that you can see what the selected theme will look like. -After you've found a theme that you want to use, choose **Apply** to save your selection, or choose **Cancel** to revert to your current theme. +After you've found a theme that you want to use, choose **Save** to save your selection, or choose **Cancel** to revert to your current theme. ## Work with classic themes -You can still use the classic themes by choosing the link to **Classic change the look options** under the modern themes listed under **Change the look**. Because the modern SharePoint UI differs from the classic UI, however, some limitations apply when you use classic themes with modern pages. +You can still use the classic themes by choosing the link to **Classic change the look options** at the bottom of the **Change the look** panel. Because the modern SharePoint UI differs from the classic UI, however, some limitations apply when you use classic themes with modern pages. When you select a classic theme, a modern theme is generated from the settings in the classic theme, including the **isInverted** flag, the background image, and the color settings for **ContentAccent1**, **PageBackground**, and **BackgroundOverlay**. If **isInverted** is set to **True**, neutral colors such as **NeutralDark** and **NeutralLight** will be reversed. @@ -71,29 +72,30 @@ The modern site theming experience has been rolled out to classic site templates To do this, you must use a Windows PowerShell script with a CSOM (client-side object model) wrapper. We recommend using the PnP PowerShell enable feature command: 1. Verify that you meet the following minimum requirements: + * You are at least a site collection owner on the site where you want to disable modern site themes * You have read about [Execution Policies](https://technet.microsoft.com/library/dd347641.aspx) -2. Download the latest PnP PowerShell from https://github.com/SharePoint/PnP-PowerShell/releases. +1. Download the latest [PnP PowerShell](https://github.com/pnp/powershell). [!INCLUDE [pnp-powershell](../../../includes/snippets/open-source/pnp-powershell.md)] -3. Enter `Connect-PnPOnline -Url -UseWebLogin` (replacing `` with the url of the site you wish to opt out of). - -4. Enter your credentials when prompted. - -5. To opt out of the site, you need to enable a feature: +1. Enter `Connect-PnPOnline -Url -Interactive -ClientId ` (replacing `` with the URL of the site you wish to connect to, and `` with the Client ID of your [registered Entra ID (Azure AD)](https://pnp.github.io/powershell/articles/registerapplication.html) application). +1. Enter your credentials when prompted. +1. To opt out of the site, you need to enable a feature: * Enter `Get-PnPFeature -Scope Site -Identity 5138468E-3D76-4F72-9DE4-E029F1245A7B` * Verify that nothing is returned from the previous command (this confirms the feature isn’t enabled yet) * Enter `Enable-PnPFeature -Scope Site -Identity 5138468E-3D76-4F72-9DE4-E029F1245A7B` * Enter `Get-PnPFeature -Scope Site -Identity 5138468E-3D76-4F72-9DE4-E029F1245A7B` -6. Verify that the following is returned: +1. Verify that the following is returned: - `ClientSideThemingOptOut - 5138468e-3d76-4f72-9de4-e029f1245a7b` + ```powershell + ClientSideThemingOptOut - 5138468e-3d76-4f72-9de4-e029f1245a7b + ``` -For more information about Windows PowerShell, see [PowerShell](/powershell/scripting/powershell-scripting). +For more information about Windows PowerShell, see [PowerShell](/powershell/scripting/overview). ## See also diff --git a/docs/declarative-customization/site-theming/sharepoint-site-theming-powershell.md b/docs/declarative-customization/site-theming/sharepoint-site-theming-powershell.md index 1da0e31e6..37dc811ec 100644 --- a/docs/declarative-customization/site-theming/sharepoint-site-theming-powershell.md +++ b/docs/declarative-customization/site-theming/sharepoint-site-theming-powershell.md @@ -1,13 +1,13 @@ --- title: SharePoint site theming - PowerShell cmdlets description: SharePoint tenant administrators can use PowerShell cmdlets to create, retrieve, and remove site themes. Developers can use the SharePoint REST API to handle theme management tasks. -ms.date: 03/22/2018 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint site theming: PowerShell cmdlets -SharePoint tenant administrators can use PowerShell cmdlets to create, retrieve, and remove site themes. +SharePoint tenant administrators can use PowerShell cmdlets to create, retrieve, and remove site themes. Developers can use the SharePoint [REST API](sharepoint-site-theming-rest-api.md) to handle theme management tasks. @@ -18,8 +18,7 @@ For information about how themes are defined and stored, see [JSON schema refere To run the PowerShell cmdlets for theme management, you must do the following: 1. Download and install the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588). If you already have a previous version of the shell installed, uninstall it first and then install the latest version. - -2. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. +1. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. To verify your setup, try using the [Get-SPOHideDefaultThemes](/powershell/module/sharepoint-online/Get-SPOHideDefaultThemes) cmdlet to read the SPOHideDefaultThemes setting. If the cmdlet runs and returns False with no errors, as shown in the following example, you're ready to proceed. @@ -33,11 +32,7 @@ The following cmdlets are available for managing site themes from PowerShell: * [Set-SPOHideDefaultThemes](/powershell/module/sharepoint-online/Set-SPOHideDefaultThemes) – Specifies whether the default themes should be available. * [Get-SPOHideDefaultThemes](/powershell/module/sharepoint-online/Get-SPOHideDefaultThemes) – Queries the current SPOHideDefaultThemes setting. - ## See also * [SharePoint site theming overview](sharepoint-site-theming-overview.md) * [SharePoint site theming: CSOM](sharepoint-site-theming-csom.md) - - - diff --git a/docs/declarative-customization/site-theming/sharepoint-site-theming-rest-api.md b/docs/declarative-customization/site-theming/sharepoint-site-theming-rest-api.md index 45260171c..de3d44434 100644 --- a/docs/declarative-customization/site-theming/sharepoint-site-theming-rest-api.md +++ b/docs/declarative-customization/site-theming/sharepoint-site-theming-rest-api.md @@ -1,8 +1,8 @@ --- title: SharePoint site theming - REST API description: Use the the SharePoint REST interface to perform basic create, read, update, and delete (CRUD) operations on site themes. -ms.date: 10/29/2019 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint site theming: REST API @@ -15,7 +15,7 @@ The SharePoint Online (and SharePoint 2016 and later on-premises) REST service s Before you get started, make sure that you're familiar with the following: -- [Get to know the SharePoint REST service](../../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) +- [Get to know the SharePoint REST service](../../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) - [Complete basic operations using SharePoint REST endpoints](../../sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints.md) ## REST commands for site themes @@ -119,7 +119,7 @@ function RestRequest(url,params) { req.send(params ? JSON.stringify(params) : void 0); } - + RestRequest("/_api/thememanager/DeleteTenantTheme", { name:"Sounders Rave Green" }); ``` @@ -147,7 +147,7 @@ function RestRequest(url,params) { req.setRequestHeader("ODATA-VERSION","4.0"); req.send(params ? JSON.stringify(params) : void 0); } - + RestRequest("/_api/thememanager/GetTenantThemingOptions"); ``` diff --git a/docs/declarative-customization/view-board-formatting.md b/docs/declarative-customization/view-board-formatting.md new file mode 100644 index 000000000..16c6f2643 --- /dev/null +++ b/docs/declarative-customization/view-board-formatting.md @@ -0,0 +1,31 @@ +--- +title: Format board view to customize SharePoint +description: Customize how board views in SharePoint lists and libraries are displayed by constructing a JSON object that describes the elements and the styles to be applied to those elements. +ms.date: 06/28/2022 +ms.localizationpriority: high +--- + +# Board view customizations + +## Build custom cards + +You can use Board **`formatter`** to define a totally custom layout of field values inside a card using the same syntax used in [Column Formatting](column-formatting.md). + +## Detailed syntax reference + +### hideSelection + +Optional element. Specifies whether the ability to select cards in the view is disabled or not. `false` is the default behavior inside a board view (meaning selection is visible and enabled). `true` means that users will not be able to select list items. + +### formatter + +JSON object that defines the layout of cards. The schema of this JSON object is identical to the schema of a column format (and that of rowFormatter). For details on this schema and its capabilities, see the [Formatting syntax reference](./formatting-syntax-reference.md). + +### commandBarProps + +Groups the command bar customization options. For details on `commandBarProps`, see [Command bar customization syntax reference](./view-commandbar-formatting.md) + +## See also +- [Command bar customization syntax reference](./view-commandbar-formatting.md) +- [Advanced formatting concepts](./formatting-advanced.md) +- [Formatting syntax reference](./formatting-syntax-reference.md) diff --git a/docs/declarative-customization/view-calendar-formatting.md b/docs/declarative-customization/view-calendar-formatting.md new file mode 100644 index 000000000..a09948812 --- /dev/null +++ b/docs/declarative-customization/view-calendar-formatting.md @@ -0,0 +1,54 @@ +--- +title: Format calendar view to customize SharePoint +description: Customize calendar views in SharePoint lists and libraries +ms.date: 02/09/2023 +ms.localizationpriority: high +--- + +# Calendar view customizations + +## Detailed syntax reference + +### commandBarProps + +Groups the command bar customization options. For details on `commandBarProps`, see [Command bar customization syntax reference](./view-commandbar-formatting.md) + +## See also +- [Command bar customization syntax reference](./view-commandbar-formatting.md) + +> ![IMPORTANT] +> **Pre-requisite : List setup before creating a calendar view and applying a JSON formatting** +> +> - Before creating a new calendar view, a list should include all the required columns to be used in any JSON formatting. +> - After creating a calendar view, if more columns are required, go to the [List Settings page](https://support.microsoft.com/office/edit-list-settings-4d35793b-246e-42a3-990c-563a83795b7f) to create and add them to a calendar view. + +### Conditional view formatting based on a specific column + +The following image shows an example of conditional formatting applied to a calendar view, based on a single choice column named **PROJECT**: + +![SharePoint list calendar formatting](../images/calendar-view-formatting.png) + +> ![NOTE] +> Before creating a new calendar view, make sure the PROJECT column is already existing to apply the JSON code illustrated below. Alternatively, go the [List Settings page](https://support.microsoft.com/office/edit-list-settings-4d35793b-246e-42a3-990c-563a83795b7f) to create and add the single choice PROJECT column to a calendar view. + +In this example, **PROJECT** column has the following options: + +- Project A +- Project B +- Project C +- Project D +- Project E + +The JSON code below makes use of SharePoint Online Modern UI classes to apply colors, borders and a hover effect through the [Excel-style expression syntax](./formatting-syntax-reference.md#excel-style-expressions): + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/calendar-formatting.schema.json", + "additionalEventClass": "=if([$PROJECT] =='Project A' && @isSelected == false, 'sp-css-backgroundColor-successBackground50 sp-css-color-BlackText sp-css-borderColor-GreenText ms-bgColor-sharedGreenCyan10--hover ms-fontColor-white--hover', if([$PROJECT] =='Project A' && @isSelected == true, 'ms-bgColor-green sp-css-color-WhiteText', if([$PROJECT] =='Project B' && @isSelected == false, 'sp-css-backgroundColor-BgPeach sp-css-color-BlackText sp-css-borderColor-RedText ms-bgColor-sharedRed10--hover ms-fontColor-white--hover', if([$PROJECT] =='Project B' && @isSelected == true, 'sp-css-backgroundColor-redDark sp-css-color-WhiteText', if([$PROJECT] =='Project C' && @isSelected == false, 'sp-css-backgroundColor-BgGold sp-css-color-BlackText sp-css-borderColor-BrownText ms-bgColor-yellow--hover ms-fontColor-white--hover', if([$PROJECT] =='Project C' && @isSelected == true, 'ms-bgColor-sharedOrange10 sp-css-color-BlackText', if([$PROJECT] =='Project D' && @isSelected == false, 'ms-bgColor-communicationTint20 sp-css-color-BlackText sp-css-borderColor-BlueText ms-bgColor-sharedCyanBlue10--hover ms-fontColor-white--hover', if([$PROJECT] =='Project D' && @isSelected == true, 'sp-css-backgroundColor-BlueText sp-css-color-WhiteText', if([$PROJECT] =='Project E' && @isSelected == false, 'sp-css-backgroundColor-BgLilac sp-css-color-BlackText sp-css-borderColor-DarkPurpleText ms-bgColor-sharedBlueMagenta20--hover ms-fontColor-white--hover', if([$PROJECT] =='Project E' && @isSelected == true, 'sp-css-backgroundColor-BgPurple sp-css-color-WhiteText', if(@isSelected == false, 'sp-css-backgroundColor-neutralBackground20 sp-css-color-BlackText ms-bgColor-neutralTertiaryAlt--hover ms-fontColor-black--hover', 'sp-css-backgroundColor-neutralTertiary sp-css-color-WhiteText')))))))))))" +} +``` + +The gif image below shows the final result: + +![SharePoint list calendar formatting result](../images/calendar-view-formatting-result.gif) + diff --git a/docs/declarative-customization/view-commandbar-formatting.md b/docs/declarative-customization/view-commandbar-formatting.md new file mode 100644 index 000000000..f7f56e8e3 --- /dev/null +++ b/docs/declarative-customization/view-commandbar-formatting.md @@ -0,0 +1,248 @@ +--- +title: Command bar customization syntax reference +description: Command bar customization syntax reference +ms.date: 05/21/2025 +ms.localizationpriority: high +--- + +# Command bar customization syntax reference + +Command bar customization helps personalize a list to suit specific requirements. The JSON-based feature allows basic changes to the command bar, including modification of icon and/or text, hiding existing options, or repositioning commands. + +## commandBarProps + +Properties for Command bar customization. Valid in all types of layouts. + +## commands + +An array of JSON objects is used to specify the commands for customization. + +## key + +Mandatory property to uniquely identify a command in the Command bar. Valid keys include: + +```javascript +'new' +'newFolder' +'newWordDocument' +'newExcelWorkbook' +'newPowerPointPresentation' +'newOneNoteNotebook' +'newFormsForExcel' +'newVisioDrawing' +'upload' +'uploadFile' +'uploadFolder' +'open' +'share' +'copyLink' +'download' +'rename' +'copyTo' +'moveTo' +'delete' +'edit' +'comment' +'editNewMenu' +'powerBI' +'powerBIVisualizeList' +'automate' +'automateCreateRule' +'automateManageRules' +'powerAutomate' +'powerAutomateCreateFlow' +'powerAutomateSeeFlows' +'powerAutomateConfigureFlows' +'aiBuilderCreate' +'aiBuilderGoto' +'aiBuilder' +'alertMe' +'newLink' +'integrate' +'manageAlert' +'powerApps' +'powerAppsCreateApp' +'powerAppsSeeAllApps' +'powerAppsCustomizeForms' +'viewDocumentUnderstandingModels' +'versionHistory' +'openInImmersiveReader' +'classifyAndExtract' +'checkOut' +'checkIn' +'undoCheckOut' +'properties' +'pinItem' +'exportExcel' +'exportCSV' +'export' +'editInGridView' +'exitGridView' +'sync' +'uploadTemplate' +'addTemplate' +'openInOfficeOnline' +'openInOfficeClient' +'addShortcut' +'pinToQuickAccess' +'unpinFromQuickAccess' +'manageForms' +'favoriteCommand' +'createCopilot' +``` + +## ⚠️ Recent updates to `commandBarCustomization` Keys + +> Some keys in the commandBarCustomization schema have been updated. To ensure your custom formatter functions correctly, please update your existing JSON to reflect these new keys. +> +> | Original Key | New Key | +> |--------------|-------------| +> | `new` | `newComposite` (Document Library)| +> | `upload` | `UploadCommand` | +> | `sync` | `syncCommand` | +> | `addShortcut`| `addShortcutToOneDriveCommand` | +> | `pinToQuickAccess` | `PinToQuickAccessCommand` | +> | `pinItem` | `pinItemCommand` | +> | `properties` | `propertiesCommand` | +> | `versionHistory` | `versionHistoryCommand` (currently not working) | +> +> Additionally, the following new command keys are now available: +> > +> - `stasherContextMenuCommand` (Add shortcut) +> - `stasherCommand.myFiles` (Add shortcut --> my Files) +> - `stasherCommand.otherLocations` (Add shortcut --> Other locations) +> - `PublishCommand` +> - `complianceDetails` (right click context menu --> More --> Compliance details) +> - `more` (right click context menu --> More) +> - `previewFileCommand` (right click context menu --> Preview) +> +> Please note that the JSON schema at https://developer.microsoft.com/json-schemas/sp/v2/command-bar-formatting.schema.json has not yet been updated to reflect these new command keys. + +> [!IMPORTANT] +> Command bar customizations also affect the item context menu (right-click menu). If a command is hidden in the command bar, it will also be hidden in the context menu. + +## hide + +An optional property that specifies the condition to hide a particular command. The value of this property can either be a boolean, string or an Expression object. `false` is the default behavior (meaning the command is visible). `true` means that the command will be hidden. + +## text + +An optional property that specifies the text to be displayed as the name of the command. The value of this property can either be a string or an Expression object. If the value is not provided, then the default name of the command will be shown. + +## title + +An optional property that specifies the tooltip text to be displayed in the command. The value of this property can either be a string or an Expression object. If the value is not provided, then the default tooltip of the command will be shown. + +## iconName + +An optional property that specifies the [Fluent UI](https://developer.microsoft.com/fluentui#/) icon to be displayed in the command. The value of this property can either be a string or an Expression object. If the value is not provided, then the default icon of the command will be shown. + +## primary + +An optional property that specifies the condition to apply primary button styling to a command. The value of this property can either be a boolean, string or an Expression object. `false` is the default behavior (meaning the default style will be applied). `true` means the primary button styling will be applied to the command only if the command is placed at the 0th position in the command bar. + +The following example shows a sample Command bar formatting JSON to do the following: + +- Hide the 'New' command. +- Update the text and icon of 'Edit in grid view' command and add primary button styling to it. +- Remove the icon from 'Share' command and update the tooltip text of it. + +```JSON +{ + "commandBarProps" : { + "commands": [ + { + "key": "new", + "hide": true + }, + { + "key": "editInGridView", + "text": "Quick edit", + "iconName": "EditTable", + "primary": true + }, + { + "key": "share", + "iconName": "", + "title": "Share this List" + } + ] + } +} +``` + +## position + +An optional property that specifies the position where the command will be placed in the command bar. The value of this property can either be a number, a string, or an Expression object. If the value is not provided then the command will be placed in it's default position. This property follows zero-based indexing. + +## sectionType + +An optional property that specifies the section where the customized command will be placed in the command bar. The following strings are valid values for this property: + +- Primary +- Overflow + +The following example shows a sample Command bar formatting JSON to do the following: + +- Puts the 'New' command at the third position in the primary section of the Command bar. +- Puts the 'Share' command in the second position in the overflow menu of the Command bar. +- Puts the 'Alert me' command at the fourth position in the primary section of the Command bar. + +```JSON +{ + "commandBarProps" : { + "commands": [ + { + "key": "new", + "position": 2 + }, + { + "key": "share", + "position": 1, + "sectionType": "Overflow" + }, + { + "key": "alertMe", + "position": 3, + "sectionType": "Primary" + } + ] + } +} +``` + +## selectionModes + +An optional property that specifies the selection modes in which the command customization will be applied. If the value is not provided, then the customization will be applied in all the selection modes in which the command is available. The value of this property can be an array of strings where the following strings are allowed: + +- NoSelection +- SingleSelection +- MultiSelection + +The following example shows a sample Command bar formatting JSON to do the following: + +- Update the text of 'Share' command if the selected item has 'NumberField' column value 3 +- Update the text of 'Delete' command only if multiple items are selected. + +```JSON +{ + "commandBarProps": { + "commands": [ + { + "key": "share", + "selectionModes": [ + "SingleSelection" + ], + "text": "=if([$NumberField] == 3, 'Share item 3', 'Share')" + }, + { + "key": "delete", + "selectionModes": [ + "MultiSelection" + ], + "text": "Delete multiple items" + } + ] + } +} +``` diff --git a/docs/declarative-customization/view-formatting.md b/docs/declarative-customization/view-formatting.md index 324bcc6d1..24b6ff6fe 100644 --- a/docs/declarative-customization/view-formatting.md +++ b/docs/declarative-customization/view-formatting.md @@ -1,8 +1,8 @@ --- title: Use view formatting to customize SharePoint description: Customize how views in SharePoint lists and libraries are displayed by constructing a JSON object that describes the elements that are displayed in a list view, and the styles to be applied to those elements. -ms.date: 06/01/2021 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Use view formatting to customize SharePoint @@ -17,766 +17,21 @@ You can use view formatting to customize how items in SharePoint lists and libra ## Get started with view formatting -To open the view formatting pane, open the view dropdown and choose **Format current view**. View dropdown menu +To open the view formatting pane, open the view dropdown and choose **Format current view**. + +![View dropdown menu](../images/view-dropdown-menu.png) The pane will look like the following depending on the current layout: -List layout formatting pane Gallery layout formatting pane +![List layout formatting pane](../images/sp-viewformatting-panel-listlayout.png) ![Gallery layout formatting pane](../images/sp-viewformatting-panel-tileslayout.png) > [!NOTE] -> We have simplified the View formatting pane experience to separate out the List and Gallery layout formatting JSON. With this change, you do not need to add `tileProps` prop anymore. +> We have simplified the View formatting pane experience to separate out layout specific formatting JSON. With this change, you do not need to add layout specific props like `tileProps` anymore. -To format rows in 'List' or 'Compact List' layout, select 'List' in 'Choose layout' dropdown in the formatting pane and use the `rowFormatter` or `additionalRowClass` properties. To format cards in 'Gallery' layout, select 'Gallery' in 'Choose layout' dropdown in the formatting pane and use the `formatter` property. +To format rows in 'List' or 'Compact List' layout, select 'List' in 'Choose layout' dropdown in the formatting pane and use the `rowFormatter` or `additionalRowClass` properties. To format cards in 'Gallery' layout, select 'Gallery' in 'Choose layout' dropdown in the formatting pane and use the `formatter` property. To format cards in 'Board' view just use the `formatter` property. The easiest way to use view formatting is to start from an example and edit it to apply to your specific view. The following sections contain examples that you can copy, paste, and customize for your specific needs. There are also several samples available in the [SharePoint/sp-dev-list-formatting repository](https://github.com/SharePoint/sp-dev-list-formatting). -## List layout customizations - -### Apply conditional classes on rows - -You can use **`additionalRowClass`** to apply one or more classes to the entire list row depending on the value of one or more fields in the row. These examples leave the content and structure of list rows intact. - -For a list of recommended classes to use inside view formats, please see the [Style Guidelines section](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting#style-guidelines) in the [Column Formatting reference document](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting). - -> [!TIP] -> Using the `additionalRowClass` property to apply classes to list rows will leave the formatting of individual columns in place. This allows you to combine view formats with column formatting for some powerful visualizations. - -#### Example: Conditional classes based on a date field - -The following image shows a list layout with a class applied based on the value of a date column: - -![SharePoint list with view formatted with conditional formatting](../images/listformatting-additionalrowclass.png) - -This example applies the class `sp-field-severity--severeWarning` to a list row when the item's DueDate is before the current date/time: - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", - "additionalRowClass": "=if([$DueDate] <= @now, 'sp-field-severity--severeWarning', '')" -} -``` - -#### Example: Conditional classes based on the value in a text or choice field - -This example was adopted from a column formatting example, [Conditional formatting based on the value in a text or choice field](https://github.com/SharePoint/sp-dev-list-formatting/tree/master/column-samples/text-conditional-format), with some important differences to apply the concept to list rows. The column formatting example applies both an icon and a class to a column based on the value of `@currentField`. The `additionalRowClass` attribute in view formatting, however, only allows you to specify a class and not an icon. Additionally, since `@currentField` always resolves to the value of the `Title` field when referenced inside a view format, this sample refers to the `Status` field directly (by using the [$Field] syntax inside the additionalRowClass property to determine which class to apply to the row). - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", - "additionalRowClass": "=if([$Status] == 'Done', 'sp-field-severity--good', if([$Status] == 'In progress', 'sp-field-severity--low' ,if([$Status] == 'In review','sp-field-severity--warning', if([$Status] == 'Has issues','sp-field-severity--blocked', ''))))" -} -``` - -You can find this sample with additional details here: [Conditional formatting based on choice field](https://github.com/SharePoint/sp-dev-list-formatting/tree/master/view-samples/text-conditional-format) - -#### Example: Alternate Row Formatting based on Modulus - -This example applies `% (Mod)` to a list row with alternate coloring the rows: - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", - "additionalRowClass": "=if(@rowIndex%2==0,'ms-bgColor-themeLight','')" -} -``` - -### Build custom list rows - -You can use **`rowFormatter`** to define a totally custom layout of field values inside a row using the same syntax used in [Column Formatting](column-formatting.md). - -#### Example: Multi-line view style - -The following image shows a list with a custom multi-line view style applied: - -![SharePoint list with multi-line view customization](../images/listformatting-rowformatter.png) - -This example uses the `rowFormatter` element, which totally overrides the rendering of a list row. The `rowFormatter` in this example creates a bounding `
` box for every list row. Inside this bounding box, the `$Title` and `$Feedback` fields are displayed on separate lines. Under those fields, a `button` element is displayed that, when clicked, does the same thing as clicking the list row in an uncustomized view, which is opening the property form for the item. This `button` is displayed conditionally, when the value of the `$Assigned_x0020_To` field (assumed to be a person/group field) matches the current signed-in user: - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", - "hideSelection": true, - "hideColumnHeader": true, - "rowFormatter": { - "elmType": "div", - "attributes": { - "class": "sp-row-card" - }, - "children": [ - { - "elmType": "div", - "style": { - "text-align": "left" - }, - "children": [ - { - "elmType": "div", - "attributes": { - "class": "sp-row-title" - }, - "txtContent": "[$Title]" - }, - { - "elmType": "div", - "attributes": { - "class": "sp-row-listPadding" - }, - "txtContent": "[$Feedback]" - }, - { - "elmType": "button", - "customRowAction": { - "action": "defaultClick" - }, - "txtContent": "Give feedback", - "attributes": { - "class": "sp-row-button" - }, - "style": { - "display": { - "operator": "?", - "operands": [ - { - "operator": "==", - "operands": [ - "@me", - "[$Assigned_x0020_To.email]" - ] - }, - "", - "none" - ] - } - } - } - ] - } - ] - } -} -``` - -You can find this sample with additional details here: [Multi-line view rendering](https://github.com/SharePoint/sp-dev-list-formatting/tree/master/view-samples/multi-line-view) - -### Build custom group headers and footers - -You can use `groupProps` to format group headers with flexibility to add grouped column's data, display name and item count. You can also add group aggregates in the group headers or format it directly in the group footers. - -#### Example: Color coded group header - -In the example below we have list with group headers formatted according to column metadata. - -![Employee list grouped by City with formatted group header](../images/employee-formatted-group-header-list-layout.png) - -In this example below, the `headerFormatter` for `groupProps` is used to format the group header and the `@group` is used to access group info. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", - "groupProps": { - "headerFormatter": { - "elmType": "div", - "style": { - "flex-wrap": "wrap", - "display": "flex", - "box-sizing": "border-box", - "padding": "4px 8px 5px 8px", - "border-radius": "6px", - "align-items": "center", - "white-space": "nowrap", - "overflow": "hidden", - "margin": "1px 4px 4px 1px" - }, - "attributes": { - "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', - if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', - if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', - if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', - if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', - 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary'))))" - }, - "children": [ - { - "elmType": "img", - "attributes": { - "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', - if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', - if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', - if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', - if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', - ''))))" - }, - "style": { - "max-width": "24px", - "max-height": "24px", - "margin-top": "2px", - "border-radius": "2px" - } - }, - { - "elmType": "div", - "children": [ - { - "elmType": "span", - "style": { - "padding": "5px 5px 5px 5px", - "font-weight": "500" - }, - "txtContent": "@group.fieldData.displayValue" - } - ] - }, - { - "elmType": "div", - "children": [ - { - "elmType": "div", - "style": { - "display": "flex", - "flex-direction": "row", - "justify-content": "center" - }, - "children": [ - { - "elmType": "div", - "txtContent": "='has ' + @group.count + if(@group.count > '1', ' employees', ' employee')", - "style": { - "font-weight": "500" - } - } - ] - } - ] - } - ] - } - } -} -``` - -#### Example: Color coded group header with aggregate - -In the example below we have list with group headers formatted with group aggregates. - -![Employee list grouped by City with formatted group header with Aggregates summary](../images/employee-formatted-group-header-aggregate-list-layout.png) - -In this example the `hideFooter` for `groupProps` is set to `true` - to hide the group footer and the `@aggregates` array is used to display a summary in the group header. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", - "groupProps": { - "hideFooter": true, - "headerFormatter": { - "elmType": "div", - "style": { - "flex-wrap": "wrap", - "display": "flex", - "box-sizing": "border-box", - "padding": "4px 8px 5px 8px", - "border-radius": "6px", - "align-items": "center", - "white-space": "nowrap", - "overflow": "hidden", - "margin": "1px 4px 4px 1px" - }, - "attributes": { - "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', - if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', - if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', - if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', - if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', - 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary'))))" - }, - "children": [ - { - "elmType": "img", - "attributes": { - "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', - if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', - if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', - if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', - if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', - ''))))" - }, - "style": { - "max-width": "24px", - "max-height": "24px", - "margin-top": "2px", - "border-radius": "2px" - } - }, - { - "elmType": "div", - "children": [ - { - "elmType": "span", - "style": { - "padding": "5px 5px 5px 5px", - "font-weight": "500" - }, - "txtContent": "@group.fieldData.displayValue" - } - ] - }, - { - "elmType": "div", - "forEach": "aggregate in @aggregates", - "children": [ - { - "elmType": "div", - "style": { - "display": "=if([$aggregate.columnDisplayName] == 'Approved' && Number([$aggregate.value]) < @group.count, 'flex', 'none')", - "flex-direction": "row", - "justify-content": "center" - }, - "children": [ - { - "elmType": "div", - "txtContent": "='has approval pending for ' + Number(@group.count - Number([$aggregate.value])) + if(@group.count - Number([$aggregate.value]) > 1 , ' employees', ' employee')", - "style": { - "font-weight": "500" - } - } - ] - } - ] - } - ] - } - } -} - -``` - -#### Example: Custom group footer - -In the example below we have list with group footer formatted according to aggregate value. - -![Employee list grouped by City with formatted group footer](../images/group-footer-list-layout.png) - -In this example the `footerFormatter` for `groupProps` are used to format the group footer and the `@columnAggregate` is used to access column aggregate. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", - "groupProps": { - "hideFooter": false, - "footerFormatter": { - "elmType": "div", - "children": [ - { - "elmType": "div", - "attributes": { - "iconName": "=if(@columnAggregate.type == 'Average' && @columnAggregate.value < 10, 'SortDown', 'SortUp')" - }, - "style": { - "color": "=if(@columnAggregate.type == 'Average' && @columnAggregate.value < 10, '#d13438', '#107c10')", - "font-weight": "600", - "margin-top": "10px" - } - }, - { - "elmType": "div", - "style": { - "color": "=if(@columnAggregate.type == 'Average' && @columnAggregate.value < 10, '#d13438', '#107c10')", - "font-weight": "600", - "margin-top": "10px", - "font-family": "Segoe UI" - }, - "txtContent": "=@columnAggregate.type + ': ' + @columnAggregate.value" - } - ] - } - } -} -``` - -### Build custom list footers - -You can use `footerFormatter` to format list footer with access to column aggregates. - -#### Example: Custom list footer - -In the example below we have list with formatted footer as per the aggregate value. - -![Employee list grouped by City with formatted list footer](../images/list-footer-list-layout.png) - -In this example the `footerFormatter` is set to format the list footer and the `@columnAggregate` is used to access column aggregate. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", - "hideFooter": false, - "footerFormatter": { - "elmType": "div", - "attributes": { - "class": "ms-fontColor-themePrimary" - }, - "customCardProps": { - "formatter": { - "elmType": "div", - "children": [ - { - "elmType": "div", - "style": { - "display": "flex" - }, - "txtContent": "=@columnAggregate.type + ' of ' + @columnAggregate.columnDisplayName + ' is ' + @columnAggregate.value" - } - ], - "style": { - "height": "10px", - "width": "auto", - "cursor": "pointer", - "font-size": "14px", - "padding": "14px" - } - }, - "openOnEvent": "hover", - "directionalHint": "bottomCenter", - "isBeakVisible": true, - "beakStyle": { - "backgroundColor": "white" - } - }, - "txtContent": "View details", - "style": { - "text-decoration": "none", - "cursor": "pointer", - "font-size": "16px", - "margin-top": "10px" - } - } -} -``` - -## Gallery layout customizations - -### Build custom cards - -You can use Gallery **`formatter`** to define a totally custom layout of field values inside a card using the same syntax used in [Column Formatting](column-formatting.md). - -#### Example: Multi line custom card - -The following image shows a customized card in Gallery layout: - -![Feedback list formatted in Gallery layout](../images/feedback-tile-layout.png) - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", - "height": "250", - "width": "350", - "hideSelection": true, - "formatter": { - "elmType": "div", - "style": { - "display": "flex", - "align-items": "stretch", - "margin-bottom": "16px", - "min-width": "150px", - "flex-grow": "1", - "justify-content": "space-around", - "padding": "5px" - }, - "children": [ - { - "elmType": "div", - "style": { - "width": "95%", - "height": "92%", - "box-shadow": "0px 1.6px 3.6px 0 #00000024, 0px 0.3px 0.9px 0 #00000024", - "overflow": "hidden", - "border-radius": "2px", - "padding-left": "16px", - "padding-top": "16px" - }, - "attributes": { - "class": "ms-bgColor-neutralLighterAlt" - }, - "children": [ - { - "elmType": "div", - "style": { - "text-align": "left" - }, - "children": [ - { - "elmType": "div", - "style": { - "color":"#333333", - "font-size": "16px", - "font-weight":"600", - "margin-bottom":"5px" - }, - "txtContent": "[$Title]" - }, - { - "elmType": "div", - "style": { - "color":"#333333", - "font-size": "14px", - "line-height":"1.8" - }, - "attributes": { - "class": "sp-row-listPadding" - }, - "txtContent": "[$Feedback]" - }, - { - "elmType": "button", - "customRowAction": { - "action": "defaultClick" - }, - "txtContent": "Give feedback", - "attributes": { - "class": "sp-row-button" - }, - "style": { - "display": { - "operator": "?", - "operands": [ - { - "operator": "==", - "operands": [ - "@me", - "[$Assigned_x0020_To.email]" - ] - }, - "", - "none" - ] - } - } - } - ] - } - ] - } - ] - } - -} -``` - -### Build custom group headers - -You can use `groupProps` to format group headers with flexibility to add grouped column's data, display name and item count. You can also add group aggregates in the group headers. - -#### Example: Color coded group header - -In the example below we have gallery view with formatted group headers as per column metadata. - -![Employee gallery grouped by City with formatted group header](../images/employee-formatted-group-header-gallery-layout.png) - -> [!NOTE] -> Gallery card formatter is skipped in the below JSON for simplicity. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", - "height": 277, - "width": 254, - "hideSelection": false, - "groupProps": { - "headerFormatter": { - "elmType": "div", - "children": [ - { - "elmType": "div", - "style": { - "flex-wrap": "wrap", - "display": "flex", - "box-sizing": "border-box", - "padding": "4px 8px 5px 8px", - "border-radius": "6px", - "align-items": "center", - "white-space": "nowrap", - "overflow": "hidden", - "margin": "1px 4px 4px 1px" - }, - "attributes": { - "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', - if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', - if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', - if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', - if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', - 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary'))))" - }, - "children": [ - { - "elmType": "img", - "attributes": { - "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', - if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', - if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', - if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', - if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', - ''))))" - }, - "style": { - "max-width": "24px", - "max-height": "24px", - "margin-top": "2px", - "border-radius": "2px" - } - }, - { - "elmType": "div", - "children": [ - { - "elmType": "span", - "style": { - "padding": "5px 5px 5px 5px", - "font-weight": "500" - }, - "txtContent": { - "operator": "+", - "operands": [ - "", - "@group.fieldData.displayValue" - ] - } - } - ] - }, - { - "elmType": "div", - "children": [ - { - "elmType": "div", - "style": { - "display": "flex", - "flex-direction": "row", - "justify-content": "center" - }, - "children": [ - { - "elmType": "div", - "txtContent": "='has ' + @group.count + if(@group.count > '1', ' employees', ' employee')", - "style": { - "font-weight": "500" - } - } - ] - } - ] - } - ] - } - ] - } - } -} -``` - -#### Example: Color coded group header with aggregate - -In the example below we have list with formatted group headers and group aggregates. - -![Employee gallery grouped by City with formatted group header with Aggregates summary](../images/employee-formatted-group-header-aggregate-gallery-layout.png) - -In this example the `@aggregates` array is used to display a summary in the group header using `headerFormatter` in `groupProps`. - -> [!NOTE] -> Gallery card formatter is skipped in the below JSON for simplicity. - -```JSON -{ - "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", - "height": 277, - "width": 254, - "hideSelection": false, - "fillHorizontally": true, - "groupProps": { - "headerFormatter": { - "debugMode": true, - "elmType": "div", - "children": [ - { - "elmType": "div", - "style": { - "flex-wrap": "wrap", - "display": "flex", - "box-sizing": "border-box", - "padding": "4px 8px 5px 8px", - "border-radius": "6px", - "align-items": "center", - "white-space": "nowrap", - "overflow": "hidden", - "margin": "1px 4px 4px 1px" - }, - "attributes": { - "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', - if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', - if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', - if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', - if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', - 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary'))))" - }, - "children": [ - { - "elmType": "img", - "attributes": { - "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', - if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', - if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', - if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', - if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', - ''))))" - }, - "style": { - "max-width": "24px", - "max-height": "24px", - "margin-top": "2px", - "border-radius": "2px" - } - }, - { - "elmType": "div", - "children": [ - { - "elmType": "span", - "style": { - "padding": "5px 5px 5px 5px", - "font-weight": "500" - }, - "txtContent": "@group.fieldData.displayValue" - } - ] - }, - { - "elmType": "div", - "forEach": "aggregate in @aggregates", - "children": [ - { - "elmType": "div", - "style": { - "display": "=if([$aggregate.columnDisplayName] == 'Approved' && Number([$aggregate.value]) < @group.count, 'flex', 'none')", - "flex-direction": "row", - "justify-content": "center" - }, - "children": [ - { - "elmType": "div", - "txtContent": "='has approval pending for ' + Number(@group.count - Number([$aggregate.value])) + if(@group.count - Number([$aggregate.value]) > 1 , ' employees', ' employee')", - "style": { - "font-weight": "500" - } - } - ] - } - ] - } - ] - } - ] - } - } -} -``` - ## Creating custom JSON Creating custom view formatting JSON from scratch is simple if user understands the schema, Monaco Editor is integrated in the formatting pane with pre-filled JSON schema reference to assist in creation of view formatting, Monaco editor has validation and autocomplete to help in crafting right JSON. User can start adding JSON after the first line that defines the schema location. @@ -787,140 +42,10 @@ Creating custom view formatting JSON from scratch is simple if user understands > [!TIP] > You can start from a HTML using [**formatter helper tool**](https://pnp.github.io/List-Formatting/tools/), which can convert HTML and CSS into formatter JSON with inline styles. -## Detailed syntax reference - -### rowFormatter - -Optional element. Specifies a JSON object that describes a list row format. The schema of this JSON object is identical to the schema of a column format. For details on this schema and its capabilities, see the [Column Format detailed syntax reference](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting#detailed-syntax-reference). Only valid for 'List' and 'Compact List' layouts. - -> [!NOTE] -> Using the `rowFormatter` property will override anything specified in the `additionalRowClass` property. They are mutually exclusive. - -#### Differences in behavior between the rowFormatter element and column formatting - -Despite sharing the same schema, there are some differences in behavior between elements inside a `rowFormatter` element and those same elements in a column formatting object. - -- `@currentField` always resolves to the value of the `Title` field inside a `rowFormatter`. - -### additionalRowClass - -Optional element. Specifies a CSS class(es) that is applied to the entire row. Supports expressions. Only valid for 'List' and 'Compact List' layouts. - -`additionalRowClass` only takes effect when there is no `rowFormatter` element specified. If a `rowFormatter` is specified, then `additionalRowClass` is ignored. - -### hideSelection - -Optional element. Specifies whether the ability to select rows in the view is disabled or not. `false` is the default behavior inside a list view (meaning selection is visible and enabled). `true` means that users will not be able to select list items. Valid in 'List', 'Compact List' and 'Gallery' layouts. - -For list & compact list layout, `hideSelection` only takes effect when there's a `rowFormatter` element specified. If no `rowFormatter` is specified, then `hideSelection` is ignored. - -### hideColumnHeader - -Optional element. Specifies whether the column headers in the view are hidden or not. `false` is the default behavior inside a list view (meaning column headers will be visible). `true` means that the view will not display column headers. Only valid for 'List' and 'Compact List' layouts. - -### height - -Optional element. Defines the height of the card in pixels for 'Gallery' layout. Only valid for 'Gallery' layout. - -### width - -Optional element. Defines the width of the card in pixels for 'Gallery' layout. Can go from height/2 to 3 x height. Only valid for 'Gallery' layout. - -### formatter - -JSON object that defines the layout of cards for 'Gallery' layout. The schema of this JSON object is identical to the schema of a column format (and that of rowFormatter). For details on this schema and its capabilities, see the [Column Format detailed syntax reference](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting#detailed-syntax-reference). Only valid for 'Gallery' layout. - -### groupProps - -Groups the group related customization options. Valid in 'List', 'Compact List' and 'Gallery' layouts. - -### headerFormatter - -JSON object that defines the format for group header. The schema of this JSON object is identical to the schema of a column format. For details on this schema and its capabilities, see the [Column Format detailed syntax reference](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting#detailed-syntax-reference). Valid in 'List', 'Compact List' and 'Gallery' layouts. - -### footerFormatter - -JSON object that defines the format for group and list footer. The schema of this JSON object is identical to the schema of a column format (and that of rowFormatter). For details on this schema and its capabilities, see the [Column Format detailed syntax reference](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting#detailed-syntax-reference). Valid in 'List' and 'Compact List' layouts. - -### hideFooter - -Optional element. Specifies whether the list footers or the group footers in the view are hidden or not. `false` is the default behavior (meaning footer is visible). `true` means that view will not display footers. Valid in 'List' and 'Compact List' layouts. - -For list & compact list layout, `hideFooter` overrides the `footerFormatter`, if present. - -### Special string values - -The values for `txtContent`, styles, and attributes can be either strings or expression objects. A few special string patterns for retrieving values from group and aggregate are supported. - -#### "@group" - -Provides access to the grouped column's data, display name and item count. Valid in 'List', 'Compact List' and 'Gallery' layouts. Available only inside `groupProps`. - -The `@group` object has the following properties (with example values): - -```JSON -{ - "fieldData": "California", - "columnDisplayName": "City", - "count": 3 -} -``` - -You can also access sub properties for fields with rich data, e.g. People field, as mentioned under [Column Format special string values](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting#special-string-values). - -```JSON -{ - "fieldData": { - "id": "122", - "title": "Kalya Tucker", - "email": "kaylat@contoso.com", - "sip": "kaylat@contoso.com", - "picture": "https://contoso.sharepoint.com/kaylat_contoso_com_MThumb.jpg?t=63576928822", - "department": "Human Resources", - "jobTitle": "HR Manager" - }, - "columnDisplayName": "Author", - "count": 5 -} - -``` - -#### "@columnAggregate" - -Provides access to the aggregated column's value, display name and aggregate type. Valid in 'List' and 'Compact List' layouts. Available only inside `footerFormatter`. - -The `@columnAggregate` object has the following properties (with example values): - -```JSON -{ - "value": "3", - "columnDisplayName": "Approved", - "type": "Count" -} -``` - -#### "@aggregates" - -Provides access to array of aggregated column's value, display name and aggregate type. Valid in 'List', 'Compact List' and 'Gallery' layouts. Available only inside `groupProps`. - -The `@aggregates` object has the following properties (with example value), and can be iterated on using [Column Format forEach](https://docs.microsoft.com/sharepoint/dev/declarative-customization/column-formatting#foreach) property. - -```JSON -[ - { - "value": "3", - "columnDisplayName": "Approved", - "type": "Count" - }, - { - "value": "1.2", - "columnDisplayName": "Growth", - "type": "Average" - }, - { - "value": "0.33%", - "columnDisplayName": "Rate of change", - "type": "Variance" - } -] -``` +## See also +- [List layout customization](./view-list-formatting.md) +- [Gallery layout customization](./view-gallery-formatting.md) +- [Board view customization](./view-gallery-formatting.md) +- [Group customization syntax reference](./view-group-formatting.md) +- [Advanced formatting concepts](./formatting-advanced.md) +- [Formatting syntax reference](./formatting-syntax-reference.md) diff --git a/docs/declarative-customization/view-gallery-formatting.md b/docs/declarative-customization/view-gallery-formatting.md new file mode 100644 index 000000000..7eb60a1f5 --- /dev/null +++ b/docs/declarative-customization/view-gallery-formatting.md @@ -0,0 +1,366 @@ +--- +title: Format gallery view to customize SharePoint +description: Customize how gallery views in SharePoint lists and libraries are displayed by constructing a JSON object that describes the elements and the styles to be applied to those elements. +ms.date: 06/28/2022 +ms.localizationpriority: high +--- + +# Gallery layout customizations + +## Build custom cards + +You can use Gallery **`formatter`** to define a totally custom layout of field values inside a card using the same syntax used in [Column Formatting](column-formatting.md). + +### Example: Multi line custom card + +The following image shows a customized card in Gallery layout: + +![Feedback list formatted in Gallery layout](../images/feedback-tile-layout.png) + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", + "height": "250", + "width": "350", + "hideSelection": true, + "formatter": { + "elmType": "div", + "style": { + "display": "flex", + "align-items": "stretch", + "margin-bottom": "16px", + "min-width": "150px", + "flex-grow": "1", + "justify-content": "space-around", + "padding": "5px" + }, + "children": [ + { + "elmType": "div", + "style": { + "width": "95%", + "height": "92%", + "box-shadow": "0px 1.6px 3.6px 0 #00000024, 0px 0.3px 0.9px 0 #00000024", + "overflow": "hidden", + "border-radius": "2px", + "padding-left": "16px", + "padding-top": "16px" + }, + "attributes": { + "class": "ms-bgColor-neutralLighterAlt" + }, + "children": [ + { + "elmType": "div", + "style": { + "text-align": "left" + }, + "children": [ + { + "elmType": "div", + "style": { + "color":"#333333", + "font-size": "16px", + "font-weight":"600", + "margin-bottom":"5px" + }, + "txtContent": "[$Title]" + }, + { + "elmType": "div", + "style": { + "color":"#333333", + "font-size": "14px", + "line-height":"1.8" + }, + "attributes": { + "class": "sp-row-listPadding" + }, + "txtContent": "[$Feedback]" + }, + { + "elmType": "button", + "customRowAction": { + "action": "defaultClick" + }, + "txtContent": "Give feedback", + "attributes": { + "class": "sp-row-button" + }, + "style": { + "display": { + "operator": "?", + "operands": [ + { + "operator": "==", + "operands": [ + "@me", + "[$Assigned_x0020_To.email]" + ] + }, + "", + "none" + ] + } + } + } + ] + } + ] + } + ] + } + +} +``` + +## Build custom group headers + +You can use `groupProps` to format group headers with flexibility to add grouped column's data, display name and item count. You can also add group aggregates in the group headers. + +### Example: Color coded group header + +In the example below we have gallery view with formatted group headers as per column metadata. + +![Employee gallery grouped by City with formatted group header](../images/employee-formatted-group-header-gallery-layout.png) + +> [!NOTE] +> Gallery card formatter is skipped in the below JSON for simplicity. +> The example below also contains line breaks. These have been added to improve the readability of the code. + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", + "height": 277, + "width": 254, + "hideSelection": false, + "groupProps": { + "headerFormatter": { + "elmType": "div", + "children": [ + { + "elmType": "div", + "style": { + "flex-wrap": "wrap", + "display": "flex", + "box-sizing": "border-box", + "padding": "4px 8px 5px 8px", + "border-radius": "6px", + "align-items": "center", + "white-space": "nowrap", + "overflow": "hidden", + "margin": "1px 4px 4px 1px" + }, + "attributes": { + "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', + if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', + if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', + if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', + if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', + 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary'))))" + }, + "children": [ + { + "elmType": "img", + "attributes": { + "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', + if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', + if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', + if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', + if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', '')))))" + }, + "style": { + "max-width": "24px", + "max-height": "24px", + "margin-top": "2px", + "border-radius": "2px" + } + }, + { + "elmType": "div", + "children": [ + { + "elmType": "span", + "style": { + "padding": "5px 5px 5px 5px", + "font-weight": "500" + }, + "txtContent": { + "operator": "+", + "operands": [ + "", + "@group.fieldData.displayValue" + ] + } + } + ] + }, + { + "elmType": "div", + "children": [ + { + "elmType": "div", + "style": { + "display": "flex", + "flex-direction": "row", + "justify-content": "center" + }, + "children": [ + { + "elmType": "div", + "txtContent": "='has ' + @group.count + if(@group.count > '1', ' employees', ' employee')", + "style": { + "font-weight": "500" + } + } + ] + } + ] + } + ] + } + ] + } + } +} +``` + +### Example: Color coded group header with aggregate + +In the example below we have list with formatted group headers and group aggregates. + +![Employee gallery grouped by City with formatted group header with Aggregates summary](../images/employee-formatted-group-header-aggregate-gallery-layout.png) + +In this example the `@aggregates` array is used to display a summary in the group header using `headerFormatter` in `groupProps`. + +> [!NOTE] +> Gallery card formatter is skipped in the below JSON for simplicity. +> The example below also contains line breaks. These have been added to improve the readability of the code. + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", + "height": 277, + "width": 254, + "hideSelection": false, + "fillHorizontally": true, + "groupProps": { + "headerFormatter": { + "debugMode": true, + "elmType": "div", + "children": [ + { + "elmType": "div", + "style": { + "flex-wrap": "wrap", + "display": "flex", + "box-sizing": "border-box", + "padding": "4px 8px 5px 8px", + "border-radius": "6px", + "align-items": "center", + "white-space": "nowrap", + "overflow": "hidden", + "margin": "1px 4px 4px 1px" + }, + "attributes": { + "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', + if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', + if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', + if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', + if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary')))))" + }, + "children": [ + { + "elmType": "img", + "attributes": { + "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', + if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', + if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', + if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', + if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', '')))))" + }, + "style": { + "max-width": "24px", + "max-height": "24px", + "margin-top": "2px", + "border-radius": "2px" + } + }, + { + "elmType": "div", + "children": [ + { + "elmType": "span", + "style": { + "padding": "5px 5px 5px 5px", + "font-weight": "500" + }, + "txtContent": "@group.fieldData.displayValue" + } + ] + }, + { + "elmType": "div", + "forEach": "aggregate in @aggregates", + "children": [ + { + "elmType": "div", + "style": { + "display": "=if([$aggregate.columnDisplayName] == 'Approved' && Number([$aggregate.value]) < @group.count, 'flex', 'none')", + "flex-direction": "row", + "justify-content": "center" + }, + "children": [ + { + "elmType": "div", + "txtContent": "='has approval pending for ' + Number(@group.count - Number([$aggregate.value])) + if(@group.count - Number([$aggregate.value]) > 1 , ' employees', ' employee')", + "style": { + "font-weight": "500" + } + } + ] + } + ] + } + ] + } + ] + } + } +} +``` + +## Detailed syntax reference + +### hideSelection + +Optional element. Specifies whether the ability to select cards in the view is disabled or not. `false` is the default behavior inside a gallery view (meaning selection is visible and enabled). `true` means that users will not be able to select list items. +### fillHorizontally + +Optional element. Specifies whether the cards in the row should be stretched horizontally to fill the row. `false` is the default behavior (meaning cards in a row are stacked without resizing until they overflow). `true` means cards in the row are stretched horizontally only if necessary to fill the row. + +### height + +Optional element. Defines the height of the card in pixels. + +### width + +Optional element. Defines the width of the card in pixels. Can go from height/2 to 3 x height. + +### formatter + +JSON object that defines the layout of cards. The schema of this JSON object is identical to the schema of a column format (and that of rowFormatter). For details on this schema and its capabilities, see the [Formatting syntax reference](./formatting-syntax-reference.md). + +### groupProps + +Groups the group related customization options. For details on `groupProps`, see [Group Customization syntax reference](./view-group-formatting.md) + +### commandBarProps + +Groups the command bar customization options. For details on `commandBarProps`, see [Command bar customization syntax reference](./view-commandbar-formatting.md) + +## See also +- [Group customization syntax reference](./view-group-formatting.md) +- [Command bar customization syntax reference](./view-commandbar-formatting.md) +- [Advanced formatting concepts](./formatting-advanced.md) +- [Formatting syntax reference](./formatting-syntax-reference.md) diff --git a/docs/declarative-customization/view-group-formatting.md b/docs/declarative-customization/view-group-formatting.md new file mode 100644 index 000000000..32798d847 --- /dev/null +++ b/docs/declarative-customization/view-group-formatting.md @@ -0,0 +1,102 @@ +--- +title: Group customization syntax reference +description: Group customization syntax reference +ms.date: 06/28/2022 +ms.localizationpriority: high +--- + +# Group customization syntax reference + +## groupProps + +Groups the group related customization options. Valid in 'List', 'Compact List' and 'Gallery' layouts. + +## headerFormatter + +JSON object that defines the format for group header. The schema of this JSON object is identical to the schema of a column format. For details on this schema and its capabilities, see the [Formatting syntax reference](./formatting-syntax-reference.md). Valid in 'List', 'Compact List' and 'Gallery' layouts. + +## footerFormatter + +JSON object that defines the format for group and list footer. The schema of this JSON object is identical to the schema of a column format (and that of rowFormatter). For details on this schema and its capabilities, see the [Formatting syntax reference](./formatting-syntax-reference.md). Valid in 'List' and 'Compact List' layouts. + +## hideFooter + +Optional element. Specifies whether the list footers or the group footers in the view are hidden or not. `false` is the default behavior (meaning footer is visible). `true` means that view will not display footers. Valid in 'List' and 'Compact List' layouts. + +For list & compact list layout, `hideFooter` overrides the `footerFormatter`, if present. + +## Special string values + +The values for `txtContent`, styles, and attributes can be either strings or expression objects. A few special string patterns for retrieving values from group and aggregate are supported. + +### "@group" + +Provides access to the grouped column's data, display name and item count. Valid in 'List', 'Compact List' and 'Gallery' layouts. Available only inside `groupProps`. + +The `@group` object has the following properties (with example values): + +```JSON +{ + "fieldData": "California", + "columnDisplayName": "City", + "count": 3 +} +``` + +You can also access sub properties for fields with rich data, e.g. People field, as mentioned under [Formatting Special string values](./formatting-syntax-reference.md#special-string-values). + +```JSON +{ + "fieldData": { + "id": "122", + "title": "Kalya Tucker", + "email": "kaylat@contoso.com", + "sip": "kaylat@contoso.com", + "picture": "https://contoso.sharepoint.com/kaylat_contoso_com_MThumb.jpg?t=63576928822", + "department": "Human Resources", + "jobTitle": "HR Manager" + }, + "columnDisplayName": "Author", + "count": 5 +} +``` + +### "@columnAggregate" + +Provides access to the aggregated column's value, display name and aggregate type. Valid in 'List' and 'Compact List' layouts. Available only inside `footerFormatter`. + +The `@columnAggregate` object has the following properties (with example values): + +```JSON +{ + "value": "3", + "columnDisplayName": "Approved", + "type": "Count" +} +``` + +### "@aggregates" + +Provides access to array of aggregated column's value, display name and aggregate type. Valid in 'List', 'Compact List' and 'Gallery' layouts. Available only inside `groupProps`. + +The `@aggregates` object has the following properties (with example value), and can be iterated on using for [Formatting forEach](./formatting-syntax-reference.md#foreach) property. + +```JSON +[ + { + "value": "3", + "columnDisplayName": "Approved", + "type": "Count" + }, + { + "value": "1.2", + "columnDisplayName": "Growth", + "type": "Average" + }, + { + "value": "0.33%", + "columnDisplayName": "Rate of change", + "type": "Variance" + } +] +``` diff --git a/docs/declarative-customization/view-list-formatting.md b/docs/declarative-customization/view-list-formatting.md new file mode 100644 index 000000000..42bc48c36 --- /dev/null +++ b/docs/declarative-customization/view-list-formatting.md @@ -0,0 +1,474 @@ +--- +title: Format list view to customize SharePoint +description: Customize how list views in SharePoint lists and libraries are displayed by constructing a JSON object that describes the elements and the styles to be applied to those elements. +ms.date: 08/10/2022 +ms.localizationpriority: high +--- + +# List layout customizations + +## Apply conditional classes on rows + +You can use **`additionalRowClass`** to apply one or more classes to the entire list row depending on the value of one or more fields in the row. These examples leave the content and structure of list rows intact. + +For a list of recommended classes to use inside view formats, please see the [Style guidelines](./column-formatting.md#style-guidelines) in the [Use column formatting to customize SharePoint](column-formatting.md). + +> [!TIP] +> Using the `additionalRowClass` property to apply classes to list rows will leave the formatting of individual columns in place. This allows you to combine view formats with column formatting for some powerful visualizations. + +### Example: Conditional classes based on a date field + +The following image shows a list layout with a class applied based on the value of a date column: + +![SharePoint list with view formatted with conditional formatting](../images/listformatting-additionalrowclass.png) + +This example applies the class `sp-field-severity--severeWarning` to a list row when the item's DueDate is before the current date/time: + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", + "additionalRowClass": "=if([$DueDate] <= @now, 'sp-field-severity--severeWarning', '')" +} +``` + +### Example: Conditional classes based on the value in a text or choice field + +This example was adopted from a column formatting example, [Conditional formatting based on the value in a text or choice field](https://github.com/SharePoint/sp-dev-list-formatting/tree/master/column-samples/text-conditional-format), with some important differences to apply the concept to list rows. The column formatting example applies both an icon and a class to a column based on the value of `@currentField`. The `additionalRowClass` attribute in view formatting, however, only allows you to specify a class and not an icon. Additionally, since `@currentField` always resolves to the value of the `Title` field when referenced inside a view format, this sample refers to the `Status` field directly (by using the [$Field] syntax inside the additionalRowClass property to determine which class to apply to the row). + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", + "additionalRowClass": "=if([$Status] == 'Done', 'sp-field-severity--good', if([$Status] == 'In progress', 'sp-field-severity--low' ,if([$Status] == 'In review','sp-field-severity--warning', if([$Status] == 'Has issues','sp-field-severity--blocked', ''))))" +} +``` + +You can find this sample with additional details here: [Conditional formatting based on choice field](https://github.com/pnp/list-formatting/tree/master/view-samples/status-rowclass) + +### Example: Alternate Row Formatting based on Modulus + +This example applies `% (Mod)` to a list row with alternate coloring the rows: + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json", + "additionalRowClass": "=if(@rowIndex%2==0,'ms-bgColor-themeLight','')" +} +``` + +## Build custom list rows + +You can use **`rowFormatter`** to define a totally custom layout of field values inside a row using the same syntax used in [Column Formatting](column-formatting.md). + +### Example: Multi-line view style + +The following image shows a list with a custom multi-line view style applied: + +![SharePoint list with multi-line view customization](../images/listformatting-rowformatter.png) + +This example uses the `rowFormatter` element, which totally overrides the rendering of a list row. The `rowFormatter` in this example creates a bounding `
` box for every list row. Inside this bounding box, the `$Title` and `$Feedback` fields are displayed on separate lines. Under those fields, a `button` element is displayed that, when clicked, does the same thing as clicking the list row in an uncustomized view, which is opening the property form for the item. This `button` is displayed conditionally, when the value of the `$Assigned_x0020_To` field (assumed to be a person/group field) matches the current signed-in user: + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", + "hideSelection": true, + "hideColumnHeader": true, + "rowFormatter": { + "elmType": "div", + "attributes": { + "class": "sp-row-card" + }, + "children": [ + { + "elmType": "div", + "style": { + "text-align": "left" + }, + "children": [ + { + "elmType": "div", + "attributes": { + "class": "sp-row-title" + }, + "txtContent": "[$Title]" + }, + { + "elmType": "div", + "attributes": { + "class": "sp-row-listPadding" + }, + "txtContent": "[$Feedback]" + }, + { + "elmType": "button", + "customRowAction": { + "action": "defaultClick" + }, + "txtContent": "Give feedback", + "attributes": { + "class": "sp-row-button" + }, + "style": { + "display": { + "operator": "?", + "operands": [ + { + "operator": "==", + "operands": [ + "@me", + "[$Assigned_x0020_To.email]" + ] + }, + "", + "none" + ] + } + } + } + ] + } + ] + } +} +``` + +You can find this sample with additional details here: [Multi-line view rendering](https://github.com/SharePoint/sp-dev-list-formatting/tree/master/view-samples/multi-line-view) + +## Build custom group headers and footers + +You can use `groupProps` to format group headers with flexibility to add grouped column's data, display name and item count. You can also add group aggregates in the group headers or format it directly in the group footers. + +### Example: Color coded group header + +In the example below we have list with group headers formatted according to column metadata. + +![Employee list grouped by City with formatted group header](../images/employee-formatted-group-header-list-layout.png) + +In this example below, the `headerFormatter` for `groupProps` is used to format the group header and the `@group` is used to access group info. + +> [!NOTE] +> The JSON below contains line breaks. These have been added to improve the readability of the code. + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", + "groupProps": { + "headerFormatter": { + "elmType": "div", + "style": { + "flex-wrap": "wrap", + "display": "flex", + "box-sizing": "border-box", + "padding": "4px 8px 5px 8px", + "border-radius": "6px", + "align-items": "center", + "white-space": "nowrap", + "overflow": "hidden", + "margin": "1px 4px 4px 1px" + }, + "attributes": { + "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', + if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', + if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', + if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', + if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', + 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary')))))" + }, + "children": [ + { + "elmType": "img", + "attributes": { + "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', + if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', + if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', + if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', + if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', '')))))" + }, + "style": { + "max-width": "24px", + "max-height": "24px", + "margin-top": "2px", + "border-radius": "2px" + } + }, + { + "elmType": "div", + "children": [ + { + "elmType": "span", + "style": { + "padding": "5px 5px 5px 5px", + "font-weight": "500" + }, + "txtContent": "@group.fieldData.displayValue" + } + ] + }, + { + "elmType": "div", + "children": [ + { + "elmType": "div", + "style": { + "display": "flex", + "flex-direction": "row", + "justify-content": "center" + }, + "children": [ + { + "elmType": "div", + "txtContent": "='has ' + @group.count + if(@group.count > '1', ' employees', ' employee')", + "style": { + "font-weight": "500" + } + } + ] + } + ] + } + ] + } + } +} +``` + +### Example: Color coded group header with aggregate + +In the example below we have list with group headers formatted with group aggregates. + +![Employee list grouped by City with formatted group header with Aggregates summary](../images/employee-formatted-group-header-aggregate-list-layout.png) + +In this example the `hideFooter` for `groupProps` is set to `true` - to hide the group footer and the `@aggregates` array is used to display a summary in the group header. + +> [!NOTE] +> The JSON below contains line breaks. These have been added to improve the readability of the code. + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", + "groupProps": { + "hideFooter": true, + "headerFormatter": { + "elmType": "div", + "style": { + "flex-wrap": "wrap", + "display": "flex", + "box-sizing": "border-box", + "padding": "4px 8px 5px 8px", + "border-radius": "6px", + "align-items": "center", + "white-space": "nowrap", + "overflow": "hidden", + "margin": "1px 4px 4px 1px" + }, + "attributes": { + "class": "=if(@group.fieldData == 'California', 'sp-css-backgroundColor-blueBackground37', + if(@group.fieldData == 'Chicago', 'sp-css-backgroundColor-successBackground50', + if(@group.fieldData == 'New York', 'sp-css-backgroundColor-warningBackground50', + if(@group.fieldData == 'Seattle', 'sp-css-backgroundColor-blockingBackground50', + if(@group.fieldData == 'Washington DC', 'sp-css-backgroundColor-errorBackground50', + 'sp-field-borderAllRegular sp-field-borderAllSolid sp-css-borderColor-neutralSecondary')))))" + }, + "children": [ + { + "elmType": "img", + "attributes": { + "src": "=if(@group.fieldData == 'California', 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/1920px-Flag_of_California.svg.png', + if(@group.fieldData == 'Chicago', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Chicago%2C_Illinois.svg/1920px-Flag_of_Chicago%2C_Illinois.svg.png', + if(@group.fieldData == 'New York', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_New_York_City.svg/2560px-Flag_of_New_York_City.svg.png', + if(@group.fieldData == 'Seattle', 'https://upload.wikimedia.org/wikipedia/en/thumb/6/6d/Flag_of_Seattle.svg/1920px-Flag_of_Seattle.svg.png', + if(@group.fieldData == 'Washington DC', 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_the_District_of_Columbia.svg/2560px-Flag_of_the_District_of_Columbia.svg.png', '')))))" + }, + "style": { + "max-width": "24px", + "max-height": "24px", + "margin-top": "2px", + "border-radius": "2px" + } + }, + { + "elmType": "div", + "children": [ + { + "elmType": "span", + "style": { + "padding": "5px 5px 5px 5px", + "font-weight": "500" + }, + "txtContent": "@group.fieldData.displayValue" + } + ] + }, + { + "elmType": "div", + "forEach": "aggregate in @aggregates", + "children": [ + { + "elmType": "div", + "style": { + "display": "=if([$aggregate.columnDisplayName] == 'Approved' && Number([$aggregate.value]) < @group.count, 'flex', 'none')", + "flex-direction": "row", + "justify-content": "center" + }, + "children": [ + { + "elmType": "div", + "txtContent": "='has approval pending for ' + Number(@group.count - Number([$aggregate.value])) + if(@group.count - Number([$aggregate.value]) > 1 , ' employees', ' employee')", + "style": { + "font-weight": "500" + } + } + ] + } + ] + } + ] + } + } +} + +``` + +### Example: Custom group footer + +In the example below we have list with group footer formatted according to aggregate value. + +![Employee list grouped by City with formatted group footer](../images/group-footer-list-layout.png) + +In this example the `footerFormatter` for `groupProps` are used to format the group footer and the `@columnAggregate` is used to access column aggregate. + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", + "groupProps": { + "hideFooter": false, + "footerFormatter": { + "elmType": "div", + "children": [ + { + "elmType": "div", + "attributes": { + "iconName": "=if(@columnAggregate.type == 'Average' && @columnAggregate.value < 10, 'SortDown', 'SortUp')" + }, + "style": { + "color": "=if(@columnAggregate.type == 'Average' && @columnAggregate.value < 10, '#d13438', '#107c10')", + "font-weight": "600", + "margin-top": "10px" + } + }, + { + "elmType": "div", + "style": { + "color": "=if(@columnAggregate.type == 'Average' && @columnAggregate.value < 10, '#d13438', '#107c10')", + "font-weight": "600", + "margin-top": "10px", + "font-family": "Segoe UI" + }, + "txtContent": "=@columnAggregate.type + ': ' + @columnAggregate.value" + } + ] + } + } +} +``` + +## Build custom list footers + +You can use `footerFormatter` to format list footer with access to column aggregates. + +### Example: Custom list footer + +In the example below we have list with formatted footer as per the aggregate value. + +![Employee list grouped by City with formatted list footer](../images/list-footer-list-layout.png) + +In this example the `footerFormatter` is set to format the list footer and the `@columnAggregate` is used to access column aggregate. + +```JSON +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", + "hideFooter": false, + "footerFormatter": { + "elmType": "div", + "attributes": { + "class": "ms-fontColor-themePrimary" + }, + "customCardProps": { + "formatter": { + "elmType": "div", + "children": [ + { + "elmType": "div", + "style": { + "display": "flex" + }, + "txtContent": "=@columnAggregate.type + ' of ' + @columnAggregate.columnDisplayName + ' is ' + @columnAggregate.value" + } + ], + "style": { + "height": "10px", + "width": "auto", + "cursor": "pointer", + "font-size": "14px", + "padding": "14px" + } + }, + "openOnEvent": "hover", + "directionalHint": "bottomCenter", + "isBeakVisible": true, + "beakStyle": { + "backgroundColor": "white" + } + }, + "txtContent": "View details", + "style": { + "text-decoration": "none", + "cursor": "pointer", + "font-size": "16px", + "margin-top": "10px" + } + } +} +``` + +## Detailed syntax reference + +### rowFormatter + +Optional element. Specifies a JSON object that describes a list row format. The schema of this JSON object is identical to the schema of a column format. For details on this schema and its capabilities, see [Formatting syntax reference](./formatting-syntax-reference.md). + +> [!NOTE] +> Using the `rowFormatter` property will override anything specified in the `additionalRowClass` property. They are mutually exclusive. + +#### Differences in behavior between the rowFormatter element and column formatting + +Despite sharing the same schema, there are some differences in behavior between elements inside a `rowFormatter` element and those same elements in a column formatting object. + +- `@currentField` always resolves to the value of the `Title` field inside a `rowFormatter`. + +### additionalRowClass + +Optional element. Specifies a CSS class(es) that is applied to the entire row. Supports expressions. + +`additionalRowClass` only takes effect when there is no `rowFormatter` element specified. If a `rowFormatter` is specified, then `additionalRowClass` is ignored. + +### hideSelection + +Optional element. Specifies whether the ability to select rows in the view is disabled or not. `false` is the default behavior inside a list view (meaning selection is visible and enabled). `true` means that users will not be able to select list items. + +### hideColumnHeader + +Optional element. Specifies whether the column headers in the view are hidden or not. `false` is the default behavior inside a list view (meaning column headers will be visible). `true` means that the view will not display column headers. + +### groupProps + +Groups the group related customization options. For details on `groupProps`, see [Group Customization syntax reference](./view-group-formatting.md) + +### commandBarProps + +Groups the command bar customization options. For details on `commandBarProps`, see [Command bar customization syntax reference](./view-commandbar-formatting.md) + +## See also +- [Group customization syntax reference](./view-group-formatting.md) +- [Command bar customization syntax reference](./view-commandbar-formatting.md) +- [Advanced formatting concepts](./formatting-advanced.md) +- [Formatting syntax reference](./formatting-syntax-reference.md) diff --git a/docs/design/accessibility.md b/docs/design/accessibility.md index 217609c09..393091803 100644 --- a/docs/design/accessibility.md +++ b/docs/design/accessibility.md @@ -1,10 +1,9 @@ --- title: Accessibility in SharePoint web part design description: Guidelines for adding accessibility to your web part. -ms.date: 03/22/2018 -localization_priority: Normal +ms.date: 06/13/2022 +ms.localizationpriority: medium --- - # Accessibility in SharePoint web part design Developing an experience that meets all users' unique visual, hearing, dexterity, cognitive, and speech needs is an important component of SharePoint web part design. Accessible design applies not only to people with disabilities, but also to potential situational impairments. Accessible design is good design. @@ -15,7 +14,7 @@ All Microsoft products must meet the requirements listed in the [Microsoft Acces ## Making web parts accessible -The SharePoint Framework provides a structure to help make all web parts accessible. The web part container provides keyboard navigation defaults for the web part toolbar to edit, move, and delete the web part, a method to select the web part, and a keyboard short cut (Ctrl+P) to open the property pane. However, you still need to specify additional keyboard and screen reader navigation for the other aspects of the UI in the web part and in the property pane. +The SharePoint Framework provides a structure to help make all web parts accessible. The web part container provides keyboard navigation defaults for the web part toolbar to edit, move, and delete the web part, a method to select the web part, and a keyboard short cut (Ctrl+P) to open the property pane. However, you still need to specify additional keyboard and screen reader navigation for the other aspects of the UI in the web part and in the property pane. In addition, many [Office UI Fabric components](https://developer.microsoft.com/fabric#/components) have built-in support for accessibility options, to make it quick to configure keyboard and screen reader navigation when you use the components in a web part. @@ -27,9 +26,9 @@ The following image shows keyboard navigation on a web part. Test your web part first with [Narrator](https://support.microsoft.com/help/22798/windows-10-narrator-get-started) and Microsoft Edge, and then verify the accessibility experience with [JAWS](http://www.freedomscientific.com/Products/Blindness/JAWS). -Narrator and Microsoft Edge are standards compliant. When you test with that combination, you are more likely to find issues, and you can validate that your site meets accessibility standards. +Narrator and Microsoft Edge are standards compliant. When you test with that combination, you are more likely to find issues, and you can validate that your site meets accessibility standards. -JAWS is the market leader in screen readers. JAWS includes features that can improve the accessibility of some websites that aren't as accessible in other screen readers. Therefore, testing in JAWS might not ensure that your site meets all accessibility requirements. +JAWS is the market leader in screen readers. JAWS includes features that can improve the accessibility of some websites that aren't as accessible in other screen readers. Therefore, testing in JAWS might not ensure that your site meets all accessibility requirements.   You might also want to test for whatever combination of browser and screen reader has the greatest market share for your website. @@ -45,13 +44,6 @@ Each control is a tab stop. Within a control, the following rules apply: - For modal surfaces, the last tab stop should be the commit actions. - For lists, the first tab stop should be the first item in the list, the next should be the commands, and then the navigation, settings, and so on. - ![Image that shows the tab stops on a SharePoint page](../images/accessibility-illustration-04.png) ### Navigation within a control @@ -92,7 +84,7 @@ Users who have vision impairments rely on screen readers to navigate the site UI ## Alt text and transcripts -Use alt text to provide descriptions of images that can be consumed by screen readers. This is useful for vision-impaired users who cannot consume information visually. Make sure that your alt text is descriptive, keeping in mind that some readers are relying on a screen reader to access the information conveyed in the image. +Use alt text to provide descriptions of images that can be consumed by screen readers. This is useful for users who have visual impairments who cannot consume information visually. Make sure that your alt text is descriptive, keeping in mind that some readers are relying on a screen reader to access the information conveyed in the image. Don't rely only on color to convey meaning; rely on both color and shape. @@ -100,9 +92,9 @@ To be fully compliant with accessibility standards, include alt text and a compl ## Minimum readable contrast -A minimum level of contrast is essential to help users with vision impairments consume the content on the page. It is also important to aid readability in low light and glare situations. +A minimum level of contrast is essential to help users who have visual impairments consume the content on the page. It is also important to aid readability in low light and glare situations. -The following image shows theme colors on the left and neutral colors on the right. +The following image shows theme colors on the left and neutral colors on the right. ![Neutral and Theme colors for minimum readable contrast](../images/themes-colors-blue-neutral-theme-2.png) @@ -162,19 +154,14 @@ The following image shows theme colors on the left and neutral colors on the rig
- ## High contrast Use high contrast colors as a guide for color choices for components and states on the web. Windows computers only have the ability to detect whether a PC is running high contrast or high contrast white. For this reason, use the default high contrast black setting for any high contrast, non-white theme. ![High contrast black and high contrast white settings](../images/accessibility-illustration-14.png) - ## See also - [SharePoint themes and colors](themes-colors.md) - [Design a web part](design-a-web-part.md) - [Designing great SharePoint experiences](design-guidance-overview.md) - - - diff --git a/docs/design/authoring-pages.md b/docs/design/authoring-pages.md index 6264e6fe5..49002ad83 100644 --- a/docs/design/authoring-pages.md +++ b/docs/design/authoring-pages.md @@ -1,62 +1,48 @@ --- title: Authoring pages in a SharePoint site description: Author pages using Edit mode, Published mode, and consider the mobile view. -ms.date: 1/23/2018 -localization_priority: Priority +ms.date: 03/08/2023 +ms.localizationpriority: high --- # Authoring pages in a SharePoint site -Authoring pages in SharePoint is a simple process, but it does require some familiarity with the SharePoint environment, as well as an understanding of what and who you are designing the page for. A few basic principles, such as remembering to "Start simple" and "Build on what's working," are valuable things to consider as you start authoring. It's also a good idea to consistently remind yourself of your audience and the goals that you are trying to help them achieve. +Authoring pages in SharePoint is a simple process, but it does require some familiarity with the SharePoint environment, and an understanding of what and who you are designing the page for. A few basic principles, such as remembering to "Start simple" and "Build on what's working," are valuable things to consider as you start authoring. It's also a good idea to consistently remind yourself of your audience and the goals that you're trying to help them achieve. - - -The SharePoint page authoring experience has two modes: +The SharePoint page authoring experience has two modes: - **Edit**. Allows page authors to add and configure web parts to add content to a page. -- **Published**. Allows your team or audience to view content and interact with web parts. +- **Published**. Allows your team or audience to view content and interact with web parts. ## Edit mode -When creating a new page, users have access to the authoring UI to add content to and customize the page content. - -Edit control - -
+When creating a new page, users have access to the authoring UI to add content to and customize the page content. -Edit control with cursor showing highlight +![Edit control](../images/design-authoring-edit-01.png) -
+![Edit control with cursor showing highlight](../images/design-authoring-edit-02.png) ### Add hint and Toolbox The add hint is a horizontal line with a plus icon that is visible when a web part is selected and on hover to indicate where page authors can add new web parts to their page. The Toolbox opens when a user selects the plus icon. The Toolbox contains all the web parts that can be added to a page. -Hint and toolbox showing tools - -
+![Hint and toolbox showing tools](../images/design-authoring-add-hint.png) ### Toolbar -A vertical toolbar and bounding box is part of the framework for every web part and is provided by the page. Each web part has an edit and delete action in the toolbar. - -Expanded toolbar +A vertical toolbar and bounding box is part of the framework for every web part and is provided by the page. Each web part has an edit and delete action in the toolbar. -
+![Expanded toolbar](../images/design-authoring-toolbar.png) ### Active and hover states On hover/active, the hint bars are primary blue or the primary theme color for the site. -Hover and active state - -
+![Hover and active state](../images/design-authoring-active-hover-01.png) The bounding box for a web part is gray by default, but picks up the primary blue or primary theme color for the site on hover or when the web part is selected. -Bounding box on and off - -
+![Bounding box on and off](../images/design-authoring-active-hover-02.png) ### Contextual edits @@ -64,35 +50,27 @@ Design a WYSIWYG experience for web parts so that users can fill in information ![Contextual edits form element](../images/design-authoring-contextual-edits.png) -
- ### Item-level edits UI can change within the web part; for example, text can become a text field, or you can display UI to reorder items or to check off tasks in a web part. You can enable interactive functionality for web parts in edit mode, in read mode, or in both, depending on your design intent. ![Item level editing with selected state](../images/design-authoring-item-level.png) -
- ### Property panes -Property panes are invoked via the **Edit** icon on the toolbar. Property panes should primarily contain configuration settings that enable or disable features that either show on the page, or make a call to a service to display content. +Property panes are invoked via the **Edit** icon on the toolbar. Property panes should primarily contain configuration settings that enable or disable features that either show on the page, or make a call to a service to display content. ![Expanded pane](../images/design-authoring-panes.png) -
- ## Published mode After the page is published, all editing UI is disabled for the viewer or reader of the page. To continue editing the page, the user selects the **Edit** button on the top right corner of the command bar. ![Publish button highlighted](../images/design-authoring-published.png) -
- ## Mobile view -All SharePoint pages are [responsive](grid-and-responsive-design.md) to allow the content of the page to be viewed on mobile devices. While designing a web part, it is important to understand how the new SharePoint site pages render across different devices. +All SharePoint pages are [responsive](grid-and-responsive-design.md) to allow the content of the page to be viewed on mobile devices. While designing a web part, it's important to understand how the new SharePoint site pages render across different devices. ![Mobile view of site](../images/design-authoring-mobile.png) diff --git a/docs/design/design-a-web-part.md b/docs/design/design-a-web-part.md index a7671229f..72c3a4bc6 100644 --- a/docs/design/design-a-web-part.md +++ b/docs/design/design-a-web-part.md @@ -1,8 +1,8 @@ --- title: Designing a SharePoint web part description: Use three types of property panes to design and develop web parts that fit your business or customer needs. -ms.date: 01/23/2018 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Designing a SharePoint web part @@ -57,7 +57,7 @@ Use accordion panes when you need to apply categorization for a complex web part ### Steps pane -Use a steps pane to group properties in multiple steps or pages when you need the web part to be configured in a linear order, or when choices in the first step affect the options that display in the second or third step. +Use a steps pane to group properties in multiple steps or pages when you need the web part to be configured in a linear order, or when choices in the first step affect the options that display in the second or third step. **Step 1 of the steps pane** @@ -67,7 +67,7 @@ In step 1, the back button is disabled and the next button is enabled.
-**Step 2 of the steps pane** +**Step 2 of the steps pane** In step 2, the back and next buttons are enabled. @@ -75,7 +75,7 @@ In step 2, the back and next buttons are enabled.
-**Step 3 of the steps pane** +**Step 3 of the steps pane** In step 3, the next button is disabled and the back button is enabled. @@ -85,5 +85,3 @@ In step 3, the next button is disabled and the back button is enabled. ## See also - [Designing great SharePoint experiences](design-guidance-overview.md) - - diff --git a/docs/design/design-guidance-overview.md b/docs/design/design-guidance-overview.md index 9ff8c935b..1566fe91e 100644 --- a/docs/design/design-guidance-overview.md +++ b/docs/design/design-guidance-overview.md @@ -1,8 +1,8 @@ --- title: Designing great SharePoint experiences description: Create compelling SharePoint experiences and effectively communicate your brand and message to your audience. -ms.date: 1/23/2018 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Designing great SharePoint experiences @@ -14,7 +14,7 @@ SharePoint is a platform that delivers content to more than 200,000 organization ![SharePoint communication site on multiple devices](../images/design-guidance-overview.png) -## SharePoint design principles +## SharePoint design principles SharePoint builds on the design principles that shape the Office and Microsoft product families. These principles help the design stay true to our product goals and user needs. @@ -38,7 +38,45 @@ We search for what’s possible beyond today’s way of getting things done. We Accessibility is developing an equal experience for all users that enables individuals to adjust their user experience to meet their unique visual, hearing, dexterity, cognitive, and speech needs. SharePoint believes strongly in providing accessible experiences for everyone, everywhere, and in optimizing our experiences to reflect the needs of all of our customers. - + + +## SharePoint Web UI Kit in Figma + +![Screenshot 2024-10-02 134843](https://github.com/user-attachments/assets/c6f4eb87-abf2-48ca-b5f2-f35ee98883c1) + +The SharePoint Web UI Kit empowers you to design communication and team sites for desktop, tablet and mobile in Figma. ​This kit delivers a set of web parts, style options, templates, and detailed guidance so you can quickly design engaging sites and pages in Figma. Figma is a subscription-based application that is the industry standard tool for web design, and provides an alternative to designing sites and pages outside of SharePoint. + +[Access the kit in Figma Community](https://aka.ms/SPWebUIkit) + +[Watch a live demo on YouTube with the product team](https://youtu.be/2UPchEYhuxI?si=x8ZWEBe3YZQL3Dkp) + +### Design without organizational limitations + +This UI kit provides SharePoint users with another tool in their toolbox. While building a page in SharePoint is easy, we wanted to provide the ability to mockup sites and pages. It allows you to explore different design options for your site without the limitation of admin privileges and tenant restrictions, and doesn’t expose organization data. + +Figma mockups provide a quick snapshot of SharePoint updates which business stakeholders can use to plan and make decisions. They can provide appropriate requirements and use this UI kit in collaboration with their design team to iterate in the life cycle of your organization's intranet. + +### Share designs with ease + +This UI kit provides you with page layouts and a selection of web parts to allow you to mockup and share new ideas across organizations and companies. Figma gives you the flexibility of reviewing and sharing your designs without having to spend time and resources creating it in SharePoint. Figma also allows you to download your designs into easy-to-use formats that can be used in documentation and presentations. Learn more at https://www.figma.com/ + +Note that Figma does not build the pages in SharePoint, so once you finalize a design in Figma, you will need to build it in SharePoint. You should evaluate if Figma is the right solution for mocking up sites and pages for SharePoint. + +### Community feedback + +Please tell us what’s missing, what doesn’t work for you, and where your biggest challenges are by leaving a comment on the [Figma SharePoint Web UI kit page](https://aka.ms/SPWebUIkit). + +### Past Tech Community blog posts for each SharePoint Web UI Kit release + +v3.0: [Figma Variables and new components available (v3.0.0) in the SharePoint Web UI Kit](https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/figma-variables-and-new-components-available-v3-0-0-in-the/ba-p/4180339) + +v2.2: [SharePoint Web UI Kit - New Figma web part components available (v2.2) and feedback requested](https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/sharepoint-web-ui-kit-new-figma-web-part-components-available-v2/ba-p/4031084) + +v2.1: [New web parts available in the SharePoint Web UI kit!](https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/new-web-parts-available-in-the-sharepoint-web-ui-kit/ba-p/3956251) + +v2.0: [Updated content for the SharePoint Web UI kit!](https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/updated-content-for-the-sharepoint-web-ui-kit/ba-p/3905250) + +v1.0: [Introducing a new SharePoint Web UI kit!](https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/introducing-a-new-sharepoint-web-ui-kit/ba-p/3870293) ## See also diff --git a/docs/design/designing-a-web-part-icon.md b/docs/design/designing-a-web-part-icon.md index 9b784b9ce..fd9b128ae 100644 --- a/docs/design/designing-a-web-part-icon.md +++ b/docs/design/designing-a-web-part-icon.md @@ -1,8 +1,8 @@ --- title: Designing a web part icon description: Learn how to design a web part icon that will look great in SharePoint. -ms.date: 08/24/2018 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # Designing a SharePoint web part icon @@ -13,13 +13,13 @@ Web part icons are designed to be simple, representative, and symbolic. Every ic ## Grid keyline shapes -Web part icons are displayed at 32x32 px but are designed at twice the size, or 64x64 px. Create icons at 100% to ensure that pixels are accurate. +Web part icons are displayed at 32x32 px but are designed at twice the size, or 64x64 px. Create icons at 100% to ensure that pixels are accurate. ![Web part icon grid](../images/02_Icons_sizes.png) ## Layout -Design icons within the 64x64 px container area. This ensures that the icon renders correctly. +Design icons within the 64x64 px container area. This ensures that the icon renders correctly. ![Grid example for web part icons at 64px](../images/03_Icons_Layout.png) @@ -32,7 +32,7 @@ Not all icons or logos are designed in a perfect square. Use this guide of basic ## Pixel clarity -Try to avoid any icon distortion by snapping your edges to the X and Y coordinates. Use whole numbers when possible. +Try to avoid any icon distortion by snapping your edges to the X and Y coordinates. Use whole numbers when possible. ![Example of an icon that is not aligned to the pixel and one that is](../images/05_Icons_pixel_clarity.png) @@ -49,4 +49,3 @@ Web part icons can contain one color or be full color. Most icons work best when Export icons as SVGs at 64x64 px with transparent backgrounds. You can find the icon grid in the [SharePoint Design toolkit](https://developer.microsoft.com/fabric#/resources). - diff --git a/docs/design/empty-states.md b/docs/design/empty-states.md index 25217f409..dc78df4c2 100644 --- a/docs/design/empty-states.md +++ b/docs/design/empty-states.md @@ -1,13 +1,13 @@ --- title: Empty states for web parts description: The empty state is a visual representation of a web part, pre-configured to a content source like a list or with placeholder content, such as images and text. -ms.date: 4/16/2018 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # Empty state of a web part -The empty state is a visual representation of a web part, pre-configured to a content source like a list or with placeholder content, such as images and text. +The empty state is a visual representation of a web part, pre-configured to a content source like a list or with placeholder content, such as images and text. The following web parts have a content source set by default but no content to show for a newly created Communication site (that is, they feature an empty state): @@ -18,7 +18,7 @@ The following web parts have a content source set by default but no content to s - Hero - Image gallery -Empty states are designed to convey the purpose, structure, and layout options of web parts before the web part is configured or content is added. The empty state is also a perfect way to illustrate the vertical rhythm and layout of a page that starts from a template. Empty states behave similarly to fully configured web parts, and reflow to accommodate available space. They should support author-configured web part layouts. +Empty states are designed to convey the purpose, structure, and layout options of web parts before the web part is configured or content is added. The empty state is also a perfect way to illustrate the vertical rhythm and layout of a page that starts from a template. Empty states behave similarly to fully configured web parts, and reflow to accommodate available space. They should support author-configured web part layouts. ![Image that shows sample web part empty states](../images/empty_state_template_01.png) @@ -26,9 +26,9 @@ Empty states are different from placeholders in that the latter are meant to be ## Empty state and editing rights -Web parts with empty states can change interaction options and display text depending on the permission level and mode of the page. +Web parts with empty states can change interaction options and display text depending on the permission level and mode of the page. -In the following example (left to right), a person with editing rights sees an empty state of the Events web part in Edit and Read modes. The last image shows a simplified empty state view for page readers that have no editing rights, with a message appropriate to their permission level. +In the following example (left to right), a person with editing rights sees an empty state of the Events web part in Edit and Read modes. The last image shows a simplified empty state view for page readers that have no editing rights, with a message appropriate to their permission level. ![Author amd reader empty states](../images/empty_state_events_02.png) @@ -38,7 +38,7 @@ The following are layout options for the Events web part in an empty state. ## Interactions with an empty state -Empty states are designed primarily for people with editing rights and change interaction options based on the current page mode. Authors can manually add content to web parts in the Read mode, such as adding a new event or new news post. +Empty states are designed primarily for people with editing rights and change interaction options based on the current page mode. Authors can manually add content to web parts in the Read mode, such as adding a new event or new news post. The following example shows an empty state with multiple items stacked vertically, where the first item acts as a call to action (CTA) to learn more or create an event. diff --git a/docs/design/grid-and-responsive-design.md b/docs/design/grid-and-responsive-design.md index 9aba73a1d..7e12fd385 100644 --- a/docs/design/grid-and-responsive-design.md +++ b/docs/design/grid-and-responsive-design.md @@ -1,85 +1,72 @@ --- title: SharePoint grid and responsive design -description: The underlying page grid system and the breakpoints, or key screen sizes where the layout of the pages will change. -ms.date: 01/23/2018 -localization_priority: Priority +description: The underlying page grid system and the breakpoints, or key screen sizes where the layout of the pages will change. +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint grid and responsive design - -Responsive experiences seamlessly scale across devices to better display your content on a range of different screen sizes. Responsive design also eliminates the need to build multiple versions of your site pages to support different devices. -The design guidance for responsive pages in the SharePoint authoring environment incorporates a responsive grid system that is based on [Office UI Fabric](https://developer.microsoft.com/fabric). This article describes the underlying page grid system and the breakpoints, or key screen sizes where the layout of the pages will change. +Responsive experiences seamlessly scale across devices to better display your content on a range of different screen sizes. Responsive design also eliminates the need to build multiple versions of your site pages to support different devices. +The design guidance for responsive pages in the SharePoint authoring environment incorporates a responsive grid system that is based on [Office UI Fabric](https://developer.microsoft.com/fabric). This article describes the underlying page grid system and the breakpoints, or key screen sizes where the layout of the pages will change. ![SharePoint page on multiple devices](../images/design-grid-responsive-overview.png) +## Page type grids - -## Page type grids - -Each page type in the SharePoint authoring experience can have its own rules for how it applies the Fabric responsive grid. This is to ensure that each page looks great, regardless of what device it's designed for, and that the experience is optimized for that environment. The basic grid in the SharePoint desktop experiences is a 12-column structure. The number of columns and gutter width adjust based on the screen width. +Each page type in the SharePoint authoring experience can have its own rules for how it applies the Fabric responsive grid. This is to ensure that each page looks great, regardless of what device it's designed for, and that the experience is optimized for that environment. The basic grid in the SharePoint desktop experiences is a 12-column structure. The number of columns and gutter width adjust based on the screen width. The following sections show the basic grid structure applied across different types of SharePoint pages, to help you better understand how the grid adjusts to support the experience and device needs. - ![Twelve column grid diagram](../images/design-grid_diagram.png) -
- ### Team sites The content area for a team site is locked to the left. Team sites have a left navigation; therefore, the space that web parts occupy on the grid and the reflow behavior respects the space given to the navigation. The max width of the content area of a Team site is 1204 px and the minimum size is 320 px for mobile support. ![Team site](../images/design-grid-team-site.png) -
- The following examples show how the grid adjusts between key breakpoints on a team site. #### Small 320 x 568 + The small size has a single centered column area, with 20 px margins left and right. ![Team site small grid](../images/design-grid-Team-site-S-Canvas-no-column.png) -
- #### Medium 480 x 854 + The medium size has 12 columns, with 16 px gutters. ![Team site medium grid](../images/design-grid-Team-site-M-Canvas-16px-gutters.png) -
- #### Large 640 x 1024 + The large size has 12 columns, with 24 px gutters. ![Team site large grid](../images/design-grid-Team-site-L-Canvas-24px-gutters.png) -
- #### XL 1024 x 768 + The XL size has 12 columns, with 24 px gutters. ![Team site XL grid](../images/design-grid-Team-site-XL-Canvas-24px-gutters.png) -
- #### XXL 1366 x 768 + The XXL size has 12 columns, with 32 px gutters. ![Team site XXL grid](../images/design-grid-Team-site-XXL-Canvas-32px-gutters.png) -
- #### XXXL 1920 x 1080 + The XXXL size has 12 columns, with 32 px gutters. ![Team site XXXL grid](../images/design-grid-Team-site-XXXL-Canvas-32px-gutters-maxwidth-1204.png) -
- #### Team site multicolumn pages and web parts + Web parts scale horizontally depending on the page layout. The following example shows how the size of a web part adjusts to accommodate the left navigation. ![Team site multicolumn page with web parts](../images/design-grid-Team-site-web-parts.png) @@ -91,75 +78,64 @@ Communication sites have a top navigation and a centered content area. The maxim ![Communication site](../images/design-grid-communication_site.png) -
- The following examples show how the grid adjusts between key breakpoints on a communication site. #### Small 320 x 568 + The small size has a single centered column area, with 20 px margins left and right. ![Communication site small grid](../images/design-grid-Communication-site-S-Canvas-no-column.png) -
- #### Medium 480 x 854 + The medium size has 12 columns, with 16 px gutters. ![Communication site medium grid](../images/design-grid-Communication-site-M-Canvas-16px-gutters.png) -
- #### Large 640 x 1024 + The large size has 12 columns, with 24 px gutters. ![Communication site large grid](../images/design-grid-Communication-site-L-Canvas-24px-gutters.png) -
- #### XL 1024 x 768 + The XL size has 12 columns, with 24 px gutters. ![Communication site XL grid](../images/design-grid-Communication-site-XL-Canvas-24px-gutters.png) -
- #### XXL 1366 x 768 + The XXL size has 12 columns, with 32 px gutters. ![Communication site XXL grid](../images/design-grid-Communication-site-XXL-Canvas-32px-gutters-maxwidth-1204.png) -
- #### XXXL 1920 x 1080 + The XXXL size has 12 columns, with 32 px gutters. ![Communication site XXXL grid](../images/design-grid-Communication-site-XXXL-Canvas-32px-gutters-maxwidth-1204.png) -
- #### Communication site multicolumn pages and web parts + Web parts scale horizontally depending on the page layout. This example shows a communication site and web parts for single to three column layouts. ![Communication site multi-column with web parts](../images/design-grid-Communciation-site-web-parts.png) +## Breakpoints - -## Breakpoints - -To create a smooth flowing experience between screen sizes, the SharePoint UI should adapt layouts for the following breakpoint widths: +To create a smooth flowing experience between screen sizes, the SharePoint UI should adapt layouts for the following breakpoint widths: - 320 px - 1024 px - 1366 px - 1920 px - + Within these breakpoints, you should take into consideration how your content shifts when the viewport size becomes optimized for the nearest breakpoint. Note that this diagram is for illustration only and is not pixel accurate. ![SharePoint diagram showing breakpoints](../images/design-grid-breakpoints.png) -
- The responsive grid for both team sites and communication sites adjusts when going from large breakpoints to mobile breakpoints. This optimizes the site for the device and screen size. The following table describes the grid sizes at various breakpoints based on popular device sizes. @@ -176,11 +152,7 @@ The responsive grid for both team sites and communication sites adjusts when goi | 1600 | Web 1600x900 | XX-Large | 12 | 32 | 3 | | 1920 | Web 1920x1080 | XXX-Large | 12 | 32 | 3 | -
- ## See also - [Design toolkit and assets](https://developer.microsoft.com/fabric#/resources) - [Designing great SharePoint experiences](design-guidance-overview.md) - - diff --git a/docs/design/key-web-part-examples.md b/docs/design/key-web-part-examples.md index ab599f1db..e1ba4a44b 100644 --- a/docs/design/key-web-part-examples.md +++ b/docs/design/key-web-part-examples.md @@ -1,15 +1,15 @@ --- title: Key web part examples -description: A visual overview of Communication site and Team site templates. -ms.date: 5/08/2018 -localization_priority: Priority +description: A visual overview of Communication site and Team site templates. +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Key web part examples -Web parts are the building blocks of your page. +Web parts are the building blocks of your page. -This is a visual overview of Communication site and Team site templates, highlighting how web parts work together to create a coherent overall design. Use these pages as reference when designing a SharePoint web part. +This is a visual overview of Communication site and Team site templates, highlighting how web parts work together to create a coherent overall design. Use these pages as reference when designing a SharePoint web part. It is important to consider how the web part will look and function when sitting next to other web parts on a page. Follow the patterns in this documentation and on the [Office UI Fabric site](https://developer.microsoft.com/fabric) to ensure consistency in layout and grid alignment, font size and hierarchy, commanding, empty states, and more. @@ -19,22 +19,20 @@ It is important to consider how the web part will look and function when sitting The Topic design is used when you have a lot of information to share, such as news, events, reports, and other content. It is built from the Hero, News, Events, Highlighted content, Quick links, and People web parts. -![Topic site homepage](../images/sites_topic.png) +![Topic site homepage](../images/sites_topic.png) ### Showcase design The Showcase design is used to feature a product, team, or event. It leverages the Hero and Image gallery web parts to show rich visual content. -![Showcase site homepage](../images/sites_showcase.png) +![Showcase site homepage](../images/sites_showcase.png) ## Team sites The Team site design is the default layout for any new team. It features the News, Quick links, Highlighted content, and Document library web parts. -![Team site homepage](../images/sites_teamsite.png) +![Team site homepage](../images/sites_teamsite.png) These example site and web part designs have been added to the SharePoint toolkit and can be used as reference when designing web parts. For more information, see the [SharePoint toolkit](https://developer.microsoft.com/fabric#/resources). - - diff --git a/docs/design/layout-patterns.md b/docs/design/layout-patterns.md index 699db6cc8..0d8891ca4 100644 --- a/docs/design/layout-patterns.md +++ b/docs/design/layout-patterns.md @@ -1,13 +1,13 @@ --- title: Layout patterns description: Find common SharePoint web part layout types and responsive patterns. -ms.date: 08/24/2018 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint web part layouts -SharePoint uses a number of different layout types for web parts. The most common are grid, list, filmstrip, carousel, and compact. Each one of these five layouts serves a different purpose, depending on the layout, breakpoints, and content density of a page. +SharePoint uses a number of different layout types for web parts. The most common are grid, list, filmstrip, carousel, and compact. Each one of these five layouts serves a different purpose, depending on the layout, breakpoints, and content density of a page. When selecting a layout that works best for your web part, consider the type of content you are displaying. Is it highly visual or rich in text and data? Determine how much space is needed on the page for enough content to be displayed. Consider shortening long descriptions to optimize for displaying more items to the user. Remember that you can use the [property pane](reactive-and-nonreactive-web-parts.md) to let authors have control over how much content is displayed. diff --git a/docs/design/placeholders-and-fallbacks.md b/docs/design/placeholders-and-fallbacks.md index 41140447f..5354450c2 100644 --- a/docs/design/placeholders-and-fallbacks.md +++ b/docs/design/placeholders-and-fallbacks.md @@ -1,14 +1,14 @@ --- title: Placeholders and fallbacks in SharePoint web parts description: Add placeholders to SharePoint web parts as a fallback if an issue occurs loading content or data. -ms.date: 01/23/2018 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # Placeholders and fallbacks in SharePoint web parts -You can add placeholders to SharePoint web parts that can also be used as a fallback if an issue occurs loading content or data for a web part. The web part name and description are automatically added from the metadata submitted with the web part. +You can add placeholders to SharePoint web parts that can also be used as a fallback if an issue occurs loading content or data for a web part. The web part name and description are automatically added from the metadata submitted with the web part. You can add a button that users can select to return to a state where they can configure the web part. diff --git a/docs/design/reactive-and-nonreactive-web-parts.md b/docs/design/reactive-and-nonreactive-web-parts.md index 87a981c83..38935ba67 100644 --- a/docs/design/reactive-and-nonreactive-web-parts.md +++ b/docs/design/reactive-and-nonreactive-web-parts.md @@ -1,47 +1,41 @@ --- title: Reactive and nonreactive SharePoint web parts description: Reactive web parts are client-side only; nonreactive web parts have elements that require a server to operate. -ms.date: 01/23/2018 -localization_priority: Priority +ms.date: 03/08/2023 +ms.localizationpriority: high --- # Reactive and nonreactive SharePoint web parts Reactive web parts are client-side only; nonreactive web parts have elements that require a server to operate. We recommend that you build your SharePoint web parts to be reactive because that best fits the UX model and WYSIWYG principles for authoring. However, it might not be possible or cost-effective in all cases to build reactive web parts. - ## Reactive web parts Reactive web parts are fully client-side web parts. This means that each component configured in the property pane reflects the change made within the web part on the page. For example, for the To-Do List web part, unchecking “Completed Tasks” hides this view in the web part. -A reactive web part +![A reactive web part](../images/design-reactive-01.png) ## Nonreactive web parts -Nonreactive web parts are not fully client-side; generally, one or more properties need to make a call to set/pull or store data on a server. For nonreactive web parts, you should enable the **Apply** button at the bottom of the property pane. -You can also customize the **Apply** button to be a more specific action. +Nonreactive web parts aren't fully client-side; generally, one or more properties need to make a call to set/pull or store data on a server. For nonreactive web parts, you should enable the **Apply** button at the bottom of the property pane. -A nonreactive web part with Apply and Cancel buttons +You can also customize the **Apply** button to be a more specific action. -
+![A nonreactive web part with Apply and Cancel buttons](../images/design-reactive-02.png) The following examples show nonreactive web parts in the context of the [three property pane structures](design-a-web-part.md). -**Single pane example** - -A nonreactive web part with a single pane property structure - -
+### Single pane example -**Accordion groups example** +![A nonreactive web part with a single pane property structure](../images/design-reactive-03.png) -A nonreactive web part with an according groups pane property structure +### Accordion groups example -
+![A nonreactive web part with an according groups pane property structure](../images/design-reactive-04.png) -**Steps pane example** +### Steps pane example -A nonreactive web part with a steps pane property structure +![A nonreactive web part with a steps pane property structure](../images/design-reactive-05.png) ## See also diff --git a/docs/design/semantic_slots.md b/docs/design/semantic_slots.md index 9232056f5..a6e5632b2 100644 --- a/docs/design/semantic_slots.md +++ b/docs/design/semantic_slots.md @@ -1,8 +1,8 @@ --- title: Designing for section backgrounds using semantic slots description: Learn how to design your web part to take advantage of section backgrounds using semantic slots. -ms.date: 05/18/2021 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # Designing for section backgrounds using semantic slots @@ -15,7 +15,7 @@ Section background is a feature that applies background color to a canvas secti ## Variant vs. Section background -A variant describes different values of color generated from an existing theme. A variant will share the same set of colors as the original theme it was generated from, but will apply those colors differently. See [Office UI Fabric variant documentation](https://github.com/OfficeDev/office-ui-fabric-react/blob/master/packages/variants/README.md) for more detail. +A variant describes different values of color generated from an existing theme. A variant will share the same set of colors as the original theme it was generated from, but will apply those colors differently. See [@fluentui/scheme-utilities](https://github.com/microsoft/fluentui/blob/master/packages/scheme-utilities/README.md) for more detail. A Section Background allows the user to apply a variant color from the theme to a canvas section. Both concepts share "Neutral", "Soft", and "Strong" options and can be used interchangeably when describing color usage. @@ -25,46 +25,23 @@ A semantic slot is a theming slot that targets specific page elements. A Offic For example, default text uses the "bodyText" semantic slot. On the None, Neutral, and Soft section backgrounds, bodyText is assigned neutralPrimary. On the Strong section background, the palette color of bodyText changes to white. Semantic slots can be assigned palette colors for all variants in dark themes as well. -In the table below, you can see all eight palette colors defined for the bodyText slot. +In the table below, you can see all eight palette colors defined for the bodyText slot. ![Example table showing semantic slots on light and dark theme variants](../images/doc-semantic-slot-940px-table.png) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Light themes Dark themes
NoneneutralPrimary #333333neutralPrimary #ffffff
NeutralneutralPrimary #333333neutralPrimary #ffffff
SoftneutralPrimary #333333neutralPrimary #ffffff
Strongwhite #ffffffwhite #1f1f1f
-
+| Weight | Light themes | Dark themes | +| ------- | ---------------------- | ---------------------- | +| None | neutralPrimary #333333 | neutralPrimary #ffffff | +| Neutral | neutralPrimary #333333 | neutralPrimary #ffffff | +| Soft | neutralPrimary #333333 | neutralPrimary #ffffff | +| Strong | white #ffffff | white #ffffff | > [!NOTE] > The current semantic slot list is defined by commonly used design patterns in SharePoint. We want to avoid creating case-specific semantic slots. When designing a new web part, consider aligning to an existing design pattern. Office UI Fabric's policy is that semantic slots may never be removed from the list, so any additions are permanent. ## Identifying semantic slots in your designs -Semantic slots should be assigned based on the function of a page element. The name of a semantic slot can quickly tell you how it’s meant to be used. You can find all existing semantic slots and their use case examples in the [Fabric semantic colors documentation](/fluentui#/styles/web/colors/theme-slots). +Semantic slots should be assigned based on the function of a page element. The name of a semantic slot can quickly tell you how it’s meant to be used. You can find all existing semantic slots and their use case examples in the [Fabric semantic colors documentation](https://developer.microsoft.com/fluentui#/styles/web/colors/theme-slots). Fabric palette colors should be referenced from your site theme’s color ramp. If your site is using a SharePoint out of the box theme, you can reference [SharePoint theme color ramps](https://fluentfabric.azurewebsites.net/#/color/products). If your site is using a custom theme, you can generate a unique color ramp using the [Fluent UI Theme Designer](https://aka.ms/themedesigner). diff --git a/docs/design/showcase-web-part.md b/docs/design/showcase-web-part.md index ce8eb74f0..09965c263 100644 --- a/docs/design/showcase-web-part.md +++ b/docs/design/showcase-web-part.md @@ -1,86 +1,61 @@ --- title: "SharePoint web part design showcase: Create a To-Do list property pane" description: Create a To-Do list web part that uses a single pane and is reactive. -ms.date: 01/23/2018 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint web part design showcase: Create a To-Do list property pane This article describes how to create a To-Do list web part. This example uses the single pane [property pane type](design-a-web-part.md) and is [reactive](reactive-and-nonreactive-web-parts.md) and based on the [Office UI Fabric](https://developer.microsoft.com/fabric) responsive grid. - ## Create a To-Do list web part 1. Add a description to help users understand more about the web part and its properties. - In this example, the description is "Select a source for your to-dos and customize the display for the list of tasks." - - ![Adding a description](../images/design-showcase-01.png) - -
- -2. Add a Fabric [drop-down component](https://developer.microsoft.com/fabric#/components/dropdown) connected to a list. - - ![Adding a Fabric dropdown](../images/design-showcase-02.png) - -
- -3. Add a Fabric [checkbox component](https://developer.microsoft.com/fabric#/components/checkbox) to display completed tasks. - - ![Adding a Fabric check box](../images/design-showcase-03.png) - -
+ In this example, the description is "Select a source for your to-dos and customize the display for the list of tasks." -4. Add two more check boxes to control display options. + ![Adding a description](../images/design-showcase-01.png) - ![Adding two more Fabric check boxes](../images/design-showcase-04.png) +1. Add a Fabric [drop-down component](https://developer.microsoft.com/fabric#/components/dropdown) connected to a list. -
+ ![Adding a Fabric dropdown](../images/design-showcase-02.png) -5. Add a Fabric [slider](https://developer.microsoft.com/fabric#/components/slider) for the maximum number of items to display. +1. Add a Fabric [checkbox component](https://developer.microsoft.com/fabric#/components/checkbox) to display completed tasks. - ![Adding a Fabric slider](../images/design-showcase-05.png) + ![Adding a Fabric check box](../images/design-showcase-03.png) -
+1. Add two more check boxes to control display options. -6. Next, the author of the page selects a list or manually adds tasks to prepopulate the To-Do list web part. + ![Adding two more Fabric check boxes](../images/design-showcase-04.png) - ![Select a list in pane](../images/design-showcase-06.png) +1. Add a Fabric [slider](https://developer.microsoft.com/fabric#/components/slider) for the maximum number of items to display. -
+ ![Adding a Fabric slider](../images/design-showcase-05.png) - ![Select a list in pane expanded](../images/design-showcase-07.png) +1. Next, the author of the page selects a list or manually adds tasks to prepopulate the To-Do list web part. -
+ ![Select a list in pane](../images/design-showcase-06.png) - ![Manual addition of tasks to list](../images/design-showcase-08.png) + ![Select a list in pane expanded](../images/design-showcase-07.png) -
+ ![Manual addition of tasks to list](../images/design-showcase-08.png) -7. The web part shows an indicator of items loading onto the page. +1. The web part shows an indicator of items loading onto the page. - ![Indicator of items](../images/design-showcase-09.png) + ![Indicator of items](../images/design-showcase-09.png) -
+1. Items from the list load. -8. Items from the list load. + ![List items loading](../images/design-showcase-10.png) - ![List items loading](../images/design-showcase-10.png) + When the new tasks are loaded, they fade into view by using animation components from Office UI Fabric. -
+ ![New tasks loaded](../images/design-showcase-11.png) - When the new tasks are loaded, they fade into view by using animation components from Office UI Fabric. +1. The property pane controls the UI. Tasks with pivots enabled are displayed via the Display check boxes in the property pane. - ![New tasks loaded](../images/design-showcase-11.png) - -
- -9. The property pane controls the UI. Tasks with pivots enabled are displayed via the Display check boxes in the property pane. - - ![Property pane controlling web part items](../images/design-showcase-12.png) - -
+ ![Property pane controlling web part items](../images/design-showcase-12.png) ## Responsive views @@ -88,20 +63,14 @@ The following example shows the 2/3 column view of the web part. ![Two thirds column view](../images/design-showcase-13.png) -
- The following example shows the 1/3 column view of the web part. ![One third column view](../images/design-showcase-14.png) -
- The following example shows the mobile (read-only) view of the web part. ![Mobile view of the to-do list web part](../images/design-showcase-15.png) -
- ## See also - [Designing great SharePoint experiences](design-guidance-overview.md) diff --git a/docs/design/themes-colors.md b/docs/design/themes-colors.md index e8dfac7c5..d2eee4ec8 100644 --- a/docs/design/themes-colors.md +++ b/docs/design/themes-colors.md @@ -1,8 +1,8 @@ --- title: SharePoint themes and colors description: Design principles that help form the current SharePoint themes and color palette. -ms.date: 05/21/2018 -localization_priority: Priority +ms.date: 09/04/2024 +ms.localizationpriority: high --- # SharePoint themes and colors @@ -19,90 +19,13 @@ The SharePoint color palette is now optimized for screens and devices. In additi Neutral colors recede into the background to let our products shine. They allow brand colors to pop when we need to draw attention to content. When coupling neutrals with brand colors, make sure there is suitable contrast between them. -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Neutral greysblack: #000000
neutralDark: #212121
neutralPrimary: #333333
neutralPrimaryAlt: #3c3c3c
neutralSecondary: #666666
neutralTertiary: #a6a6a6
neutralTertiaryAlt: #c8c8c8
neutralQuaternary: #d0d0d0
neutralQuaternaryAlt: #dadada
neutralLight: #eaeaea
neutralLighter: #f4f4f4
neutralLighterAlt: #f8f8f8
white: #ffffff
-
+![Neutral greys](../images/sharepoint-neutralgreys.png) ## Shades and tints After you select a color, light and dark shades of the accent color are created based on HSB values of color luminosity. Web parts and apps can use shade variations to create visual hierarchy and provide an indication of interaction. -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Theme primary colorsthemeDarker: #004578
themeDark: #005a9e
themeDarkAlt: #106ebe
themePrimary: #0078d4
themeSecondary: #2b88d8
themeTertiary: #71afe5
themeLight: #c7e0f4
themeLighter: #deecf9
themeLighterAlt: #eff6fc
- -
- +![Theme primary colors](../images/sharepoint-theme-primary.png) ## Dark themes @@ -110,22 +33,6 @@ SharePoint includes a palette that supports dark themes. The SharePoint-provided ![SharePoint dark theme color palette, Red EF6950, Yellow FFC83D, Green 00b294, Blue 3a96dd, Purple 9c89e9, Grey b1adab](../images/sharepoint-themes-dark.png) -## Principles - -The following design principles helped form the current SharePoint themes and color palette. - -### Guided -Our theming system works at a global level so that updates can be made consistently across each site, allowing users to optimize their websites effortlessly. Our theming system operates in a controlled environment so that successful outcomes can be optimized quickly. - -### Smart and efficient -Our theming system expedites the site creation process by using smart algorithms to generate options that maximize aesthetic choices. - -### Professional -Our themes embody a professional look and feel that ensures coherency and conveys the brand of our enterprise audiences. - -### Accessible -Our built-in accessibility checker ensures universal design at all levels of default themes. For users who decide to customize, we provide helpful guidelines to design for accessibility. - ## See also - [Accessibility](accessibility.md) diff --git a/docs/design/ui-text-for-web-parts.md b/docs/design/ui-text-for-web-parts.md index 9be1c6ec3..5dfd50870 100644 --- a/docs/design/ui-text-for-web-parts.md +++ b/docs/design/ui-text-for-web-parts.md @@ -1,64 +1,56 @@ --- title: UI text guidelines for SharePoint web parts description: Use simple, understandable, and concise UI text to create effective web parts in SharePoint. -ms.date: 01/23/2018 -localization_priority: Normal +ms.date: 03/08/2023 +ms.localizationpriority: medium --- # UI text guidelines for SharePoint web parts - -One aspect of creating effective web parts in SharePoint is to use simple, understandable, and concise UI text. By keeping your message clear and easy to understand, you ensure that customers move through your experiences quickly and can identify the content they are looking for. This article provides guidance for writing UI text for key areas within SharePoint web parts. +One aspect of creating effective web parts in SharePoint is to use simple, understandable, and concise UI text. By keeping your message clear and easy to understand, you ensure that customers move through your experiences quickly and can identify the content they're looking for. This article provides guidance for writing UI text for key areas within SharePoint web parts. ## Capitalization -Use sentence casing (first letter of first word is capitalized, the rest all lowercase) for all UI elements, including buttons, page titles, and control labels. - +Use sentence casing (first letter of first word is capitalized, the rest all lowercase) for all UI elements, including buttons, page titles, and control labels. Always capitalize: - The first word of a new sentence. - The word following a colon in a title or heading. For example, "Step 1: Begin by entering your account information." -- Proper nouns, such as the names of people, cities, and so on. - -An image web part with sentence-style capitalization highlighted +- Proper nouns, such as the names of people, cities, and so on. -
+![Screenshot of an image alternative-text web part with sentence-style capitalization highlighted](../images/design-uitext-01.png) -An image web part with sentence-style capitalization highlighted +![Screenshot of an image gallery add web part with sentence-style capitalization highlighted](../images/design-uitext-02.png) ## Punctuation Follow the basic rules of punctuation to avoid grammatical errors in your experience. The following table provides guidance and reminders about what punctuation to use when, and why. -|Punctuation |Guidance |Example | -|-------------|------------------------------------------------|-----------------| -|Colons (:) | Use colons if you are introducing a list in the web part description.
Don't use colons in UI labels.| Choose one of the following: Cats, Dogs, Quokkas | -|Commas (,) | Use serial commas (including before the word "and"). |I like cats, birds, and dogs. | -|Ellipses (…)| Use ellipses to show truncation and for progress indicator strings.
Don't use ellipses to indicate that the user must make further choices.|Truncation: Last modified by John Armstr…
Progress indicator: Uploading… | -|Periods (.) | Use periods as you normally would for descriptions.
Don't use periods in titles, headings, or labels. Don't use periods for radio button options or check boxes. | Select the content that you want to highlight and how you want it displayed. Use a filter to narrow your selection. | - - +| Punctuation | Guidance | Example | +| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| Colons (:) | Use colons if you're introducing a list in the web part description.
Don't use colons in UI labels. | Choose one of the following: Cats, Dogs, Quokkas | +| Commas (,) | Use serial commas (including before the word "and"). | I like cats, birds, and dogs. | +| Ellipses (…) | Use ellipses to show truncation and for progress indicator strings.
Don't use ellipses to indicate that the user must make further choices. | Truncation: Last modified by John Armstr…
Progress indicator: Uploading… | +| Periods (.) | Use periods as you normally would for descriptions.
Don't use periods in titles, headings, or labels. Don't use periods for radio button options or check boxes. | Select the content that you want to highlight and how you want it displayed. Use a filter to narrow your selection. | ## Voice and tone Crafting the right tone in your product communication is essential to building a strong, lasting relationship with your audience. Try to keep your words crisp and clear, warm and relaxed, and approachable. How you talk to your audience influences how they engage with your site and content, and how much value they derive from it. -**Do:** +### Do -- Use a casual, conversational tone in the UI. -- Use contractions. For example, use "can't" instead of "cannot". +- Use a casual, conversational tone in the UI. +- Use contractions. For example, use "can't" instead of "can't". - Read your UI text out loud to test the tone. Does it sound like everyday language? -- Use simple words. -- Remove technical details if they're not relevant to the user experience. -- Use "Please" only if you are inconveniencing the user. Avoid overuse. -- Use "Sorry" only in error messages in SharePoint that result in serious problems for the customer. +- Use simple words. +- Remove technical details if they're not relevant to the user experience. +- Use "Please" only if you're inconveniencing the user. Avoid overuse. +- Use "Sorry" only in error messages in SharePoint that result in serious problems for the customer. +### Don't -**Don't:** - -- Clutter the UI text with unnecessary repetition. Make every word meaningful. - +- Clutter the UI text with unnecessary repetition. Make every word meaningful. ## Pronouns @@ -66,25 +58,21 @@ Avoid pronouns in UI elements if possible. If you can say something equally well If your design does warrant using pronouns, apply the following guidelines to make sure that you're using them correctly. -**Do:** +### Do - Use second person ("you" or "your") when you're presenting something that belongs to the user. For example, "Your drafts" or "Your images". - Use first person ("me" or "my") for UI in which the user instructs the service to do something. For example, "Alert me when someone responds to my post." - Use "they" or "their" as a singular possessive modifier to avoid awkward "he/she" or "his/her" constructs. Ideally, rewrite the sentence as plural if possible. - Avoid using "them"; instead, use words like "someone" or "people". For example, "Enter a user name and domain to give someone permission to use this PC." -An image showing the correct use of the second person you and the incorrect use of the third person users in the UI - -
+![An image showing the correct use of the second person you and the incorrect use of the third person users in the UI](../images/design-uitext-03.png) -An image showing the correct use of the UI text Select the page you want people to see first +![An image showing the correct use of the UI text Select the page you want people to see first](../images/design-uitext-04.png) -**Don't:** +### Don't - Use third person references, as they sound impersonal and can create a disconnected customer experience. Instead of saying "Users can change the layout", use a phrase like "You can change the layout". - - ## Error messages Error conditions are inherent in any software or service. Your error messages can affect the overall user satisfaction with the product. A good error message should do the following: @@ -93,50 +81,44 @@ Error conditions are inherent in any software or service. Your error messages ca - Provide a workaround or resolution suggestions. - Show empathy. - - The following is an example of an error message that occurs when a user tries to edit a page that's checked out by another user. - -| You can't edit right now | -|-------------------------------------------------------------------------| +| You can't edit right now | +| ------------------------------------------------------------------------------- | | Another user is currently editing this page. Please try again in a few minutes. | - ## Links to help articles Make an effort to link strategically to help articles. Try to anticipate where the user might need help, and then include a link to the help article close to that UI element. The following are some key things to remember when you place help article links in your UI. -**Do:** - -- Keep the in-product help links specific. Ensure that the target article is appropriate. When the user opens the article, they should be able to locate the information they need. -- Use natural language for your hyperlinks. +### Do - +- Keep the in-product help links specific. Ensure that the target article is appropriate. When the user opens the article, they should be able to locate the information they need. +- Use natural language for your hyperlinks. -**Don’t:** +### Don't - Put a help article link next to every UI element. This results in visual noise. - Include multiple links that go to the same target in the same UI. -- Use "click here" for the text for your hyperlink. +- Use "click here" for the text for your hyperlink. -An image of the More information and examples as the help link text +![An image of the More information and examples as the help link text](../images/design-uitext-05.png) ## Hint text Hint text, or ghost text, is the text element you display in a UI element, typically a text box, to help the user interact with the UI. The hint text gives information about what the user should enter. For example, it might mention field restrictions or show an example. -**Do:** +### Do - Use hint text sparingly, and only if it helps the user. Not all UI elements require hint text. For some complex fields, hint text can help provide more context and clarity. For example, if you have a field that requires the user to enter a secured URL, the hint text https://www.example.com might be more helpful than the text **Enter secure URL here.** -**Don't** +### Don't - Repeat the label. For example, if you have a text box with the label **Name**, the hint text **Enter name** is redundant and potentially confusing. -The following hint text is for the embed web part. The text field can accept a secure website address or an iframe embed code. The text shows an example of both. +The following hint text is for the embed web part. The text field can accept a secure website address or an ` + + +``` + +## Load the document preview dynamically + +If you intend to dynamically load the preview in the same page without leaving it, you might get a CORS error if you attempt to access the Microsoft Graph endpoint directly from a script from your page. + +One way to solve this problem is to create an endpoint in your application that makes the request and returns the url. + +For example, your server-side code should first obtain the document's preview url: + +```csharp +[HttpGet] +[AuthorizeForScopes(Scopes = new string[] { "Files.Read.All" })] +public async Task> GetPreviewUrl(string driveId, string itemId) +{ + // Obtain tokens for the the request + // Use the function created in the first step + return url + "&nb=true"; //Use nb=true to suppress banner +} +``` + +The client-side application can then use the browser's `fetch` API to request and inject the url into the `iframe`: + +```javascript +async function preview(driveId, itemId) { + const url = `/GetPreviewUrl?driveId=${driveId}&itemId=${itemId}`; + const response = await fetch(url, { + credentials: 'include', + }).then(response => response.text()); + + document.getElementById('preview').src = response + "&nb=true"; //Use nb=true to suppress banner +} +``` diff --git a/docs/embedded/development/tutorials/using-webhooks.md b/docs/embedded/development/tutorials/using-webhooks.md new file mode 100644 index 000000000..b0511b294 --- /dev/null +++ b/docs/embedded/development/tutorials/using-webhooks.md @@ -0,0 +1,113 @@ +--- +title: Using Webhooks +description: Use webhooks with SharePoint Embedded. +ms.date: 03/03/2025 +ms.localizationpriority: high +--- + +# Using Webhooks + +## Set Up Webhooks with SharePoint Embedded + +Webhooks are automated messages that are transmitted by an application when a trigger is activated. They can be used in SPE to enable the automation of workflows, the integration of systems, and to respond to events in real-time. + +You'll use webhooks to invoke the Azure Cognitive Services APIs from the application whenever an existing file is updated, or a new file is uploaded. + +To set up webhooks with your [current SharePoint Embedded application](/training/modules/sharepoint-embedded-create-app/), you need to: + +1. Create and register a webhook endpoint to get notifications whenever there's a change in your container. This will be done using REST APIs. +1. Connect to Graph and subscribe to changes. You can expose your application to the internet by either running it locally or deploying it on the cloud. For this tutorial, you'll be employing the former by utilizing ngrok and then subscribing to the changes by making a POST call. +1. Perform any desired action by handling the webhook data. One such use case is covered in [Enabling document processing with Azure Cognitive Services tutorial](./doc-processing-acs.md). + +![using webhooks schema](../../images/Using-Webhooks.png) + +> [!TIP] +> To learn more about the Microsoft Graph APIs used in this tutorial, see [Create subscription](/graph/api/subscription-post-subscriptions). + +## Create and register a webhook + +Open the **index.ts** file and add an endpoint `onReceiptAdded`: + +```typescript +server.post('/api/onReceiptAdded', async (req, res, next) => { + try { + const response = await onReceiptAdded(req, res); + res.send(200, response) + } catch (error: any) { + res.send(500, { message: `Error in API server: ${error.message}` }); + } + next(); +}); +``` + +You also need to add the query parser plugin at the top of this file so that it runs at server startup: + +```typescript +server.use(restify.plugins.bodyParser(), restify.plugins.queryParser()); +``` + +Create **onReceiptAdded.ts** and implement the method `onReceiptAdded` to read `validationToken` and `driveId`. `validationToken` is required when Microsoft Graph makes a one-time call to verify the endpoint upon creation of the webhook subscription. `driveId` is the container-id for which the subscription is created. + +```typescript +require('isomorphic-fetch'); + +export const onReceiptAdded = async (req: Request, res: Response) => { + + const validationToken = req.query['validationToken']; + if (validationToken) { + res.send(200, validationToken, {"Content-Type":"text/plain"}); + return; + } + + const driveId = req.query['driveId']; + if (!driveId) { + res.send(200, "Notification received without driveId, ignoring", {"Content-Type":"text/plain"}); + return; + } + + console.log(`Received driveId: ${driveId}`); + + res.send(200, ""); + return; +} +``` + +## Connect to Graph and subscribe to changes + +Follow the [documentation](https://ngrok.com/docs/getting-started/) to create a tunnel for your backend server using ngrok. + +After starting the app, run the following command in a terminal: + +```powershell +ngrok http 3001 +``` + +On successful completion, you should get the following output. The public-facing endpoint for the app is highlighted in the red rectangle: + +![ngrok registration](../../images/ngrok-registration.png) + +Once the tunneling is active, you can subscribe to delta changes in the container by adding the webhook URL. To do that, open Postman and make the following `POST` request with the appropriate graph access token and `notificationUrl` with the `driveId` appended as a query parameter to ensure that you get notifications for changes only in the desired container. + +```json +POST https://graph.microsoft.com/v1.0/subscriptions +{ + "changeType": "updated", + "notificationUrl":"https://5ac2-2404-f801-8028-3-691a-87b2-d309-545b.ngrok-free.app/api/onReceiptAdded?driveId={{ContainerId}}", + "resource": "drives/{{ContainerId}}/root", + "expirationDateTime": "2024-01-20T03:58:34.088Z", + "clientState": "" +} +``` + +You can use the following code snippet for setting the max possible expiration time of 4230 minutes from the current time by adding this to the "Pre-request Script" section. It will set an environment variable that can be used in the request body. + +```javascript +var now = new Date() +var duration = 1000 * 60 * 4230; // max lifespan of driveItem subscription is 4230 minutes +var expiry = new Date(now.getTime() + duration); +var expiryDateTime = expiry.toISOString(); + +pm.environment.set("ContainerSubscriptionExpiry", expiryDateTime); +``` + +At this point, if you add/update any file in the container, you'll get a notification at the previously added endpoint (`/api/onReceiptAdded`) and a log message at the console: `Received driveId: ` diff --git a/docs/embedded/getting-started/containertypes.md b/docs/embedded/getting-started/containertypes.md new file mode 100644 index 000000000..f21edc78f --- /dev/null +++ b/docs/embedded/getting-started/containertypes.md @@ -0,0 +1,207 @@ +--- +title: Create New SharePoint Embedded Container Types +description: This article explains how Container Types work and the steps to create new Container Types. +ms.date: 03/03/2025 +ms.localizationpriority: high +--- + +# SharePoint Embedded Container Types + +A container type is a SharePoint Embedded resource that defines the relationship, access privileges, and billing accountability between a SharePoint Embedded application and a set of containers. Also, the container type defines behaviors on the set of containers. + +Each container type is strongly coupled with one SharePoint Embedded application, which is referred to as the owning application. The owning application developer is responsible for creating and managing their container types. SharePoint Embedded mandates a 1:1 relationship between owning application and a container type. + +Container type is represented on each container instance as an immutable property (ContainerTypeID) and is used across the entire SharePoint Embedded ecosystem, including: + +- **Access authorization**: A SharePoint Embedded application must be associated with a container type to get access to container instances of that type. Once associated, the application has access to all container instances of that type. The actual access privilege is determined by the application-ContainerTypeID permission setting. The owning application by default has full access privilege to all container instances of the container type it's strongly coupled with. Learn more about [SharePoint Embedded Authorization](../development/auth.md). +- **Easy exploration**: Container type can be created for trial purposes, allowing developers to explore SharePoint Embedded application development and assess its features for free. +- **Billing**: Container types for non-trial purposes are billable and must be created with an Azure Subscription. The usage of containers is metered and charged. Learn more about [metering](../administration/billing/meters.md) and the [SharePoint Embedded billing experience](../administration/billing/billingmanagement.md). +- **Configurable behaviors**: Container type defines selected behaviors for all container instances of that type. Learn more about setting [Container type configuration](../getting-started/containertypes.md#configuring-container-types). + +> [!NOTE] +> +> 1. You must specify the purpose of the container type you're creating at creation time. Depending on the purpose, you may or may not need to provide your Azure Subscription ID. A container type set for trial purposes can't be converted for production; or vice versa. +> 1. Standard and pass through container types can't be converted once created. If you want to convert a standard container type to pass through billing or vice versa, you must delete and re-create the container type. +> 1. You must use the latest version of SharePoint PowerShell to configure a container type. For permissions and the most current information about Windows PowerShell for SharePoint Embedded, see the documentation at [Intro to SharePoint Embedded Management Shell](/powershell/sharepoint/sharepoint-online/introduction-sharepoint-online-management-shell). + +## Creating Container Types + +SharePoint Embedded has 2 different Container Types you can create. + +1. [Trial Container Type](#trial-container-type) +1. [Standard Container Type](#standard-container-types-non-trial) + +### Prerequisites to create SharePoint Embedded container type + +A new container type will be created using **SharePoint Online Management Shell**: + +1. Download and install the [latest version of SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588) +1. Open SharePoint Online Management Shell from **Start** screen, type **sharepoint**, and then select **SharePoint Online Management Shell**. +1. Connect to SPO service using `Connect-SPOService` cmdlet by providing admin credentials associated with tenancy. For information on [how to use Connect-SPOService](/powershell/module/sharepoint-online/connect-sposervice), refer the linked documentation. + +### Tenant requirements + +- An active instance of SharePoint is required in your Microsoft 365 tenant. +- Users who will be authenticating into SharePoint Embedded Container Types and Containers must be in Entra ID (Members and Guests) + + > [!NOTE] + > An Office license is not required to collaborate on Microsoft Office documents stored in a container. + +### Roles and Permissions + +- The admin who sets up the billing relationship for SharePoint Embedded needs to have owner or contributor permissions on the Azure subscription. +- Admin needs to have a SharePoint Embedded Administrator or Global Admin role to operate billing cmdlets. + +### Azure Subscription + +For the standard billing container type, the global administrator or SharePoint Embedded Administrator needs to set up: + +- An existing SharePoint tenancy +- An Azure subscription in the tenancy +- A resource group attached to the Azure subscription + +## Trial Container Type + +A container type can be created for trial/development purposes and isn't linked to any Azure billing profile. This enables developers to explore SharePoint Embedded application development and assess its features for free. For trial container types, the developer tenant is the same as the consuming tenant. +Each developer can have only one container type in the trial status in their tenant at a time. The trial container type is valid for up to 30 days but can be removed at any time within this period. + +To create a container type for trial purposes, you can: + +- Use SharePoint Embedded Visual Studio Code Extension to create the container type in just a few steps. The Visual Studio Code extension registers your container type and creates containers for you. +- Use SharePoint PowerShell. You must be a SharePoint Embedded Administrator or Global Administrator to run the following cmdlet. If you're a SharePoint Administrator, grant yourself the SharePoint Embedded Admin role as well to execute these cmdlets. + + ```powershell + New-SPOContainerType [–TrialContainerType] [-ContainerTypeName] [-OwningApplicationId] [-ApplicationRedirectUrl] [] + ``` + +The following restrictions are applied to trial container types: + +- Up to five containers of the container type can be created. This includes active containers and those in the recycle bin. +- Each container has up to 1 GB of storage space. +- The container type expires after 30 days and access to any existing containers of that container type will be removed. +- The developer must permanently delete all containers of an existing container type in trial status to create a new container type for trial. This includes containers in the deleted container collection. +- The container type is restricted to work in the developer tenant. It can't be deployed in other consuming tenants. + +## Standard Container Types (non-trial) + +A standard container type in SharePoint Embedded defines the relationship, access privileges, and billing profile between an application and its containers. It establishes how the application interacts with the containers, including access permissions, and is associated with a billing profile for non-trial purposes. Each tenant can have 25 container types at a time. + +### Billing profile + +SharePoint Embedded is a consumption-based Pay-as-you-go (PAYG) offering meaning you pay only for what you use. SharePoint Embedded provides two billing models that the tenant developing the SharePoint Embedded application can select for respective container types, tailoring it to their unique business requirements. The two billing models are Standard and Pass-through billing. + +### Standard Container Type - with billing profile + +With the standard billing profile, all consumption-based charges are directly billed to the tenant who owns or develops the application. The admin in the developer tenant must establish a valid billing profile when creating a standard container type. + +![Standard](../images/1bill521.png) + +Each developer tenant can create up to five container types consisting of 1 trial container type and 4 standard container types or 5 standard container types. +Standard container types are created using the [New-SPOContainerType](/powershell/module/sharepoint-online/new-spocontainertype) cmdlet. + +You need the following to create a standard container type: + +- Use SharePoint PowerShell. You must be a SharePoint Embedded Administrator or Global Administrator to run this cmdlet. If you're a SharePoint Administrator, grant yourself the SharePoint Embedded Admin role as well to execute these cmdlets. +- An Azure subscription and a resource group must be present in the Azure portal for regular billing. +- An App registration must be created in Microsoft Entra ID. + +To create a standard container type using an Azure billing profile, use the following cmdlets: + +```powershell +New-SPOContainerType [-ContainerTypeName] [-OwningApplicationId] [-ApplicationRedirectUrl] [] +``` + +Once the container type is created, add the Azure billing profile. + +```powershell +Add-SPOContainerTypeBilling –ContainerTypeId -AzureSubscriptionId -ResourceGroup -Region +``` + +> [!NOTE] +> The user or admin who sets up a billing relationship for SharePoint Embedded must have owner or contributor permissions on the Azure subscription. +> +> Every container type must have an owning application. +> +> A single-owning app can only own one container type at a time. +> +> An Azure subscription can be attached to any number of container types. +> +> If the cmdlet above fails with a SubscriptionNotRegistered error, it is because **Microsoft.Syntex** is not registered as a resource provider in the subscription. The cmdlet will send a resource provider registration request on your behalf but it will take a few minutes to be completed. Please wait 5-10 minutes and try again until the cmdlet succeeds. + +### Standard Container Type - pass-through billing + +With pass-through billing, consumption-based charges are billed directly to the tenant registered to use the SharePoint Embedded application (consuming tenant). Admins in the developer tenant don't need to set up an Azure billing profile when creating a pass-through SharePoint Embedded container type. + +![Pass Through](../images/2bill521.png) + +For container types intended to be directly billed to a customer use the flag `-IsPassThroughBilling`. For the direct to customer billed container type, there's no need to attach a billing profile. + +To create a pass through billing, standard container type, use the following cmdlet: + +```powershell +New-SPOContainerType [-ContainerTypeName] [-OwningApplicationId] [-ApplicationRedirectUrl] [-IsPassThroughBilling] [] +``` + +Once the container type is [registered](../getting-started/register-api-documentation.md) in the consuming tenant, the consuming tenant admin (SharePoint Admin or Global Admin) needs to set up the billing profile in the consuming tenant to use the SharePoint Embedded application. + +#### Set Up Billing Profile in Consuming Tenant + +1. In [Microsoft 365 admin center](https://admin.microsoft.com/), select **Setup**, and the view the **Billing and licenses** section. Select **Activate pay-as-you-go services.** + + ![Microsoft 365 admin center Files and Content](../images/SyntexActivatePAYGSetup.png) + +1. Select **Go to Pay as you go services**. +1. Select **Apps** under **Syntex services for**, select **Apps** and **SharePoint Embedded** + + ![Microsoft 365 admin center SharePoint Embedded Billing setting](../images/SyntexPAYGActivateSPE.png) + + > [NOTE] + The subscription configured in the Syntex services will reflect the consuming charges in the Azure billing portal. + +1. [Register the container type](#registering-container-types) using the App only authentication token. + +## Configuring Container Types + +The Developer Admin can set selected settings on the SharePoint Embedded container types created by using this PowerShell cmdlet. + +This cmdlet allows admins to set [Microsoft 365 content discoverability](../development/content-experiences/user-experiences-overview.md) and [sharing](../development/sharing-and-perm.md) settings on container types. The setting applies to all container instances of the container type: + +```powershell +Set-SPOContainerTypeConfiguration -ContainerTypeId 4f0af585-8dcc-0000-223d-661eb2c604e4 -DiscoverabilityDisabled $False +``` + +## Viewing Container Types + +The Developer Admin can view all the SharePoint Embedded container types they created on their tenant using `Get-SPOContainerType`. This cmdlet retrieves and returns the list of container types created for a SharePoint Embedded Application in the tenant. + +```powershell +Get-SPOContainerType [] +``` + +Example output of the `Get-SPOContainerType` cmdlet + +```powershell +ContainerTypeId : 4f0af585-8dcc-0000-223d-661eb2c604e4 +ContainerTypeName : ContosoLegal +OwningApplicationId : a735e4af-b86e-0000-93ba-1faded6c39e1 +Classification : Standard +AzureSubscriptionId : 564e9025-f7f5-xxx9-9ddd-4cdxxxx1755 +ResourceGroup : prod-resources +Region : EastUS +``` + +## Registering Container Types + +To create and interact with containers, you must [register](../getting-started/register-api-documentation.md) the container type within the Consuming Tenant. The owning application defines the permissions for the container type by invoking the [registration API](../getting-started/register-api-documentation.md). + +## Deleting Container Types + +Developer admins can delete both trial and standard container types. To delete a container type, you must first remove all containers of that container type, including from the deleted container collection. To remove containers, refer to [Consuming Tenant Admin](../administration/consuming-tenant-admin/cta.md). +Once all the containers are deleted, Developer admins can delete the container type using `Remove-SPOContainerType`. + +```powershell +Remove-SPOContainerType [-ContainerTypeId ] +``` +## SharePoint Embedded meters + +To learn more about the supported pay-as-you-go meters, refer to the [SharePoint Embedded meters](../administration/billing/meters.md) article. diff --git a/docs/embedded/getting-started/register-api-documentation.md b/docs/embedded/getting-started/register-api-documentation.md new file mode 100644 index 000000000..320893e72 --- /dev/null +++ b/docs/embedded/getting-started/register-api-documentation.md @@ -0,0 +1,175 @@ +--- +title: Register File Storage container Type Application Permissions +description: Register the container type. +ms.date: 03/03/2025 +ms.localizationpriority: high +--- + +# Register file storage container type application permissions + +In order for a SharePoint Embedded application to interact with containers in a consuming tenant, the container type must first be registered in the consuming tenant. Container type registration happens when the owning application invokes the registration API to specify what permissions can be performed against its container type. The registration API also grants access to other Guest Apps to interact with the owning application's containers. For example, a SharePoint Embedded application can grant permissions to another application--a Guest App so that the Guest App can perform backup operations against its containers. + +Since the registration API controls the permissions that a SharePoint Embedded application can perform against the container in the consuming tenant, this call should be one of the first APIs invoked. Failure to do so results in access denied errors when invoking other APIs against the container and/or the content in the containers. + +There are no restrictions on how many times the registration API can be invoked. How often the registration API is invoked and when it's invoked is dependent on the SharePoint Embedded application. However, the last successful call to the registration API determines the settings used in the consuming tenant. + +## Authentication and authorization requirements + +For the container type's owning application to act on a consuming tenant, some pre-requisites must be completed: + +- the owning app must have a service principal installed on the consuming tenant; and +- the owning app must be granted admin consent to perform container type registration in the consuming tenant. + +> [!NOTE] +> Only the owning application of the container type can invoke the registration API in the consuming tenant. + +Both requirements can be satisfied by having a tenant administrator of the consuming tenant [grant admin consent](/entra/identity/enterprise-apps/grant-admin-consent?pivots=portal) to the container type's owning application. + +The container type registration API requires the `Container.Selected` app-only permission for SharePoint (see [Exceptional access patterns](../development/auth.md#exceptional-access-patterns)). You will need to use the [client credentials grant flow](/entra/identity-platform/v2-oauth2-client-creds-grant-flow) and [request a token with a certificate](/entra/identity-platform/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate) to use the registration API. + +> [!NOTE] +> The registration API is **NOT** a Microsoft Graph API but a SharePoint API. This API will be ported to Microsoft Graph in the future. + +To request admin consent from a tenant administrator in the consuming tenant, you may direct them to the [admin consent endpoint](/entra/identity-platform/v2-admin-consent). For the right endpoints on national clouds, see [Microsoft identity platform endpoints on national clouds](/entra/identity-platform/authentication-national-cloud#microsoft-entra-authentication-endpoints): + +```http +https://login.microsoftonline.com//adminconsent?client_id= +``` + +You may configure the admin consent endpoint to fit your needs, including handling errors and successful grants. For more information, see [Admin consent URI](/entra/identity-platform/v2-admin-consent). + + +## Container type Permissions + +The registration API determines what permissions a SharePoint Embedded application can perform against containers and content in containers for the specified container type. + +| Permission | Description | +| -------------------- | ------------------------------------------------------------------------------------------------------------------ | +| None | Has no permissions to any containers or content of this container type. | +| ReadContent | Can read content of containers of this container type. | +| WriteContent | Can write content to containers for this container type. This permission can't be granted without the ReadContent permission. | +| Create | Can create containers of this container type. | +| Delete | Can delete containers of this container type. | +| Read | Can read the metadata of containers of this container type. | +| Write | Can update the metadata of containers of this container type. | +| EnumeratePermissions | Can enumerate the members of a container and their roles for containers of this container type. | +| AddPermissions | Can add members to the container for containers of this container type. | +| UpdatePermissions | Can update (change roles of) existing memberships in the container for containers of this container type. | +| DeletePermissions | Can delete other members (but not self) from the container for containers of this container type. | +| DeleteOwnPermissions | Can remove own membership from the container for containers of this container type. | +| ManagePermissions | Can add, remove (including self) or update members in the container roles for containers of this container type. | +| Full | Has all permissions for containers of this container type. | + +## HTTP request + +```http +PUT {RootSiteUrl}/_api/v2.1/storageContainerTypes/{containerTypeId}/applicationPermissions +``` + +> [!NOTE] +> This is NOT a Graph API +> +> `{RootSiteURL}` is the SharePoint URL of the consuming tenant. For example, https://contoso.sharepoint.com. + +### Request body + +In the request body, supply a JSON representation of the container type permissions for the SharePoint Embedded applications. + +### Response + +If successful, this method returns a `200 OK` response code and the container type permissions configured for the SharePoint Embedded applications in the response body. + +| HTTP Code | Description | +| :--------: | ----------- | +| 400 | Bad request. | +| 401 | Request lacks valid authentication credentials. | +| 403 | Provided authentication credentials are valid but insufficient to perform the requested operation. Examples: the calling app isn't the owning app of the container type. | +| 404 | Container type doesn't exist. | + +## Examples + +### Register the container type in a consuming tenant with permissions only for the Owning App + +Register the container type in the consuming tenant and grant full permissions to the Owning Application (AppId 71392b2f-1765-406e-86af-5907d9bdb2ab) for Delegated and AppOnly calls. + +#### Request + +```json +PUT {RootSiteUrl}/_api/v2.1/storageContainerTypes/{containerTypeId}/applicationPermissions +Content-Type: application/json + +{ + "value": [ + { + "appId": "71392b2f-1765-406e-86af-5907d9bdb2ab", + "delegated": ["full"], + "appOnly": ["full"] + } + ] +} +``` + +#### Response + +```json +HTTP/1.1 200 OK +Content-type: application/json + +{ + "value": [ + { + "appId": "71392b2f-1765-406e-86af-5907d9bdb2ab", + "delegated": ["full"], + "appOnly": ["full"] + } + ] +} +``` + +### Register the container type in a consuming tenant with permissions for a Guest App + +Register the container type in the consuming tenant and grant full permissions to the Owning Application (AppId 71392b2f-1765-406e-86af-5907d9bdb2ab) for Delegated and AppOnly calls. In addition, grant a Guest App (AppId 89ea5c94-7736-4e25-95ad-3fa95f62b6) read and write permissions only for Delegated calls. + +#### Request + +```json +PUT /storagecontainerTypes/{containerTypeId}/applicationPermissions +Content-Type: application/json + +{ + "value": [ + { + "appId": "71392b2f-1765-406e-86af-5907d9bdb2ab", + "delegated": ["full"], + "appOnly": ["full"] + }, + { + "appId": "89ea5c94-7736-4e25-95ad-3fa95f62b6", + "delegated": ["read", "write"], + "appOnly": ["none"] + } + ] +} +``` + +#### Response + +```json +HTTP/1.1 200 OK +Content-type: application/json + +{ + "value": [ + { + "appId": "71392b2f-1765-406e-86af-5907d9bdb2ab", + "delegated": ["full"], + "appOnly": ["read"] + }, + { + "appId": "89ea5c94-7736-4e25-95ad-3fa95f62b6", + "delegated": ["read", "write"], + "appOnly": ["none"] + } + ] +} +``` diff --git a/docs/embedded/getting-started/spembedded-for-vscode.md b/docs/embedded/getting-started/spembedded-for-vscode.md new file mode 100644 index 000000000..343a842f5 --- /dev/null +++ b/docs/embedded/getting-started/spembedded-for-vscode.md @@ -0,0 +1,176 @@ +--- +title: SharePoint Embedded for Visual Studio Code +description: Installation and getting started with SharePoint Embedded for Visual Studio Code +ms.date: 07/16/2025 +ms.localizationpriority: high +--- + +# SharePoint Embedded for Visual Studio Code + +The SharePoint Embedded Visual Studio Code extension helps developers get started for free with SharePoint Embedded application development. + +> [!IMPORTANT] +> To start building with SharePoint Embedded, you'll need administrative access to a Microsoft 365 tenant. +> If you don't already have a tenant, you can get your own tenant with the [Microsoft 365 Developer Program](https://developer.microsoft.com/microsoft-365/dev-program), [Microsoft Customer Digital Experience](https://cdx.transform.microsoft.com/), or create a free trial of a [Microsoft 365 E3 license](https://www.microsoft.com/microsoft-365/enterprise/microsoft365-plans-and-pricing). + +## Install SharePoint Embedded for Visual Studio Code + +1. Open a new window in [Visual Studio Code](https://code.visualstudio.com/) and navigate to "**Extensions**" on the activity bar. +1. Search "SharePoint Embedded" in the Extensions view. You can also view the extension in [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=SharepointEmbedded.ms-sharepoint-embedded-vscode-extension). +1. Select **"Install"** and the SharePoint Embedded icon will appear on the activity bar. +1. If already installed, please update to the latest version if one is available. +1. Select the icon to open the SharePoint Embedded view and create a container type with trial configuration. + +![SharePoint Embedded VS Extensions](../images/vsx-images/n1downloadvsx.png) + +### Sign in with admin credentials + +To use the extension, you must sign in to a Microsoft 365 tenant with an administrator account. + +![Install](../images/vsx-images/n2vsx-signin.png) + +- Authentication opens a new tab in an external browser to grant permissions + + ![authorize and authenticate the extension to your M365 Entra tenant](../images/vsx-images/auth-allow-extension-uri.png) + +- Review the requested permissions carefully, then select **Accept** on the pop-up window prompting admin consent + + ![review before consenting to the permissions the extension is asking for](../images/vsx-images/n3vsx-grant-admin-consent.png) + +After successful authorization, select open on the dialog to be redirected to VSCode: + +![authorization completed in browser now redirecting to visual studio code](../images/vsx-images/auth-redirect.png) + +## Create a container type with a trial configuration + +Once signed in, you're prompted to create a [container type with trial configuration](./containertypes.md#trial-container-type). A container type lets you get started calling SharePoint Embedded APIs and building a proof-of-concept application using SharePoint Embedded. Learn more about [container types](containertypes.md). + +![home screen](../images/vsx-images/n4vsx-home-screen.png) + +- Select **Create Trial Container Type** +- Follow the prompts to name your container type. You can change your container type name later on. + +![create container type](../images/vsx-images/n5a-name-ct.png) + +> [!NOTE] +> SharePoint Embedded for Visual Studio Code only supports container types with trial configuration at this time. Other container types with standard or pass-through billing configurations must be created using the SharePoint Online PowerShell Module. + +## Create a Microsoft Entra ID App + +Every container type is owned by a Microsoft Entra ID application. The first step when creating a free trial container type is to create a new or select an existing Microsoft Entra ID application as the owning application. You can either specify the name of your new application or pick one of your existing applications. Learn more about SharePoint Embedded [app architecture](../development/app-architecture.md) + +- Follow the prompts to name your new Entra application or select an existing application ID: + +![Create App](../images/vsx-images/n6aname-app.png) + +> [!NOTE] +> If you choose an existing application, the extension will update that app's configuration settings for it to work with both SharePoint Embedded and this extension. Doing this is NOT recommended on production applications. + +After your container type is created and your application is configured, you'll be able to view your local tenant registration as a tree in the left nav-bar. + +## Register your container type + +After creating your container type, you'll need to register that container type on your local tenant. Learn more about container type [registration](./register-api-documentation.md). + +- Follow the prompts and select **Register on local tenant** on the lower right corner of the VS Code window + + ![local tenant registration popup](../images/vsx-images/local-tenant-registration-popup.png) + +- If you don't see the prompt, you can right-click on your `` and select **Register** from the menu + + ![register](../images/vsx-images/n7aregister-ct.png) + +### Grant permissions + +Review permissions and follow the prompt to grant admin consent + +![grant admin consent popup](../images/vsx-images/auth-grant-admin-consent-popup.png) + +An external browser window will pop open for you to sign-in and grant admin consent + +![login permissions](../images/vsx-images/n9alogin-grant-permissions.png) + +## Create your first container + +With your container type registered, you can now create your first container. Only five containers of container type can be created to upload and manage content. + +- Right-click on the **Containers** drop-down from the tree in the left nav-bar and select **Create container** +- Enter a name for the container you would like to create + +![create container](../images/vsx-images/n10acreate-container.png) +![name container](../images/vsx-images/n11aname-first-cont.png) + +## Recycling Containers + +You can also recycle and recover containers within the extension. + +![recycle containers](../images/vsx-images/n12arecycle-cont.png) + +![final home page](../images/vsx-images/n13a-final-home-page.png) + +## Load Sample App + +With your free trial container type created, you can use the extension to load one of the SharePoint Embedded sample apps and automatically populate the runtime configuration file with the details of your Microsoft Entra ID app and container type. + +![Load Sample App](../images/vsx-images/n15vsxsa-c.png) + +When loading the sample application, you'll be notified that it will create plain text secrets to authenticate on your local machine. + +![sample app plain text secrets notice](../images/vsx-images/sample-app-app-secrets-notice.png) + +If no client secret is found on your application, it will ask if you would like to create one. Press OK to proceed. + +![sample app creating client secret](../images/vsx-images/sample-app-create-client-secret.png) + +> [!IMPORTANT] +> This isn't intended for production environments. [Find out more on how to setup Application Registration for production environments here.](/entra/identity-platform/quickstart-register-app) + +## Using Sample App + +In your terminal, run the following command, this will start the sample application, which consists of 2 parts: + +1. **React Client Application** - The frontend user interface running on port 8080 +1. **Azure Function Application Server** - The backend API server that handles SharePoint Embedded operations + +```console +# Navigate to your sample application directory +cd [your-path]\SharePoint-Embedded-Samples\Samples\spe-typescript-react-azurefunction + +# Install dependencies and start the application +npm run start +``` + +> [!NOTE] +> The initial startup may take a few minutes as dependencies are installed and both applications are built. Wait for both console outputs to appear before navigating to the application. + +This will install the dependencies and run the server and client application, once running, you'll see the following in the terminal, after which you can navigate to http://localhost:8080 to access the application. + +![function api console logs](../images/vsx-images/fn-api-logs.png) + +![client app console logs](../images/vsx-images/client-app-logs.png) + +Once both applications are running successfully: + +1. Open your web browser and navigate to **http://localhost:8080** +1. Sign in using your Microsoft 365 administrator account (the same account used in the VS Code extension) +1. On the home page, select **"Containers"** to begin creating containers and uploading files +1. Follow the on-screen prompts to interact with your SharePoint Embedded containers + +![home-page-for-spe-sample-app](../images/vsx-images/spe-sample-app-home.png) + +> [!IMPORTANT] +> This sample application stores authentication secrets in plain text for development purposes only. Never use this configuration in a production environment. + +### Troubleshooting + +If you encounter issues: + +- **Port already in use**: If port 8080 is already in use, the application will automatically try the next available port +- **Dependencies not installing**: Try running `npm install` manually before `npm run start` +- **Authentication errors**: Ensure your Microsoft Entra ID app is properly configured with the correct redirect URIs + +## Export Postman Environment + +The [SharePoint Embedded Postman Collection](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/main/Postman) allows you to explore and call the SharePoint Embedded APIs. The Collection requires an environment file with variables used for authentication and various identifiers. This extension automates the generation of this populated environment file so you can import it into Postal worker and immediately call the SharePoint Embedded APIs. + +![Export Postman Environment](../images/vsx-images/n14postman-c.png) diff --git a/docs/embedded/images/1bill521.png b/docs/embedded/images/1bill521.png new file mode 100644 index 000000000..6528d71c3 Binary files /dev/null and b/docs/embedded/images/1bill521.png differ diff --git a/docs/embedded/images/2bill521.png b/docs/embedded/images/2bill521.png new file mode 100644 index 000000000..d4dfc162b Binary files /dev/null and b/docs/embedded/images/2bill521.png differ diff --git a/docs/embedded/images/DTCBilling1.png b/docs/embedded/images/DTCBilling1.png new file mode 100644 index 000000000..6a24fa4b5 Binary files /dev/null and b/docs/embedded/images/DTCBilling1.png differ diff --git a/docs/embedded/images/DTCBilling2.png b/docs/embedded/images/DTCBilling2.png new file mode 100644 index 000000000..b4c7318b9 Binary files /dev/null and b/docs/embedded/images/DTCBilling2.png differ diff --git a/docs/embedded/images/Document-Processing.png b/docs/embedded/images/Document-Processing.png new file mode 100644 index 000000000..7982dba53 Binary files /dev/null and b/docs/embedded/images/Document-Processing.png differ diff --git a/docs/embedded/images/SPEAdmin1.png b/docs/embedded/images/SPEAdmin1.png new file mode 100644 index 000000000..87c3a1fa8 Binary files /dev/null and b/docs/embedded/images/SPEAdmin1.png differ diff --git a/docs/embedded/images/SPEAdmin10.png b/docs/embedded/images/SPEAdmin10.png new file mode 100644 index 000000000..9f5feab08 Binary files /dev/null and b/docs/embedded/images/SPEAdmin10.png differ diff --git a/docs/embedded/images/SPEAdmin11.png b/docs/embedded/images/SPEAdmin11.png new file mode 100644 index 000000000..1027fc70a Binary files /dev/null and b/docs/embedded/images/SPEAdmin11.png differ diff --git a/docs/embedded/images/SPEAdmin12.png b/docs/embedded/images/SPEAdmin12.png new file mode 100644 index 000000000..102e0dacf Binary files /dev/null and b/docs/embedded/images/SPEAdmin12.png differ diff --git a/docs/embedded/images/SPEAdmin13.png b/docs/embedded/images/SPEAdmin13.png new file mode 100644 index 000000000..83d556813 Binary files /dev/null and b/docs/embedded/images/SPEAdmin13.png differ diff --git a/docs/embedded/images/SPEAdmin14.png b/docs/embedded/images/SPEAdmin14.png new file mode 100644 index 000000000..dc66703b5 Binary files /dev/null and b/docs/embedded/images/SPEAdmin14.png differ diff --git a/docs/embedded/images/SPEAdmin15.png b/docs/embedded/images/SPEAdmin15.png new file mode 100644 index 000000000..4a3f80cdb Binary files /dev/null and b/docs/embedded/images/SPEAdmin15.png differ diff --git a/docs/embedded/images/SPEAdmin16.png b/docs/embedded/images/SPEAdmin16.png new file mode 100644 index 000000000..03568e615 Binary files /dev/null and b/docs/embedded/images/SPEAdmin16.png differ diff --git a/docs/embedded/images/SPEAdmin2.png b/docs/embedded/images/SPEAdmin2.png new file mode 100644 index 000000000..8be14b0b4 Binary files /dev/null and b/docs/embedded/images/SPEAdmin2.png differ diff --git a/docs/embedded/images/SPEAdmin3.png b/docs/embedded/images/SPEAdmin3.png new file mode 100644 index 000000000..010bf998b Binary files /dev/null and b/docs/embedded/images/SPEAdmin3.png differ diff --git a/docs/embedded/images/SPEAdmin4.png b/docs/embedded/images/SPEAdmin4.png new file mode 100644 index 000000000..26b05d149 Binary files /dev/null and b/docs/embedded/images/SPEAdmin4.png differ diff --git a/docs/embedded/images/SPEAdmin5.png b/docs/embedded/images/SPEAdmin5.png new file mode 100644 index 000000000..b82c2bbfc Binary files /dev/null and b/docs/embedded/images/SPEAdmin5.png differ diff --git a/docs/embedded/images/SPEAdmin6.png b/docs/embedded/images/SPEAdmin6.png new file mode 100644 index 000000000..e80422388 Binary files /dev/null and b/docs/embedded/images/SPEAdmin6.png differ diff --git a/docs/embedded/images/SPEAdmin7.png b/docs/embedded/images/SPEAdmin7.png new file mode 100644 index 000000000..1b97c3acb Binary files /dev/null and b/docs/embedded/images/SPEAdmin7.png differ diff --git a/docs/embedded/images/SPEAdmin8.png b/docs/embedded/images/SPEAdmin8.png new file mode 100644 index 000000000..62cd5b268 Binary files /dev/null and b/docs/embedded/images/SPEAdmin8.png differ diff --git a/docs/embedded/images/SPEAdmin9.png b/docs/embedded/images/SPEAdmin9.png new file mode 100644 index 000000000..08a6f7120 Binary files /dev/null and b/docs/embedded/images/SPEAdmin9.png differ diff --git a/docs/embedded/images/SPEArch.png b/docs/embedded/images/SPEArch.png new file mode 100644 index 000000000..cb0818e3f Binary files /dev/null and b/docs/embedded/images/SPEArch.png differ diff --git a/docs/embedded/images/SPECTDedicated.png b/docs/embedded/images/SPECTDedicated.png new file mode 100644 index 000000000..67b94e68c Binary files /dev/null and b/docs/embedded/images/SPECTDedicated.png differ diff --git a/docs/embedded/images/SPECTShared.png b/docs/embedded/images/SPECTShared.png new file mode 100644 index 000000000..bcc4de7e8 Binary files /dev/null and b/docs/embedded/images/SPECTShared.png differ diff --git a/docs/embedded/images/SharePointEmbeddedToS-1.jpg b/docs/embedded/images/SharePointEmbeddedToS-1.jpg new file mode 100644 index 000000000..03777613c Binary files /dev/null and b/docs/embedded/images/SharePointEmbeddedToS-1.jpg differ diff --git a/docs/embedded/images/SharePointEmbeddedToS-2.jpg b/docs/embedded/images/SharePointEmbeddedToS-2.jpg new file mode 100644 index 000000000..c7196e505 Binary files /dev/null and b/docs/embedded/images/SharePointEmbeddedToS-2.jpg differ diff --git a/docs/embedded/images/SharePointEmbeddedToS-3.jpg b/docs/embedded/images/SharePointEmbeddedToS-3.jpg new file mode 100644 index 000000000..e7fb61050 Binary files /dev/null and b/docs/embedded/images/SharePointEmbeddedToS-3.jpg differ diff --git a/docs/embedded/images/SharePointEmbeddedToS-4.jpg b/docs/embedded/images/SharePointEmbeddedToS-4.jpg new file mode 100644 index 000000000..0d29fbfd4 Binary files /dev/null and b/docs/embedded/images/SharePointEmbeddedToS-4.jpg differ diff --git a/docs/embedded/images/SharePointEmbeddedToS-5.jpg b/docs/embedded/images/SharePointEmbeddedToS-5.jpg new file mode 100644 index 000000000..e09f5cd1c Binary files /dev/null and b/docs/embedded/images/SharePointEmbeddedToS-5.jpg differ diff --git a/docs/embedded/images/SharingPartitions.png b/docs/embedded/images/SharingPartitions.png new file mode 100644 index 000000000..5b3b4bd66 Binary files /dev/null and b/docs/embedded/images/SharingPartitions.png differ diff --git a/docs/embedded/images/SyntexActivatePAYGSetup.png b/docs/embedded/images/SyntexActivatePAYGSetup.png new file mode 100644 index 000000000..00147f57b Binary files /dev/null and b/docs/embedded/images/SyntexActivatePAYGSetup.png differ diff --git a/docs/embedded/images/SyntexPAYGActivateSPE.png b/docs/embedded/images/SyntexPAYGActivateSPE.png new file mode 100644 index 000000000..739a58a47 Binary files /dev/null and b/docs/embedded/images/SyntexPAYGActivateSPE.png differ diff --git a/docs/embedded/images/Using-Webhooks.png b/docs/embedded/images/Using-Webhooks.png new file mode 100644 index 000000000..5d98224cf Binary files /dev/null and b/docs/embedded/images/Using-Webhooks.png differ diff --git a/docs/embedded/images/add-owners-one.png b/docs/embedded/images/add-owners-one.png new file mode 100644 index 000000000..bba134252 Binary files /dev/null and b/docs/embedded/images/add-owners-one.png differ diff --git a/docs/embedded/images/add-owners-two.png b/docs/embedded/images/add-owners-two.png new file mode 100644 index 000000000..fe7af04ed Binary files /dev/null and b/docs/embedded/images/add-owners-two.png differ diff --git a/docs/embedded/images/app-arch.png b/docs/embedded/images/app-arch.png new file mode 100644 index 000000000..0129f6719 Binary files /dev/null and b/docs/embedded/images/app-arch.png differ diff --git a/docs/embedded/images/app-flow7.jpg b/docs/embedded/images/app-flow7.jpg new file mode 100644 index 000000000..cbf6f4801 Binary files /dev/null and b/docs/embedded/images/app-flow7.jpg differ diff --git a/docs/embedded/images/app-registration-console-platform.png b/docs/embedded/images/app-registration-console-platform.png new file mode 100644 index 000000000..177c0bc5a Binary files /dev/null and b/docs/embedded/images/app-registration-console-platform.png differ diff --git a/docs/embedded/images/apparc-1.png b/docs/embedded/images/apparc-1.png new file mode 100644 index 000000000..082e51788 Binary files /dev/null and b/docs/embedded/images/apparc-1.png differ diff --git a/docs/embedded/images/apparc-2.png b/docs/embedded/images/apparc-2.png new file mode 100644 index 000000000..7f8a72df8 Binary files /dev/null and b/docs/embedded/images/apparc-2.png differ diff --git a/docs/embedded/images/apparchexample.png b/docs/embedded/images/apparchexample.png new file mode 100644 index 000000000..f862809ad Binary files /dev/null and b/docs/embedded/images/apparchexample.png differ diff --git a/docs/embedded/images/architecture-overview.png b/docs/embedded/images/architecture-overview.png new file mode 100644 index 000000000..b815cb4cd Binary files /dev/null and b/docs/embedded/images/architecture-overview.png differ diff --git a/docs/embedded/images/billing-1.png b/docs/embedded/images/billing-1.png new file mode 100644 index 000000000..14eb0f29a Binary files /dev/null and b/docs/embedded/images/billing-1.png differ diff --git a/docs/embedded/images/billing-2.png b/docs/embedded/images/billing-2.png new file mode 100644 index 000000000..669b0642a Binary files /dev/null and b/docs/embedded/images/billing-2.png differ diff --git a/docs/embedded/images/billing-manage.png b/docs/embedded/images/billing-manage.png new file mode 100644 index 000000000..014db7f05 Binary files /dev/null and b/docs/embedded/images/billing-manage.png differ diff --git a/docs/embedded/images/billmanag1.png b/docs/embedded/images/billmanag1.png new file mode 100644 index 000000000..bebe7f8b9 Binary files /dev/null and b/docs/embedded/images/billmanag1.png differ diff --git a/docs/embedded/images/billmanag2.png b/docs/embedded/images/billmanag2.png new file mode 100644 index 000000000..1bca53b4f Binary files /dev/null and b/docs/embedded/images/billmanag2.png differ diff --git a/docs/embedded/images/billmanag3.png b/docs/embedded/images/billmanag3.png new file mode 100644 index 000000000..2ac8dd97b Binary files /dev/null and b/docs/embedded/images/billmanag3.png differ diff --git a/docs/embedded/images/ctaux1.png b/docs/embedded/images/ctaux1.png new file mode 100644 index 000000000..c5ff77540 Binary files /dev/null and b/docs/embedded/images/ctaux1.png differ diff --git a/docs/embedded/images/ctaux10.png b/docs/embedded/images/ctaux10.png new file mode 100644 index 000000000..d60b84e5d Binary files /dev/null and b/docs/embedded/images/ctaux10.png differ diff --git a/docs/embedded/images/ctaux11.png b/docs/embedded/images/ctaux11.png new file mode 100644 index 000000000..01dc83bc0 Binary files /dev/null and b/docs/embedded/images/ctaux11.png differ diff --git a/docs/embedded/images/ctaux12.png b/docs/embedded/images/ctaux12.png new file mode 100644 index 000000000..b7f53ffed Binary files /dev/null and b/docs/embedded/images/ctaux12.png differ diff --git a/docs/embedded/images/ctaux13.png b/docs/embedded/images/ctaux13.png new file mode 100644 index 000000000..e77fd7b11 Binary files /dev/null and b/docs/embedded/images/ctaux13.png differ diff --git a/docs/embedded/images/ctaux14.png b/docs/embedded/images/ctaux14.png new file mode 100644 index 000000000..b62786140 Binary files /dev/null and b/docs/embedded/images/ctaux14.png differ diff --git a/docs/embedded/images/ctaux15-n.png b/docs/embedded/images/ctaux15-n.png new file mode 100644 index 000000000..c534fae69 Binary files /dev/null and b/docs/embedded/images/ctaux15-n.png differ diff --git a/docs/embedded/images/ctaux2.png b/docs/embedded/images/ctaux2.png new file mode 100644 index 000000000..3c5dac782 Binary files /dev/null and b/docs/embedded/images/ctaux2.png differ diff --git a/docs/embedded/images/ctaux3.png b/docs/embedded/images/ctaux3.png new file mode 100644 index 000000000..88728dc03 Binary files /dev/null and b/docs/embedded/images/ctaux3.png differ diff --git a/docs/embedded/images/ctaux4.png b/docs/embedded/images/ctaux4.png new file mode 100644 index 000000000..5c06e1b4f Binary files /dev/null and b/docs/embedded/images/ctaux4.png differ diff --git a/docs/embedded/images/ctaux5.png b/docs/embedded/images/ctaux5.png new file mode 100644 index 000000000..4ca1d7238 Binary files /dev/null and b/docs/embedded/images/ctaux5.png differ diff --git a/docs/embedded/images/ctaux6.png b/docs/embedded/images/ctaux6.png new file mode 100644 index 000000000..ab0b73ff8 Binary files /dev/null and b/docs/embedded/images/ctaux6.png differ diff --git a/docs/embedded/images/ctaux7.png b/docs/embedded/images/ctaux7.png new file mode 100644 index 000000000..d5f841cc6 Binary files /dev/null and b/docs/embedded/images/ctaux7.png differ diff --git a/docs/embedded/images/ctaux8.png b/docs/embedded/images/ctaux8.png new file mode 100644 index 000000000..48e3c9b4e Binary files /dev/null and b/docs/embedded/images/ctaux8.png differ diff --git a/docs/embedded/images/ctaux9.png b/docs/embedded/images/ctaux9.png new file mode 100644 index 000000000..233cded62 Binary files /dev/null and b/docs/embedded/images/ctaux9.png differ diff --git a/docs/embedded/images/enable1.png b/docs/embedded/images/enable1.png new file mode 100644 index 000000000..e6f7a30d3 Binary files /dev/null and b/docs/embedded/images/enable1.png differ diff --git a/docs/embedded/images/enable2.png b/docs/embedded/images/enable2.png new file mode 100644 index 000000000..d3bcbbfa2 Binary files /dev/null and b/docs/embedded/images/enable2.png differ diff --git a/docs/embedded/images/enable3.png b/docs/embedded/images/enable3.png new file mode 100644 index 000000000..52f0cd78e Binary files /dev/null and b/docs/embedded/images/enable3.png differ diff --git a/docs/embedded/images/enable4.png b/docs/embedded/images/enable4.png new file mode 100644 index 000000000..3bd2d76ee Binary files /dev/null and b/docs/embedded/images/enable4.png differ diff --git a/docs/embedded/images/enable5.png b/docs/embedded/images/enable5.png new file mode 100644 index 000000000..ec852a6ce Binary files /dev/null and b/docs/embedded/images/enable5.png differ diff --git a/docs/embedded/images/featuretbl.png b/docs/embedded/images/featuretbl.png new file mode 100644 index 000000000..e2cf7c5df Binary files /dev/null and b/docs/embedded/images/featuretbl.png differ diff --git a/docs/embedded/images/filter-on-delete.png b/docs/embedded/images/filter-on-delete.png new file mode 100644 index 000000000..87599873d Binary files /dev/null and b/docs/embedded/images/filter-on-delete.png differ diff --git a/docs/embedded/images/filter.png b/docs/embedded/images/filter.png new file mode 100644 index 000000000..6f1eacbeb Binary files /dev/null and b/docs/embedded/images/filter.png differ diff --git a/docs/embedded/images/itemcount.png b/docs/embedded/images/itemcount.png new file mode 100644 index 000000000..5ceb712fe Binary files /dev/null and b/docs/embedded/images/itemcount.png differ diff --git a/docs/embedded/images/ngrok-registration.png b/docs/embedded/images/ngrok-registration.png new file mode 100644 index 000000000..86c133609 Binary files /dev/null and b/docs/embedded/images/ngrok-registration.png differ diff --git a/docs/embedded/images/office1.png b/docs/embedded/images/office1.png new file mode 100644 index 000000000..8ff7d3ba9 Binary files /dev/null and b/docs/embedded/images/office1.png differ diff --git a/docs/embedded/images/office2.png b/docs/embedded/images/office2.png new file mode 100644 index 000000000..3753f7c67 Binary files /dev/null and b/docs/embedded/images/office2.png differ diff --git a/docs/embedded/images/raasflow.png b/docs/embedded/images/raasflow.png new file mode 100644 index 000000000..a23fd1eff Binary files /dev/null and b/docs/embedded/images/raasflow.png differ diff --git a/docs/embedded/images/raaspic2.png b/docs/embedded/images/raaspic2.png new file mode 100644 index 000000000..bd77feabc Binary files /dev/null and b/docs/embedded/images/raaspic2.png differ diff --git a/docs/embedded/images/reassign-user.png b/docs/embedded/images/reassign-user.png new file mode 100644 index 000000000..5ae1447ed Binary files /dev/null and b/docs/embedded/images/reassign-user.png differ diff --git a/docs/embedded/images/remove-user.png b/docs/embedded/images/remove-user.png new file mode 100644 index 000000000..ffa8d357a Binary files /dev/null and b/docs/embedded/images/remove-user.png differ diff --git a/docs/embedded/images/sc1.png b/docs/embedded/images/sc1.png new file mode 100644 index 000000000..7e284f0a5 Binary files /dev/null and b/docs/embedded/images/sc1.png differ diff --git a/docs/embedded/images/sc2.png b/docs/embedded/images/sc2.png new file mode 100644 index 000000000..f621f6df3 Binary files /dev/null and b/docs/embedded/images/sc2.png differ diff --git a/docs/embedded/images/sc3.png b/docs/embedded/images/sc3.png new file mode 100644 index 000000000..62e1623f4 Binary files /dev/null and b/docs/embedded/images/sc3.png differ diff --git a/docs/embedded/images/sc4.png b/docs/embedded/images/sc4.png new file mode 100644 index 000000000..285aa9dad Binary files /dev/null and b/docs/embedded/images/sc4.png differ diff --git a/docs/embedded/images/sc5.png b/docs/embedded/images/sc5.png new file mode 100644 index 000000000..5fb5d3ae5 Binary files /dev/null and b/docs/embedded/images/sc5.png differ diff --git a/docs/embedded/images/sc6.png b/docs/embedded/images/sc6.png new file mode 100644 index 000000000..98fc406ed Binary files /dev/null and b/docs/embedded/images/sc6.png differ diff --git a/docs/embedded/images/sc7.png b/docs/embedded/images/sc7.png new file mode 100644 index 000000000..fb4038ad6 Binary files /dev/null and b/docs/embedded/images/sc7.png differ diff --git a/docs/embedded/images/search.png b/docs/embedded/images/search.png new file mode 100644 index 000000000..02c1c3ffc Binary files /dev/null and b/docs/embedded/images/search.png differ diff --git a/docs/embedded/images/sensitivity-label.png b/docs/embedded/images/sensitivity-label.png new file mode 100644 index 000000000..5180a30a0 Binary files /dev/null and b/docs/embedded/images/sensitivity-label.png differ diff --git a/docs/embedded/images/sorting-on-deleted.png b/docs/embedded/images/sorting-on-deleted.png new file mode 100644 index 000000000..961e81d55 Binary files /dev/null and b/docs/embedded/images/sorting-on-deleted.png differ diff --git a/docs/embedded/images/sorting.png b/docs/embedded/images/sorting.png new file mode 100644 index 000000000..3f495f85c Binary files /dev/null and b/docs/embedded/images/sorting.png differ diff --git a/docs/embedded/images/spe-vscode-marketplace.png b/docs/embedded/images/spe-vscode-marketplace.png new file mode 100644 index 000000000..ac9a383b6 Binary files /dev/null and b/docs/embedded/images/spe-vscode-marketplace.png differ diff --git a/docs/embedded/images/speco-apparch.png b/docs/embedded/images/speco-apparch.png new file mode 100644 index 000000000..ec05874da Binary files /dev/null and b/docs/embedded/images/speco-apparch.png differ diff --git a/docs/embedded/images/speco-appscopingvenn.png b/docs/embedded/images/speco-appscopingvenn.png new file mode 100644 index 000000000..d5727486a Binary files /dev/null and b/docs/embedded/images/speco-appscopingvenn.png differ diff --git a/docs/embedded/images/speco-bound.png b/docs/embedded/images/speco-bound.png new file mode 100644 index 000000000..8f3cff455 Binary files /dev/null and b/docs/embedded/images/speco-bound.png differ diff --git a/docs/embedded/images/speco-cloneproject.png b/docs/embedded/images/speco-cloneproject.png new file mode 100644 index 000000000..4573bdc74 Binary files /dev/null and b/docs/embedded/images/speco-cloneproject.png differ diff --git a/docs/embedded/images/speco-createappsecret.png b/docs/embedded/images/speco-createappsecret.png new file mode 100644 index 000000000..b283b8259 Binary files /dev/null and b/docs/embedded/images/speco-createappsecret.png differ diff --git a/docs/embedded/images/speco-createclientsecret.png b/docs/embedded/images/speco-createclientsecret.png new file mode 100644 index 000000000..37cf20e57 Binary files /dev/null and b/docs/embedded/images/speco-createclientsecret.png differ diff --git a/docs/embedded/images/speco-createcontosocontainer2.png b/docs/embedded/images/speco-createcontosocontainer2.png new file mode 100644 index 000000000..995cd7f88 Binary files /dev/null and b/docs/embedded/images/speco-createcontosocontainer2.png differ diff --git a/docs/embedded/images/speco-createdcontainer.png b/docs/embedded/images/speco-createdcontainer.png new file mode 100644 index 000000000..e429321c4 Binary files /dev/null and b/docs/embedded/images/speco-createdcontainer.png differ diff --git a/docs/embedded/images/speco-feedbackcombined.png b/docs/embedded/images/speco-feedbackcombined.png new file mode 100644 index 000000000..c3d95ef63 Binary files /dev/null and b/docs/embedded/images/speco-feedbackcombined.png differ diff --git a/docs/embedded/images/speco-feedbackmodal.png b/docs/embedded/images/speco-feedbackmodal.png new file mode 100644 index 000000000..ef3b9ab51 Binary files /dev/null and b/docs/embedded/images/speco-feedbackmodal.png differ diff --git a/docs/embedded/images/speco-feedbackthumbsdown.png b/docs/embedded/images/speco-feedbackthumbsdown.png new file mode 100644 index 000000000..d9e3bd0f5 Binary files /dev/null and b/docs/embedded/images/speco-feedbackthumbsdown.png differ diff --git a/docs/embedded/images/speco-ragai.png b/docs/embedded/images/speco-ragai.png new file mode 100644 index 000000000..28b3f3eac Binary files /dev/null and b/docs/embedded/images/speco-ragai.png differ diff --git a/docs/embedded/images/speco-ragm365.png b/docs/embedded/images/speco-ragm365.png new file mode 100644 index 000000000..17a016ff8 Binary files /dev/null and b/docs/embedded/images/speco-ragm365.png differ diff --git a/docs/embedded/images/speco-ragquery.png b/docs/embedded/images/speco-ragquery.png new file mode 100644 index 000000000..b8a52311b Binary files /dev/null and b/docs/embedded/images/speco-ragquery.png differ diff --git a/docs/embedded/images/speco-reacttypescripthomepage.png b/docs/embedded/images/speco-reacttypescripthomepage.png new file mode 100644 index 000000000..b25861791 Binary files /dev/null and b/docs/embedded/images/speco-reacttypescripthomepage.png differ diff --git a/docs/embedded/images/speco-runnpmrunstart.png b/docs/embedded/images/speco-runnpmrunstart.png new file mode 100644 index 000000000..1f26f6395 Binary files /dev/null and b/docs/embedded/images/speco-runnpmrunstart.png differ diff --git a/docs/embedded/images/speco-runsampleapp.png b/docs/embedded/images/speco-runsampleapp.png new file mode 100644 index 000000000..3d3341eaf Binary files /dev/null and b/docs/embedded/images/speco-runsampleapp.png differ diff --git a/docs/embedded/images/speco-setshowsidebartrue.png b/docs/embedded/images/speco-setshowsidebartrue.png new file mode 100644 index 000000000..2b73eac96 Binary files /dev/null and b/docs/embedded/images/speco-setshowsidebartrue.png differ diff --git a/docs/embedded/images/speco-spechatenabled.png b/docs/embedded/images/speco-spechatenabled.png new file mode 100644 index 000000000..87f35bb1b Binary files /dev/null and b/docs/embedded/images/speco-spechatenabled.png differ diff --git a/docs/embedded/images/speco-uncommentchatsidebar.png b/docs/embedded/images/speco-uncommentchatsidebar.png new file mode 100644 index 000000000..ccc7cfd46 Binary files /dev/null and b/docs/embedded/images/speco-uncommentchatsidebar.png differ diff --git a/docs/embedded/images/speco-vscodeclonedproject.png b/docs/embedded/images/speco-vscodeclonedproject.png new file mode 100644 index 000000000..c88e78db4 Binary files /dev/null and b/docs/embedded/images/speco-vscodeclonedproject.png differ diff --git a/docs/embedded/images/speco-vscodeextensiondisablediscovery.png b/docs/embedded/images/speco-vscodeextensiondisablediscovery.png new file mode 100644 index 000000000..d1c9d63d2 Binary files /dev/null and b/docs/embedded/images/speco-vscodeextensiondisablediscovery.png differ diff --git a/docs/embedded/images/vscodeconsentperms.png b/docs/embedded/images/vscodeconsentperms.png new file mode 100644 index 000000000..05d708775 Binary files /dev/null and b/docs/embedded/images/vscodeconsentperms.png differ diff --git a/docs/embedded/images/vscodecontcreate.png b/docs/embedded/images/vscodecontcreate.png new file mode 100644 index 000000000..df87b340f Binary files /dev/null and b/docs/embedded/images/vscodecontcreate.png differ diff --git a/docs/embedded/images/vscodecontname.png b/docs/embedded/images/vscodecontname.png new file mode 100644 index 000000000..9b2c6d17a Binary files /dev/null and b/docs/embedded/images/vscodecontname.png differ diff --git a/docs/embedded/images/vscodeinstall.png b/docs/embedded/images/vscodeinstall.png new file mode 100644 index 000000000..68ea5d36c Binary files /dev/null and b/docs/embedded/images/vscodeinstall.png differ diff --git a/docs/embedded/images/vscodelaunch.png b/docs/embedded/images/vscodelaunch.png new file mode 100644 index 000000000..50ada3175 Binary files /dev/null and b/docs/embedded/images/vscodelaunch.png differ diff --git a/docs/embedded/images/vscodelogin.png b/docs/embedded/images/vscodelogin.png new file mode 100644 index 000000000..b6921c523 Binary files /dev/null and b/docs/embedded/images/vscodelogin.png differ diff --git a/docs/embedded/images/vscoderegister.png b/docs/embedded/images/vscoderegister.png new file mode 100644 index 000000000..5cfb6fb43 Binary files /dev/null and b/docs/embedded/images/vscoderegister.png differ diff --git a/docs/embedded/images/vscodetree.png b/docs/embedded/images/vscodetree.png new file mode 100644 index 000000000..3d7337b18 Binary files /dev/null and b/docs/embedded/images/vscodetree.png differ diff --git a/docs/embedded/images/vsx-images/auth-allow-extension-uri.png b/docs/embedded/images/vsx-images/auth-allow-extension-uri.png new file mode 100644 index 000000000..f71029396 Binary files /dev/null and b/docs/embedded/images/vsx-images/auth-allow-extension-uri.png differ diff --git a/docs/embedded/images/vsx-images/auth-grant-admin-consent-popup.png b/docs/embedded/images/vsx-images/auth-grant-admin-consent-popup.png new file mode 100644 index 000000000..a8b8485e7 Binary files /dev/null and b/docs/embedded/images/vsx-images/auth-grant-admin-consent-popup.png differ diff --git a/docs/embedded/images/vsx-images/auth-redirect.png b/docs/embedded/images/vsx-images/auth-redirect.png new file mode 100644 index 000000000..ee09cc6bb Binary files /dev/null and b/docs/embedded/images/vsx-images/auth-redirect.png differ diff --git a/docs/embedded/images/vsx-images/client-app-logs.png b/docs/embedded/images/vsx-images/client-app-logs.png new file mode 100644 index 000000000..61c81ce0f Binary files /dev/null and b/docs/embedded/images/vsx-images/client-app-logs.png differ diff --git a/docs/embedded/images/vsx-images/fn-api-logs.png b/docs/embedded/images/vsx-images/fn-api-logs.png new file mode 100644 index 000000000..dc0263c40 Binary files /dev/null and b/docs/embedded/images/vsx-images/fn-api-logs.png differ diff --git a/docs/embedded/images/vsx-images/local-tenant-registration-popup.png b/docs/embedded/images/vsx-images/local-tenant-registration-popup.png new file mode 100644 index 000000000..e233afcf7 Binary files /dev/null and b/docs/embedded/images/vsx-images/local-tenant-registration-popup.png differ diff --git a/docs/embedded/images/vsx-images/n10acreate-container.png b/docs/embedded/images/vsx-images/n10acreate-container.png new file mode 100644 index 000000000..6be23f1cc Binary files /dev/null and b/docs/embedded/images/vsx-images/n10acreate-container.png differ diff --git a/docs/embedded/images/vsx-images/n11aname-first-cont.png b/docs/embedded/images/vsx-images/n11aname-first-cont.png new file mode 100644 index 000000000..3a184eb9c Binary files /dev/null and b/docs/embedded/images/vsx-images/n11aname-first-cont.png differ diff --git a/docs/embedded/images/vsx-images/n12arecycle-cont.png b/docs/embedded/images/vsx-images/n12arecycle-cont.png new file mode 100644 index 000000000..6c26b1b20 Binary files /dev/null and b/docs/embedded/images/vsx-images/n12arecycle-cont.png differ diff --git a/docs/embedded/images/vsx-images/n13a-final-home-page.png b/docs/embedded/images/vsx-images/n13a-final-home-page.png new file mode 100644 index 000000000..bb77e35ed Binary files /dev/null and b/docs/embedded/images/vsx-images/n13a-final-home-page.png differ diff --git a/docs/embedded/images/vsx-images/n14postman-c.png b/docs/embedded/images/vsx-images/n14postman-c.png new file mode 100644 index 000000000..86d9b8a80 Binary files /dev/null and b/docs/embedded/images/vsx-images/n14postman-c.png differ diff --git a/docs/embedded/images/vsx-images/n15vsxsa-c.png b/docs/embedded/images/vsx-images/n15vsxsa-c.png new file mode 100644 index 000000000..6391443a2 Binary files /dev/null and b/docs/embedded/images/vsx-images/n15vsxsa-c.png differ diff --git a/docs/embedded/images/vsx-images/n1downloadvsx.png b/docs/embedded/images/vsx-images/n1downloadvsx.png new file mode 100644 index 000000000..94229faf7 Binary files /dev/null and b/docs/embedded/images/vsx-images/n1downloadvsx.png differ diff --git a/docs/embedded/images/vsx-images/n2vsx-signin.png b/docs/embedded/images/vsx-images/n2vsx-signin.png new file mode 100644 index 000000000..fa78d61e6 Binary files /dev/null and b/docs/embedded/images/vsx-images/n2vsx-signin.png differ diff --git a/docs/embedded/images/vsx-images/n3vsx-grant-admin-consent.png b/docs/embedded/images/vsx-images/n3vsx-grant-admin-consent.png new file mode 100644 index 000000000..c6cfd5cdc Binary files /dev/null and b/docs/embedded/images/vsx-images/n3vsx-grant-admin-consent.png differ diff --git a/docs/embedded/images/vsx-images/n4vsx-home-screen.png b/docs/embedded/images/vsx-images/n4vsx-home-screen.png new file mode 100644 index 000000000..6b9a85cae Binary files /dev/null and b/docs/embedded/images/vsx-images/n4vsx-home-screen.png differ diff --git a/docs/embedded/images/vsx-images/n5a-name-ct.png b/docs/embedded/images/vsx-images/n5a-name-ct.png new file mode 100644 index 000000000..aca25d3a8 Binary files /dev/null and b/docs/embedded/images/vsx-images/n5a-name-ct.png differ diff --git a/docs/embedded/images/vsx-images/n6aname-app.png b/docs/embedded/images/vsx-images/n6aname-app.png new file mode 100644 index 000000000..d58360b2a Binary files /dev/null and b/docs/embedded/images/vsx-images/n6aname-app.png differ diff --git a/docs/embedded/images/vsx-images/n7aregister-ct.png b/docs/embedded/images/vsx-images/n7aregister-ct.png new file mode 100644 index 000000000..9ae83ca19 Binary files /dev/null and b/docs/embedded/images/vsx-images/n7aregister-ct.png differ diff --git a/docs/embedded/images/vsx-images/n9alogin-grant-permissions.png b/docs/embedded/images/vsx-images/n9alogin-grant-permissions.png new file mode 100644 index 000000000..a5cdd7fe2 Binary files /dev/null and b/docs/embedded/images/vsx-images/n9alogin-grant-permissions.png differ diff --git a/docs/embedded/images/vsx-images/sample-app-app-secrets-notice.png b/docs/embedded/images/vsx-images/sample-app-app-secrets-notice.png new file mode 100644 index 000000000..1ade7d0fb Binary files /dev/null and b/docs/embedded/images/vsx-images/sample-app-app-secrets-notice.png differ diff --git a/docs/embedded/images/vsx-images/sample-app-create-client-secret.png b/docs/embedded/images/vsx-images/sample-app-create-client-secret.png new file mode 100644 index 000000000..2bddaef4f Binary files /dev/null and b/docs/embedded/images/vsx-images/sample-app-create-client-secret.png differ diff --git a/docs/embedded/images/vsx-images/spe-sample-app-home.png b/docs/embedded/images/vsx-images/spe-sample-app-home.png new file mode 100644 index 000000000..575c8da11 Binary files /dev/null and b/docs/embedded/images/vsx-images/spe-sample-app-home.png differ diff --git a/docs/embedded/overview.md b/docs/embedded/overview.md new file mode 100644 index 000000000..9f707d52e --- /dev/null +++ b/docs/embedded/overview.md @@ -0,0 +1,72 @@ +--- +title: SharePoint Embedded Overview +description: Microsoft SharePoint Embedded is a cloud-based file and document management system suitable for use in any application. SharePoint Embedded is a new API-only solution that enables app developers to harness the power of the Microsoft 365 file and document storage platform for any app, and is suitable for enterprises building line-of-business applications and ISVs building multitenant applications. +ms.date: 08/17/2024 +ms.localizationpriority: high +--- + +# Overview of SharePoint Embedded + +Microsoft SharePoint Embedded is a cloud-based file and document management system suitable for use in any application. SharePoint Embedded is a new API-only solution that enables app developers to harness the power of the Microsoft 365 file and document storage platform for any app, and is suitable for enterprises building line-of-business applications and ISVs building multitenant applications. + +SharePoint Embedded allows you to integrate advanced Microsoft 365 features into your apps including full-featured collaborative functions from Office, Purview's security and compliance tools, and Copilot capabilities. + +> [!IMPORTANT] +> Help us shape the future of SharePoint Embedded! +> Take our [quick survey](https://forms.microsoft.com/r/1YpGd2pAUS) and share your experience! + +## App documents stay in their Microsoft 365 tenant + +When a consumer uses a SharePoint Embedded application in their Microsoft 365 tenant, SharePoint Embedded creates another partition within their tenant. This storage partition doesn't have a user experience and the documents in the partition are only accessible via APIs. This means that all documents will be accessible to the developer’s application, but the documents will only reside in the consumer’s Microsoft 365 tenant. Within this new storage partition inside of a Microsoft 365 tenant, a SharePoint Embedded application can create many "File Storage Containers" for storing content. + +## Introducing File Storage Containers + +SharePoint Embedded applications use Microsoft Graph APIs to store files and documents in a new entity called a "File Storage Container” or Container for short.  If you’re an ISV, your app will create these containers in your customer’s Microsoft 365 tenant, and if you’re an enterprise, your app will create these containers in your own tenant. Each container provides a place to store files - you can think of them as similar to an API-only Document Library in SharePoint, but with some slight differences. Your app can create many of these containers inside each tenant that uses your app, and each container can be granted permissions separately storing many files with multiple terabytes of content. + +SharePoint Embedded containers are dedicated to and accessible by just your app, so the files and documents your app depends on are isolated and secure within that tenant boundary. + +## App-managed content experiences + +By default, the content stored within a Microsoft 365 tenant by a SharePoint Embedded application is only accessible through that owning application. Applications using SharePoint Embedded also provide the user experience layer for accessing and managing content, using some of the rich content capabilities that Microsoft 365 offers such as: + +- Core content management features like support for any file type and folder structure, searching, sharing, automatic versioning, recycle-bin, and more +- Collaboration features like view, edit, and co-authoring Office Word, Excel, and PowerPoint documents in Office Web and Desktop + +SharePoint Embedded is used by several types of applications: + +- Certain Microsoft products use SharePoint Embedded to manage customer content, such as Loop and Designer. +- ISVs can use SharePoint Embedded in their apps to manage content within their customer’s Microsoft 365 tenant +- Enterprises can use SharePoint Embedded to manage and store content within their own Microsoft 365 tenant, but outside of regular Microsoft 365 entitlements + +## Consumer Microsoft 365 settings apply to app documents + +All documents stored in the SharePoint partition created by the SharePoint Embedded app are in the consumer’s Microsoft 365 tenant and therefore are subject to the consumer’s Microsoft 365 tenant settings. + +This includes settings from Microsoft Purview compliance, risk, and security settings, documents can be opened from Office clients, and customers can use the Office web clients to view and collaborate on the documents. Choosing applications that are built on SharePoint Embedded provides the app consumer Microsoft Purview security and compliance capabilities on that app content, such as: + +- eDiscovery +- Auditing +- Data loss prevention (DLP) +- Retention policies, sensitivity labels, conditional access + +## Understanding the costs and billing for SharePoint Embedded content + +Microsoft 365 customers have different entitlements related to storage, usage, and features depending on the licenses the customer has purchased. + +The partition created in the consumer’s Microsoft 365 tenant by a SharePoint Embedded app doesn’t count towards other Microsoft 365 entitlements including the total amount of Microsoft SharePoint storage that can be used by your organization. Instead, the partition in the consumer’s Microsoft 365 tenant by the SharePoint Embedded app are billed separately through an Azure subscription on a pay-as-you-go metered consumption model that’s based on total storage and the number of API calls. + +> [!NOTE] +> Learn more about billing for SharePoint Embedded, see [Billing Meters](./administration/billing/meters.md). + +## Get Started with SharePoint Embedded + +[Review the prerequisites](./administration/billing/billing.md) + +Create a "File Storage Container" in 15 minutes or less: + +- [Free trial: SharePoint Embedded for Visual Studio Code](./getting-started/spembedded-for-vscode.md) + +Follow manual set-up on SharePoint Embedded from the following Microsoft Learning modules: + +- [Microsoft Learning: SharePoint Embedded - overview & configuration](/training/modules/sharepoint-embedded-setup) +- [Microsoft Learning: SharePoint Embedded - building applications](/training/modules/sharepoint-embedded-create-app) diff --git a/docs/embedded/scenarios-and-use-cases.md b/docs/embedded/scenarios-and-use-cases.md new file mode 100644 index 000000000..2c199f287 --- /dev/null +++ b/docs/embedded/scenarios-and-use-cases.md @@ -0,0 +1,71 @@ +--- +title: Scenarios and Use Cases +description: Scenarios and Use Cases for SharePoint Embedded +ms.date: 05/21/2024 +ms.localizationpriority: high +--- + +# Scenarios and use cases for SharePoint Embedded + +Use these example scenarios to prompt ideas about how custom applications can use SharePoint Embedded. + +> [!NOTE] +> This article is not intended to be an exhaustive list of all SharePoint Embedded features and scenarios. The intention is that these scenarios are contextualized examples of how combinations of features can be used. + +## Scenario: Structured user experience + +### Description + +Where your application requires a guided user experience to make users work in a structured way, rather than the flexible experience of SharePoint. + +Where your application is enabling a business-critical or time sensitive process, use the dedicated resource allocation of SharePoint Embedded to simplify management of throttling. + +### Examples + +- Extended Relationship Management (XRM) applications +- Engagement-based applications +- Workflow-based collaboration, with defined state + +### Why use SharePoint Embedded instead of SharePoint? + +- Your application is the only user interface, allowing you to create a prescriptive user experience +- Resources are separate from your Microsoft 365 entitlements– allowing for simpler resource management. + +## Scenario: Highly controlled collaboration + +### Description + +When building applications on top of SharePoint, it will still be possible for a user with permissions to navigate to the underlying site. Based on their permission level, a user might complete actions in the SharePoint interface that weren't intended by your application, for example changing site settings. These actions might have unintended consequences for your application or content. + +Because SharePoint Embedded is headless, there's no user interface other than what is provided by your custom application. If you don't supply a method to change content or settings through your application, then it won’t be possible for a user to circumvent this through SharePoint. You have the choice for which collaborative features are available in your application, for example sharing. + +### Examples + +- Deal room applications +- Shared research environments + +### Why use SharePoint Embedded instead of SharePoint? + +- You need the collaborative capabilities of SharePoint, only via a highly customized user interface +- You're handling high-value content, where you want to manage risk by removing abilities for a user to discover or alter the content repository +- All containers for the application can share default sharing settings that are separate from your OneDrive and SharePoint settings +- Content is logically separated from other Microsoft 365 content + +## Scenario: Customer facing document upload + +### Description + +Your application is aimed at an end customer, either within your organization or externally, who needs to upload a file as part of their interaction. You require a simplified end-user experience in your custom application, along with the Microsoft 365 capabilities of document storage and compliance. + +Using SharePoint Embedded will support this scenario, while not requiring the users of your application to have access or entitlement to your Microsoft 365 tenant. + +### Examples + +- Applying evidence to mortgage application +- Identity document verification + +### Why use SharePoint Embedded instead of SharePoint? + +- It's critical to segregate this data from the rest of your Microsoft 365 storage, while still being in scope for compliance tools like eDiscovery +- No Microsoft 365 licensing is required for users, or the use of external users in SharePoint +- Containers offer a simple, flexible unit of data storage diff --git a/docs/embedded/whats-new.md b/docs/embedded/whats-new.md new file mode 100644 index 000000000..4a0ba7af0 --- /dev/null +++ b/docs/embedded/whats-new.md @@ -0,0 +1,19 @@ +--- +title: What's new in SharePoint Embedded? +description: Updates about Microsoft SharePoint Embedded. +ms.date: 06/23/2025 +ms.localizationpriority: medium +--- + +# What's new in SharePoint Embedded + +## June 2025 + +- The `CopilotEmbeddedChatHosts` container type setting is now required to use [SharePoint Embedded agent](./development/declarative-agent/spe-da-adv.md#csp-policies). It must be set by the application owner via [`Set-SPOContainerTypeConfiguration`](/powershell/module/sharepoint-online/set-spocontainertypeconfiguration) and can optionally be overridden by consuming tenant administrators via [`Set-SPOApplication`](/powershell/module/SharePoint-online/set-spoapplication). + +## May 2025 + +- The limit of container types that a partner tenant can create has been increased to 25 by default. See [Limits and Calling Patterns](./development/limits-calling.md#size-limits). +- SharePoint Embedded agent switched to a consumption-based model for all users regardless of whether they have a Copilot license or not. See [SharePoint Embedded agent](./development/declarative-agent/spe-da.md). +- The guidance on how to grant admin consent to a SharePoint Embedded application has been updated to use URL-based admin consent. See [Authentication and authorization](./development/auth.md#whats-next). +- Documented an exceptional access pattern for operations that may require a user license. See [Authentication and authorization](./development/auth.md#operations-that-require-a-user-license). diff --git a/docs/features/embed-pages-to-teams.md b/docs/features/embed-pages-to-teams.md index 83ae47ad3..a4085809f 100644 --- a/docs/features/embed-pages-to-teams.md +++ b/docs/features/embed-pages-to-teams.md @@ -1,13 +1,13 @@ --- -title: Embedding modern SharePoint pages in Microsoft Teams as personal apps (preview) +title: Embedding modern SharePoint pages in Microsoft Teams as personal apps description: SharePoint pages can be embedded as personal apps in the Microsoft Teams. -ms.date: 04/20/2021 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- -# Embedding modern SharePoint pages in Microsoft Teams as personal apps (preview) +# Embedding modern SharePoint pages in Microsoft Teams as personal apps _**Applies to:** Microsoft 365_ ->[!Important] -> When you are planning to embed SharePoint sites in Microsoft Teams, please use the [Viva Connections Desktop model](/SharePoint/viva-connections) for the optimal experience. +> [!Important] +> When you are planning to embed SharePoint sites in Microsoft Teams, please use the [Viva Connections model](/sharepoint/guide-to-setting-up-viva-connections) for the supported experience. diff --git a/docs/features/groupify/groupify-csom.md b/docs/features/groupify/groupify-csom.md index be5adaac1..32e38e055 100644 --- a/docs/features/groupify/groupify-csom.md +++ b/docs/features/groupify/groupify-csom.md @@ -1,8 +1,8 @@ --- title: Connect to new Microsoft 365 group - CSOM development description: Client-side object model development for connecting to a new Microsoft 365 group operation. -ms.date: 11/18/2020 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Connect to new Microsoft 365 group: CSOM development @@ -23,7 +23,7 @@ You also need to reference the [Microsoft.SharePointOnline.CSOM](https://www.nug ## CSOM code example -The following example shows how to create a __Microsoft.Online.SharePoint.TenantAdministration.Tenant__ object and call the __CreateGroupForSite__ method to return a list of themes. +The following example shows how to create a __Microsoft.Online.SharePoint.TenantAdministration.Tenant__ object and call the __CreateGroupForSite__ method to return a list of themes. > [!NOTE] > * The URL used to create the context object includes the _-admin_ suffix, because **TenantAdministration** methods work with the admin site. @@ -84,6 +84,3 @@ __type:__ Microsoft.Online.SharePoint.TenantAdministration.GroupCreationParams - When using POST to update a hub site with new information, use the following additional header values: | Header | Value | @@ -63,8 +61,7 @@ For GET, no request body is needed. When using POST to update a hub site with ne #### Sample request ```HTTP -GET -https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-499c-92db-38800eefbe44' +GET https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-499c-92db-38800eefbe44' ``` #### Sample response @@ -73,19 +70,19 @@ https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-49 ```JSON { - "@odata.context": "https://contoso.sharepoint.com/_api/$metadata#hubsites/$entity", - "@odata.type": "#SP.HubSite", - "@odata.id": "https://contoso.sharepoint.com/_api/HubSites/GetById", - "@odata.etag": "\"3\"", - "@odata.editLink": "HubSites/GetById", - "Description": null, - "ID": "f93eff08-5806-499c-92db-38800eefbe44", - "LogoUrl": "https://contoso.sharepoint.com/sites/marketing/SiteAssets/__hubLogo____hubLogo__.png", - "SiteId": "f93eff08-5806-499c-92db-38800eefbe44", - "SiteUrl": "https://contoso.sharepoint.com/sites/marketing", - "Targets": "", - "TenantInstanceId": "00000000-0000-0000-0000-000000000000", - "Title": "" + "@odata.context": "https://contoso.sharepoint.com/_api/$metadata#hubsites/$entity", + "@odata.type": "#SP.HubSite", + "@odata.id": "https://contoso.sharepoint.com/_api/HubSites/GetById", + "@odata.etag": "\"3\"", + "@odata.editLink": "HubSites/GetById", + "Description": null, + "ID": "f93eff08-5806-499c-92db-38800eefbe44", + "LogoUrl": "https://contoso.sharepoint.com/sites/marketing/SiteAssets/__hubLogo____hubLogo__.png", + "SiteId": "f93eff08-5806-499c-92db-38800eefbe44", + "SiteUrl": "https://contoso.sharepoint.com/sites/marketing", + "Targets": "", + "TenantInstanceId": "00000000-0000-0000-0000-000000000000", + "Title": "" } ``` @@ -94,8 +91,7 @@ https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-49 #### Sample request ```HTTP -POST -https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-499c-92db-38800eefbe44' +POST https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-499c-92db-38800eefbe44' ``` #### Sample response @@ -110,6 +106,28 @@ https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-49 } ``` +### Associate a hub with another hub (parent hub association) + +#### Sample request + +```HTTP +POST https://contoso.sharepoint.com/_api/HubSites/GetById('f93eff08-5806-499c-92db-38800eefbe44') +``` + +```JSON +{ + "__metadata": { "type": "SP.HubSite" }, + "Title":"Marketing hub site", + "LogoUrl": "https://contoso.sharepoint.com/sites/marketing/SiteAssets/__hubLogo____hubLogo__.png", + "Description": "Hub site for marketing coordination", + "ParentHubSiteId":"269da5d4-6a9e-45a5-9502-a74d14977293" +} +``` + +#### Sample response + +**Status code:** 204 + ## See also - [Hub site REST API](hub-site-rest-api.md) diff --git a/docs/features/hub-site/REST-hubsitedata-method.md b/docs/features/hub-site/REST-hubsitedata-method.md index aba75ce34..9d0911b2d 100644 --- a/docs/features/hub-site/REST-hubsitedata-method.md +++ b/docs/features/hub-site/REST-hubsitedata-method.md @@ -1,8 +1,8 @@ --- title: HubSiteData REST method description: Gets hub site data for the current web. -ms.date: 6/18/2019 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # HubSiteData diff --git a/docs/features/hub-site/REST-hubsites-method.md b/docs/features/hub-site/REST-hubsites-method.md index c19a5fbcd..5db692961 100644 --- a/docs/features/hub-site/REST-hubsites-method.md +++ b/docs/features/hub-site/REST-hubsites-method.md @@ -1,8 +1,8 @@ --- title: HubSites REST method description: Gets information about all hub sites that the current user can access. -ms.date: 6/18/2019 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # HubSites diff --git a/docs/features/hub-site/REST-joinhubsite-method.md b/docs/features/hub-site/REST-joinhubsite-method.md index ab84427dd..0962b6db4 100644 --- a/docs/features/hub-site/REST-joinhubsite-method.md +++ b/docs/features/hub-site/REST-joinhubsite-method.md @@ -1,8 +1,8 @@ --- title: JoinHubSite REST method description: Associates a site with an existing hub site. You can also use this method to disassociate a site from a hub site. -ms.date: 6/18/2019 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # JoinHubSite diff --git a/docs/features/hub-site/REST-registerhubsite.method.md b/docs/features/hub-site/REST-registerhubsite.method.md index 4ee23cc85..50a8a7d82 100644 --- a/docs/features/hub-site/REST-registerhubsite.method.md +++ b/docs/features/hub-site/REST-registerhubsite.method.md @@ -1,8 +1,8 @@ --- title: RegisterHubSite REST method description: Registers an existing site as a hub site. -ms.date: 6/18/2019 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # RegisterHubSite diff --git a/docs/features/hub-site/REST-sphubsite-type.md b/docs/features/hub-site/REST-sphubsite-type.md index 394429cf4..36cfaad0d 100644 --- a/docs/features/hub-site/REST-sphubsite-type.md +++ b/docs/features/hub-site/REST-sphubsite-type.md @@ -1,8 +1,8 @@ --- title: SPHubSite object type -description: Contains data describing a SharePoint hub site. -ms.date: 6/18/2019 -localization_priority: Normal +description: The SPHubSite object type contains data describing a SharePoint hub site. +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # SPHubSite object type diff --git a/docs/features/hub-site/REST-sphubsitedata-type.md b/docs/features/hub-site/REST-sphubsitedata-type.md index 45014adc6..6457fbd56 100644 --- a/docs/features/hub-site/REST-sphubsitedata-type.md +++ b/docs/features/hub-site/REST-sphubsitedata-type.md @@ -1,8 +1,8 @@ --- title: SPHubSiteData object type -description: Contains data describing a SharePoint hub site. -ms.date: 6/18/2019 -localization_priority: Normal +description: The SPHubSiteData object type contains data describing a SharePoint hub site. +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # SPHubSiteData object type diff --git a/docs/features/hub-site/REST-synchubsitetheme-method.md b/docs/features/hub-site/REST-synchubsitetheme-method.md index 545e974ba..9980cfe9d 100644 --- a/docs/features/hub-site/REST-synchubsitetheme-method.md +++ b/docs/features/hub-site/REST-synchubsitetheme-method.md @@ -1,13 +1,13 @@ --- title: SyncHubSiteTheme REST method description: Applies any theme updates from the parent hub site. -ms.date: 6/18/2019 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # SyncHubSiteTheme -Applies any theme updates from the parent hub site. +Applies any theme updates from the parent hub site. ## HTTP request diff --git a/docs/features/hub-site/REST-unregisterhubsite-method.md b/docs/features/hub-site/REST-unregisterhubsite-method.md index 787f462fb..bc676626d 100644 --- a/docs/features/hub-site/REST-unregisterhubsite-method.md +++ b/docs/features/hub-site/REST-unregisterhubsite-method.md @@ -1,16 +1,13 @@ --- title: UnRegisterHubSite REST method description: Unregisters a hub site so that it is no longer a hub site. -ms.date: 4/20/2018 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # UnRegisterHubSite -> [!IMPORTANT] -> The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments. - -Unregisters a hub site so that it is no longer a hub site. It will become a regular site. Any sites associated with the hub site will no longer be associated. This can take up to an hour to propagate. If you want to speed up the process, first remove any associated sites before unregistering the hub site. +Unregisters a hub site so that it is no longer a hub site. It will become a regular site. Any sites associated with the hub site will no longer be associated. This can take up to an hour to propagate. If you want to speed up the process, first remove any associated sites before unregistering the hub site. ## HTTP request diff --git a/docs/features/hub-site/create-hub-site-with-powershell.md b/docs/features/hub-site/create-hub-site-with-powershell.md index 97004b833..16c183783 100644 --- a/docs/features/hub-site/create-hub-site-with-powershell.md +++ b/docs/features/hub-site/create-hub-site-with-powershell.md @@ -1,23 +1,24 @@ --- title: Create SharePoint hub sites using PowerShell description: Example code for creating a SharePoint hub site by using PowerShell. -ms.date: 11/18/2020 -localization_priority: Priority +ms.date: 04/23/2025 +ms.localizationpriority: high --- # Create SharePoint hub sites by using PowerShell If you're a global or SharePoint admin in Office 365, you can convert any existing site to a hub site by using Microsoft PowerShell. In this example, you'll learn how to create a SharePoint hub site and to associate another site with it. In this scenario, you are setting up sites for the Contoso marketing department: + - You will create a hub site that all other marketing sites will be associated with. - You will then specify settings and permissions for the hub site. -- Finally, you will create a second site and associate it with the hub site. +- Finally, you will create a second site and associate it with the hub site. > [!NOTE] > To work with this example in SharePoint Online, we recommend that you use a developer tenant and not your production tenant. All of the following steps use a fictional tenant named "Contoso" that you can replace with your tenant name. ## Using PnP PowerShell -The samples below can be performed using [PnP PowerShell](https://www.powershellgallery.com/packages/SharePointPnPPowerShellOnline). +The samples below can be performed using [PnP PowerShell](https://www.powershellgallery.com/packages/PnP.PowerShell). > [!NOTE] > In the remainder of this exercise, **contoso** will be used as the tenant name. Continue to use your own tenant name in place of **contoso**. @@ -28,29 +29,29 @@ The samples below can be performed using [PnP PowerShell](https://www.powershell First, we will create the marketing site that will serve as a hub site that other sites can associate with. The intent is that any sites that are marketing-oriented will be part of the hub site. This applies common navigation and branding across the associated sites, enables team members to search across all the sites associated with the single hub site, and takes advantage of other hub site features. -1. Connect to the SharePoint Online Admin center using: +1. Connect to the SharePoint Online Admin center using interactive login and [registered Azure AD (Entra ID)](https://pnp.github.io/powershell/articles/registerapplication.html) application: - ```powershell - Connect-PnPOnline -Url https://contoso-admin.sharepoint.com -UseWebLogin - ``` + ```powershell + Connect-PnPOnline -Url https://contoso-admin.sharepoint.com -Interactive -ClientId + ``` -2. Create the site to be used as a hub site using the [New-PnPSite](/powershell/module/sharepoint-pnp/new-pnpsite) cmdlet: +1. Create the site to be used as a hub site using the [New-PnPSite](https://pnp.github.io/powershell/cmdlets/New-PnPSite.html) cmdlet: - ```powershell - New-PnPSite -Type TeamSite -Title "Contoso marketing division" -Alias "marketing" -Description "Main site for collaboration for marketing teams at Contoso" - ``` + ```powershell + New-PnPSite -Type TeamSite -Title "Contoso marketing division" -Alias "marketing" -Description "Main site for collaboration for marketing teams at Contoso" + ``` - The cmdlet returns the URL of the new site similar to the following: + The cmdlet returns the URL of the new site similar to the following: - ``` - https://contoso.sharepoint.com/sites/marketing - ``` + ```http + https://contoso.sharepoint.com/sites/marketing + ``` -3. Register the new marketing site as a hub site by using the [Register-SPOHubSite](/powershell/module/sharepoint-online/register-spohubsite) cmdlet: +1. Register the new marketing site as a hub site by using the [Register-PnPHubSite](https://pnp.github.io/powershell/cmdlets/Register-PnPHubSite.html) cmdlet: - ```powershell - Register-SPOHubSite -Site https://contoso.sharepoint.com/sites/marketing - ``` + ```powershell + Register-PnPHubSite -Site https://contoso.sharepoint.com/sites/marketing + ``` ## Set properties and permissions on the hub site @@ -58,58 +59,56 @@ The hub site doesn't have a logo or description yet. We also want to constrain i ### Set properties -1. Upload a logo image for the site by going to `https://contoso.sharepoint.com/sites/marketing/SiteAssets` and uploading any image you like. Make a note of the image file name. - -2. Use the [Set-PnPHubSite](/powershell/module/sharepoint-pnp/set-pnphubsite) cmdlet to set the logo and description. In place of `mylogo.jpg`, specify the name of the image that you uploaded: +1. Upload a logo image for the site by going to `https://contoso.sharepoint.com/sites/marketing/SiteAssets` and uploading any image you like. Make a note of the image file name. +1. Use the [Set-PnPHubSite](https://pnp.github.io/powershell/cmdlets/Set-PnPHubSite.html) cmdlet to set the logo and description. In place of `mylogo.jpg`, specify the name of the image that you uploaded: - ```powershell - Set-PnPHubSite - -Identity https://contoso.sharepoint.com/sites/marketing - -LogoUrl https://contoso.sharepoint.com/sites/marketing/SiteAssets/mylogo.jpg - -Description "Main hub site for collaboration on marketing activities across Contoso" - ``` + ```powershell + Set-PnPHubSite + -Identity https://contoso.sharepoint.com/sites/marketing + -LogoUrl https://contoso.sharepoint.com/sites/marketing/SiteAssets/mylogo.jpg + -Description "Main hub site for collaboration on marketing activities across Contoso" + ``` ### Set permissions Now we will restrict access so that only the user `nestorw@contoso.com` can make changes to the hub site associations. -- Run the [Grant-PnPHubSiteRights](/powershell/module/sharepoint-pnp/grant-pnphubsiterights) cmdlet to grant a user rights to the marketing hub site. We'll use `nestorw@contoso` in this example, but you can use any valid user on your tenant (you can specify multiple users by separating them with a comma): +- Run the [Grant-PnPHubSiteRights](https://pnp.github.io/powershell/cmdlets/Grant-PnPHubSiteRights.html) cmdlet to grant a user rights to the marketing hub site. We'll use `nestorw@contoso` in this example, but you can use any valid user on your tenant (you can specify multiple users by separating them with a comma): - ```powershell - Grant-PnPHubSiteRights -Identity https://contoso.sharepoint.com/sites/marketing -Principals "nestorw@contoso" -Rights Join - ``` + ```powershell + Grant-PnPHubSiteRights -Identity https://contoso.sharepoint.com/sites/marketing -Principals "nestorw@contoso" + ``` ## Create and associate a new site The final step is to create the site we want to associate with the hub. You can repeat these steps for as many sites as you want to join to the hub. -1. Provision the site by using the [New-PnPSite](/powershell/module/sharepoint-pnp/new-pnpsite) cmdlet: - - ```powershell - New-PnPSite -Type TeamSite -Title "Online advertising team" -Alias "online-advertising" -Description "For collaboration on online advertising resources" - ``` - - The cmdlet returns the URL of the new site similar to the following: - - ``` +1. Provision the site by using the [New-PnPSite](https://pnp.github.io/powershell/cmdlets/New-PnPSite.html) cmdlet: + + ```powershell + New-PnPSite -Type TeamSite -Title "Online advertising team" -Alias "online-advertising" -Description "For collaboration on online advertising resources" + ``` + + The cmdlet returns the URL of the new site similar to the following: + + ```http: https://contoso.sharepoint.com/sites/online-advertising - ``` - -2. Associate this site with the hub site by using the [Add-PnPHubSiteAssociation](/powershell/module/sharepoint-pnp/add-pnphubsiteassociation) cmdlet: - - ```powershell - Add-PnPHubSiteAssociation - -Site https://contoso.sharepoint.com/sites/online-advertising - -HubSite https://contoso.sharepoint.com/sites/marketing - ``` + ``` + +1. Associate this site with the hub site by using the [Add-PnPHubSiteAssociation](https://pnp.github.io/powershell/cmdlets/Add-PnPHubSiteAssociation.html) cmdlet: + + ```powershell + Add-PnPHubSiteAssociation + -Site https://contoso.sharepoint.com/sites/online-advertising + -HubSite https://contoso.sharepoint.com/sites/marketing + ``` ## Confirm the hub site is working To confirm, you can either: -- Run the [Get-PnPHubSite](/powershell/module/sharepoint-pnp/get-pnphubsite) cmdlet. - -- Sign in to SharePoint Online and view the hub site directly at `https://contoso.sharepoint.com/sites/marketing`. +- Run the [Get-PnPHubSite](https://pnp.github.io/powershell/cmdlets/Get-PnPHubSite.html) cmdlet. +- Sign in to SharePoint Online and view the hub site directly at `https://contoso.sharepoint.com/sites/marketing`. The hub site navigation appears at the top of the site. If you go to the `https://contoso.sharepoint.com/sites/online-advertising` site, it shows the same hub site navigation at the top. diff --git a/docs/features/hub-site/hub-site-o365cli.md b/docs/features/hub-site/hub-site-o365cli.md index 6dd2830a2..2ecea1787 100644 --- a/docs/features/hub-site/hub-site-o365cli.md +++ b/docs/features/hub-site/hub-site-o365cli.md @@ -1,8 +1,8 @@ --- title: CLI for Microsoft 365 commands for SharePoint hub sites description: Use CLI for Microsoft 365 to create and manage SharePoint hub sites. -ms.date: 06/05/2020 -localization_priority: Priority +ms.date: 06/27/2024 +ms.localizationpriority: high --- # CLI for Microsoft 365 commands for SharePoint hub sites @@ -16,10 +16,8 @@ Use the CLI for Microsoft 365 commands to create and manage SharePoint hub sites To run the CLI for Microsoft 365 commands, you'll need to do the following: 1. Download and install [NodeJS LTS version](https://nodejs.org/en/) - -2. Follow the instructions at [Installing the CLI](https://pnp.github.io/cli-microsoft365/user-guide/installing-cli/) to install the CLI for Microsoft 365 on your machine - -3. Follow the instructions at [Logging in to Office 365](https://pnp.github.io/cli-microsoft365/user-guide/connecting-office-365/) to connect to your SharePoint tenant. +1. Follow the instructions at [Installing the CLI](https://pnp.github.io/cli-microsoft365/user-guide/installing-cli/) to install the CLI for Microsoft 365 on your machine +1. Follow the instructions at [Logging in to Office 365](https://pnp.github.io/cli-microsoft365/user-guide/connecting-microsoft-365) to connect to your SharePoint tenant. To verify your setup and connection, try using the [hubsite list](https://pnp.github.io/cli-microsoft365/cmd/spo/hubsite/hubsite-list/) command to list the current hub sites. If the cmdlet runs and returns with no errors, you're ready to proceed. @@ -38,7 +36,7 @@ The following commands are available for managing hub sites: |[hubsite rights grant](https://pnp.github.io/cli-microsoft365/cmd/spo/hubsite/hubsite-rights-grant)| Grants permissions to join the hub site for one or more principals | |[hubsite rights revoke](https://pnp.github.io/cli-microsoft365/cmd/spo/hubsite/hubsite-rights-revoke)| Revokes rights to join sites to the specified hub site for one or more principals | |[hubsite set](https://pnp.github.io/cli-microsoft365/cmd/spo/hubsite/hubsite-set)| Updates properties of the specified hub site | -|[hubsite theme sync](https://pnp.github.io/cli-microsoft365/cmd/spo/hubsite/hubsite-theme-sync)| Applies any theme updates from the parent hub site. | +|[hubsite theme sync](https://pnp.github.io/cli-microsoft365/cmd/spo/site/site-hubsite-theme-sync)| Applies any theme updates from the parent hub site. | |[hubsite unregister](https://pnp.github.io/cli-microsoft365/cmd/spo/hubsite/hubsite-unregister)| Unregisters the specifies site collection as a hub site | ## See also diff --git a/docs/features/hub-site/hub-site-overview.md b/docs/features/hub-site/hub-site-overview.md index 78f7c00ad..dff8662cc 100644 --- a/docs/features/hub-site/hub-site-overview.md +++ b/docs/features/hub-site/hub-site-overview.md @@ -1,8 +1,8 @@ --- title: SharePoint hub sites overview description: SharePoint hub sites connect and organize sites based on organizational attributes such as project, department, division, or region. -ms.date: 4/20/2018 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # SharePoint hub sites overview @@ -17,7 +17,7 @@ For more information about creating hub sites, see [Create SharePoint hub sites - We recommend that you select a communication site or a team site that uses the modern template. If you use a classic team site, the hub site navigation will only appear on modern pages, including document libraries, lists, and site contents. Hub site settings will only appear on modern pages. -- You can create up to 2000 hub sites for an organization. +- You can create up to 2000 hub sites for an organization. - If you set up [SharePoint Multi-Geo](../../solution-guidance/multigeo-introduction.md) for your organization, any geo location where the SharePoint workload is available can be associated with a hub site. diff --git a/docs/features/hub-site/hub-site-powershell.md b/docs/features/hub-site/hub-site-powershell.md index 5e0841e39..58fa78c4d 100644 --- a/docs/features/hub-site/hub-site-powershell.md +++ b/docs/features/hub-site/hub-site-powershell.md @@ -1,8 +1,8 @@ --- title: PowerShell cmdlets for SharePoint hub sites description: Use PowerShell cmdlets to create and manage SharePoint hub sites. -ms.date: 6/18/2019 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # PowerShell cmdlets for SharePoint hub sites @@ -14,8 +14,7 @@ Use PowerShell cmdlets to create and manage SharePoint hub sites. To run the PowerShell cmdlets: 1. Download and install the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588). If you already have a previous version of the shell installed, uninstall it first, and then install the latest version. - -2. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. +1. Follow the instructions at [Connect to SharePoint Online PowerShell](https://technet.microsoft.com/library/fp161372.aspx) to connect to your SharePoint tenant. To verify your setup, try using the **Get-SPOHubSite** cmdlet to read the current list of hub sites. If the cmdlet runs and returns with no errors, you're ready to proceed. diff --git a/docs/features/hub-site/hub-site-rest-api.md b/docs/features/hub-site/hub-site-rest-api.md index d2aa1606d..5f22dbf4b 100644 --- a/docs/features/hub-site/hub-site-rest-api.md +++ b/docs/features/hub-site/hub-site-rest-api.md @@ -1,15 +1,15 @@ --- title: Hub site REST API description: Overview of hub site REST API for creating hub sites and associating existing sites with hub sites. -ms.date: 4/20/2018 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Hub site REST API -You can use the SharePoint REST interface to register sites as hub sites, associate existing sites with hub sites, and obtain or update information about hub sites. +You can use the SharePoint REST interface to register sites as hub sites, associate existing sites with hub sites, and obtain or update information about hub sites. -The SharePoint Online (and SharePoint 2016 and later on-premises) REST service supports combining multiple requests into a single call to the service by using the OData $batch query option. +The SharePoint Online (and SharePoint 2016 and later on-premises) REST service supports combining multiple requests into a single call to the service by using the OData $batch query option. For details and links to code samples, see [Make batch requests with the REST APIs](../../sp-add-ins/make-batch-requests-with-the-rest-apis.md). @@ -17,7 +17,7 @@ For details and links to code samples, see [Make batch requests with the REST AP Before you get started, make sure that you're familiar with the following: -- [Get to know the SharePoint REST service](../../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) +- [Get to know the SharePoint REST service](../../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) - [Complete basic operations using SharePoint REST endpoints](../../sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints.md) ## REST commands @@ -50,4 +50,3 @@ To remove, or disassociate a site from a hub site, call [JoinHubSite](REST-joinh ## See also - [SharePoint hub sites overview](hub-site-overview.md) - diff --git a/docs/features/site-footer.md b/docs/features/site-footer.md index db7f563bf..eb1d37583 100644 --- a/docs/features/site-footer.md +++ b/docs/features/site-footer.md @@ -1,8 +1,8 @@ --- title: Overview of the SharePoint Site footer description: SharePoint Site footers can be used to show a logo or set of links/labels in a modern SharePoint site. They can be configured using the UI settings or by using APIs. -ms.date: 06/06/2020 -localization_priority: Priority +ms.date: 09/24/2023 +ms.localizationpriority: high --- # SharePoint Site Footer @@ -10,13 +10,15 @@ localization_priority: Priority Footers are a common branding / navigation control in websites and portals. SharePoint Communication sites will have an out-of-the box footer control, which can be controlled either using UI elements or by using APIs. This control supports following elements - 8 links or labels -- Footer logo +- Footer logo - Footer name > [!IMPORTANT] -> Footer will be enabled by default for all new communication sites after the feature is rolled out. Along with this update, the content bar (also referred to as the “social bar”) - which contains the Like, Comment, View and Save for Later icons - will be docked permanently on top of the Comments section on all modern pages and news posts. +> Footer will be enabled by default for all new communication sites after the feature is rolled out. Along with this update, the content bar (also referred to as the “social bar”) - which contains the Like, Comment, View and Save for Later icons - will be docked permanently on top of the Comments section on all modern pages and news posts. +> +> Footers don't appear in sites on mobile devices or apps. -## Sample footer +## Sample footer Following picture demonstrates a footer with a logo, footer name and labels and links. @@ -27,12 +29,13 @@ Following picture demonstrates a footer with a logo, footer name and labels and You can control the footer existence with a `FooterEnabled` property in the `Web` object. Following PowerShell scripts shows how this can be done using [PnP PowerShell cmdlets](/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets): ```powershell -Connect-PnPOnline -Url "" –Credentials (Get-Credential) -Set-PnPFooter -Enabled:$false +Connect-PnPOnline -Url "" –Credentials (Get-Credential) +Set-PnPFooter -Enabled:$false # for disabling the footer +Set-PnPFooter -Enabled:$true # for enabling the footer ``` > [!NOTE] -> Above PowerShell scripts assumes that you have already installed PnP PowerShell cmdlets for your environment and you are not using multi-factor authentication. You can install PnP PowerShell cmdlets to your computer by opening PowerShell console in administrative mode and executing following command: `Install-Module SharePointPnPPowerShellOnline`. If you are using multi-factor authentication, you can enable MFA login by updating the `Connect-PnPOnline` line as follows: `Connect-PnPOnline -Url "" -UseWebLogin`. +> Above PowerShell scripts assumes that you have already installed PnP PowerShell cmdlets for your environment and you are not using multi-factor authentication. You can install PnP PowerShell cmdlets to your computer by opening PowerShell console in administrative mode and executing following command: `Install-Module PnP.PowerShell -Scope CurrentUser`. If you are using multi-factor authentication, you can enable MFA login by updating the `Connect-PnPOnline` line as follows: `Connect-PnPOnline -Url "" -Interactive`. [!INCLUDE [pnp-powershell](../../includes/snippets/open-source/pnp-powershell.md)] diff --git a/docs/general-development/access-sharepoint-from-mobile-and-native-device-apps.md b/docs/general-development/access-sharepoint-from-mobile-and-native-device-apps.md index f255dbbfb..bc4e82403 100644 --- a/docs/general-development/access-sharepoint-from-mobile-and-native-device-apps.md +++ b/docs/general-development/access-sharepoint-from-mobile-and-native-device-apps.md @@ -1,9 +1,9 @@ --- title: Access SharePoint from mobile and native device apps -ms.date: 05/01/2020 -ms.prod: sharepoint +description: Describes how to access Sharepoint from mobile apps and other native device apps, and from external web applications. +ms.date: 06/10/2022 ms.assetid: 42014171-5ee5-421d-9cde-413efc3aecef -localization_priority: Priority +ms.localizationpriority: high --- @@ -16,7 +16,7 @@ SharePoint Add-ins, farm solutions, and "no code" sandboxed solutions are all ru > [!IMPORTANT] -> To test and debug on any platform, you need a **developer account on Office 365**. More info: [Set up a development environment for SharePoint Add-ins on Office 365](https://msdn.microsoft.com/library/b22ce52a-ae9e-4831-9b68-c9210af6dc54%28Office.15%29.aspx) or [Create a developer site on an existing Office 365 subscription](https://msdn.microsoft.com/library/2ec857d5-dc6f-4cf6-ba45-adc845ef2a25%28Office.15%29.aspx). +> To test and debug on any platform, you need a **developer account on Office 365**. More info: [Set up a development environment for SharePoint Add-ins on Office 365](/sharepoint/dev/sp-add-ins/set-up-a-development-environment-for-sharepoint-add-ins-on-office-365) or [Create a developer site on an existing Office 365 subscription](https://msdn.microsoft.com/library/2ec857d5-dc6f-4cf6-ba45-adc845ef2a25%28Office.15%29.aspx). @@ -76,5 +76,4 @@ You can build these apps on the ASP.NET platform or a non-Microsoft stack. If yo These apps **gain authorized access to SharePoint data by using access tokens** that are issued by the Azure Control Service (ACS) in compliance with the OAuth Authentication Code flow. For more, see [Authorization Code OAuth flow for SharePoint Add-ins](https://msdn.microsoft.com/library/e89e91c7-ea39-49b9-af5a-7f047a7e2ab7%28Office.15%29.aspx). -> [!IMPORTANT] -> Azure Access Control (ACS), a service of Azure Active Directory (Azure AD), will be retired on November 7, 2018. This retirement does not impact the SharePoint Add-in model, which uses the `https://accounts.accesscontrol.windows.net` hostname (which is not impacted by this retirement). For more information, see [Impact of Azure Access Control retirement for SharePoint Add-ins](https://developer.microsoft.com/office/blogs/impact-of-azure-access-control-deprecation-for-sharepoint-add-ins). +[!INCLUDE [azure-acs-retirement](../../includes/snippets/azure-acs-deprecation.md)] diff --git a/docs/general-development/accessibility-in-sharepoint.md b/docs/general-development/accessibility-in-sharepoint.md index 336a240c1..ea9313596 100644 --- a/docs/general-development/accessibility-in-sharepoint.md +++ b/docs/general-development/accessibility-in-sharepoint.md @@ -2,9 +2,8 @@ title: Accessibility in SharePoint description: Learn about the features, products, and services that make SharePoint accessible for people with disabilities, and find developer resources that can help you design and build apps and websites that support key accessibility scenarios. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: c9106d47-c523-49c1-b9f1-cdd7420abd5e -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/accessing-a-schema.md b/docs/general-development/accessing-a-schema.md index 817750de0..09e945d3b 100644 --- a/docs/general-development/accessing-a-schema.md +++ b/docs/general-development/accessing-a-schema.md @@ -1,9 +1,9 @@ --- title: Accessing a Schema -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This topic shows one example of how you can access and look at a schema for the REST service in Excel Services. +ms.date: 06/03/2022 ms.assetid: 02613912-36f6-4edc-a915-165d12e60bc8 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/accessing-the-soap-api.md b/docs/general-development/accessing-the-soap-api.md index bf09a3c35..5486a00fe 100644 --- a/docs/general-development/accessing-the-soap-api.md +++ b/docs/general-development/accessing-the-soap-api.md @@ -1,12 +1,12 @@ --- title: Accessing the SOAP API -ms.date: 09/25/2017 +description: The SOAP API consists of methods and a set of complex type objects that you can use to access the complete functionality of Excel Web Services. +ms.date: 06/03/2022 keywords: soap f1_keywords: - soap -ms.prod: sharepoint ms.assetid: 36e8e3d5-83ac-4bd3-b556-1af132add3eb -localization_priority: Priority +ms.localizationpriority: high --- @@ -58,7 +58,7 @@ The following table describes each element in the URL. |:-----|:-----| | _server_
|The name of the server on which Microsoft SharePoint Server 2010 is deployed.
| | _customsite_
|A custom SharePoint Server 2010 site that the server administrator creates.
| -| _.asmx_
|The name of the Web service endpoint. For Excel Web Services, it is `ExcelService.asmx`.
| +| _\.asmx_
|The name of the Web service endpoint. For Excel Web Services, it is `ExcelService.asmx`.
| For more information about the WSDL format, see the World Wide Web Consortium (W3C) WSDL specification at http://www.w3.org/TR/wsdl. diff --git a/docs/general-development/add-in-scoped-external-content-types-in-sharepoint.md b/docs/general-development/add-in-scoped-external-content-types-in-sharepoint.md index a34523ee4..9530e038b 100644 --- a/docs/general-development/add-in-scoped-external-content-types-in-sharepoint.md +++ b/docs/general-development/add-in-scoped-external-content-types-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Add-in-scoped external content types in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes external content types that are installed or scoped at the add-in level in SharePoint and enable you to create data-rich SharePoint Add-ins using external data sources. +ms.date: 06/10/2022 ms.assetid: a34cbbba-dc38-4d3d-b796-d54b5848bdfb -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/add-sharepoint-capabilities.md b/docs/general-development/add-sharepoint-capabilities.md index 04de43627..8e62f2328 100644 --- a/docs/general-development/add-sharepoint-capabilities.md +++ b/docs/general-development/add-sharepoint-capabilities.md @@ -1,9 +1,9 @@ --- title: Add SharePoint capabilities -ms.date: 09/25/2017 -ms.prod: sharepoint +ms.date: 06/13/2022 +description: Describes how-to information about adding SharePoint features and capabilities to custom apps. ms.assetid: 11ecb65e-6dc5-4cf1-80ca-3c16418697b6 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/advanced-scenarios-and-additional-samples.md b/docs/general-development/advanced-scenarios-and-additional-samples.md index d98cf4b8f..e24df89fa 100644 --- a/docs/general-development/advanced-scenarios-and-additional-samples.md +++ b/docs/general-development/advanced-scenarios-and-additional-samples.md @@ -2,9 +2,8 @@ title: Advanced Scenarios and Additional Samples description: This topic describes some advanced REST scenarios and additional samples. It provides links to webpages where you can get more detailed information. ms.date: 01/14/2021 -ms.prod: sharepoint ms.assetid: 110bcc88-2b55-4d80-ab5c-dc3b9658e48d -localization_priority: Normal +ms.localizationpriority: medium --- # Advanced Scenarios and Additional Samples diff --git a/docs/general-development/architecture-of-the-windows-phone-sharepoint-list-application-template.md b/docs/general-development/architecture-of-the-windows-phone-sharepoint-list-application-template.md index a97807e2e..dde454c5d 100644 --- a/docs/general-development/architecture-of-the-windows-phone-sharepoint-list-application-template.md +++ b/docs/general-development/architecture-of-the-windows-phone-sharepoint-list-application-template.md @@ -1,9 +1,9 @@ --- title: Architecture of the Windows Phone SharePoint List Application template -ms.date: 09/25/2017 -ms.prod: sharepoint +ms.date: 06/13/2022 +description: Describes the design pattern of projects created from the Windows Phone SharePoint List Application template. ms.assetid: 2c09bd02-bed0-4293-a4d4-1778692e246a -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/authentication-authorization-and-security-in-sharepoint.md b/docs/general-development/authentication-authorization-and-security-in-sharepoint.md index a1c2076f8..c4459f33b 100644 --- a/docs/general-development/authentication-authorization-and-security-in-sharepoint.md +++ b/docs/general-development/authentication-authorization-and-security-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Authentication, authorization, and security in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +ms.date: 06/13/2022 +description: Describes some of the enhancements added to SharePoint including updates in authentication, authorization, and security. ms.assetid: 8734790c-eb75-4d78-9604-7cc23b33b693 -localization_priority: Priority +ms.localizationpriority: high --- @@ -22,7 +22,7 @@ The following are some of the enhancements added to SharePoint: - SharePoint continues to offer support for both claims and classic authentication modes. Claims authentication is the default authentication option in SharePoint. Classic-mode authentication is deprecated and can be managed only by using Windows PowerShell. A lot of features in SharePoint require claims-mode. - - The **MigrateUsers** method from SharePoint 2010 is now deprecated, it's no longer the correct way to migrate accounts. To migrate accounts, use the new Windows PowerShell cmdlet called `Convert-SPWebApplication`. For more information see [Migrate from classic-mode to claims-based authentication in SharePoint](https://docs.microsoft.com/sharepoint/upgrade-and-update/migrate-from-classic-mode-to-claims-based-authentication-in-sharepoint-2013). + - The **MigrateUsers** method from SharePoint 2010 is now deprecated, it's no longer the correct way to migrate accounts. To migrate accounts, use the new Windows PowerShell cmdlet called `Convert-SPWebApplication`. For more information see [Migrate from classic-mode to claims-based authentication in SharePoint](/sharepoint/upgrade-and-update/migrate-from-classic-mode-to-claims-based-authentication-in-sharepoint-2013). - Requirement to register claims providers is eliminated. However, you do have to pre-configure claims type. You can choose the characters for the claim type and there is no enforcement on the ordering of claim types. diff --git a/docs/general-development/authorization-users-groups-and-the-object-model-in-sharepoint.md b/docs/general-development/authorization-users-groups-and-the-object-model-in-sharepoint.md index ad2a82133..c18a7e6da 100644 --- a/docs/general-development/authorization-users-groups-and-the-object-model-in-sharepoint.md +++ b/docs/general-development/authorization-users-groups-and-the-object-model-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Authorization, users, groups, and the object model in SharePoint -ms.date: 11/15/2018 -ms.prod: sharepoint +ms.date: 06/13/2022 +description: Describes authorization, users, groups, and the object model in SharePoint. ms.assetid: aacf3398-f0b5-48cb-9071-440b4c3a9dd1 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/basic-uri-structure-and-path.md b/docs/general-development/basic-uri-structure-and-path.md index 119f42f09..86c10a404 100644 --- a/docs/general-development/basic-uri-structure-and-path.md +++ b/docs/general-development/basic-uri-structure-and-path.md @@ -1,179 +1,92 @@ --- title: Basic URI Structure and Path -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This article provides a link explaining how to construct the URI structure and path for REST service commands in Excel Services. +ms.date: 06/07/2022 ms.assetid: d73cf6c2-0677-4726-8a3e-2ad130e1a12c -localization_priority: Priority +ms.localizationpriority: high --- # Basic URI Structure and Path This topic explains how to construct the URI structure and path for REST service commands in Excel Services. - + > [!NOTE] -> -> The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of the [Microsoft Graph](http://graph.microsoft.io/docs/api-reference/v1.0/resources/excel +> +> The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of the [Microsoft Graph](https://graph.microsoft.io/docs/api-reference/v1.0/resources/excel ) endpoint. - - - - ## Basic URL Structure and Path -The REST API in Excel Services gives you the ability to access resources like charts, PivotTables, tables, and named ranges in a workbook directly through a URL. Each REST URL in Excel Services is built of three parts. Following is the basic structure of the URL to access the resources in a workbook: - - - +The REST API in Excel Services gives you the ability to access resources like charts, PivotTables, tables, and named ranges in a workbook directly through a URL. Each REST URL in Excel Services is built of three parts. Following is the basic structure of the URL to access the resources in a workbook: 1. **REST aspx Page URI** The entry point to an .aspx page - - -2. **Workbook Location** The path to the workbook - - -3. **Resource Location** The path to the requested resource inside the workbook - - -Following is the construct for the REST URL to a specific element in a workbook: - - - - +1. **Workbook Location** The path to the workbook +1. **Resource Location** The path to the requested resource inside the workbook +Following is the construct for the REST URL to a specific element in a workbook: -``` - +```http http:///_vti_bin/ExcelRest.aspx/// ``` Following is an example of how a REST URL in Excel Services looks with all three parts combined. In this example, the REST URL is accessing a workbook called "sampleWorkbook.xlsx" that contains a chart called "SampleChart": - - - - - -``` +```http http:///_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart') ``` -The workbook is stored in a document library. The full path to the workbook is `http://` __ `/Docs/Documents/sampleWorkbook.xlsx`. - - - +The workbook is stored in a document library. The full path to the workbook is `http://` _\_ `/Docs/Documents/sampleWorkbook.xlsx`. + The three parts of the REST URL are: - - - - -1. **REST aspx Page URI**: `http://` __ `/_vti_bin/ExcelRest.aspx` - - -2. **Workbook Location**: `/Docs/Documents/sampleWorkbook.xlsx` - - -3. **Resource Location**: `/model/Ranges('nameOfTheNamedRange')` - - + +1. **REST aspx Page URI**: `http://` _\_ `/_vti_bin/ExcelRest.aspx` +1. **Workbook Location**: `/Docs/Documents/sampleWorkbook.xlsx` +1. **Resource Location**: `/model/Ranges('nameOfTheNamedRange')` ### Accessing by Using the Discovery User Interface You can also access the chart by using the discovery user interface. To learn how access resources like charts, tables, PivotTables, and ranges by using the discovery mechanism shown in the following screen shot, see [Discovery in Excel Services REST API](discovery-in-excel-services-rest-api.md). - - - - - - ![Excel Services REST model URL](../images/SharePointServer14Con_XLSvcs_RESTModel.gif) - - - - - - - - - - - - - - - ### Marker Path Following is the aspx page for the REST service in Excel Services: - - - -``` +```http http:///_vti_bin/ExcelRest.aspx ``` -To access the REST service in Excel Services, you must preface the URL with `http://` __ `/_vti_bin/ExcelRest.aspx`. - - - +To access the REST service in Excel Services, you must preface the URL with `http://` _\_ `/_vti_bin/ExcelRest.aspx`. ### Workbook Location -The workbook location is the relative path to the workbook that has resources that you are interested in accessing. For example, assume that you have a workbook named sampleWorkbook.xlsx, saved to a trusted SharePoint document library. In this example, following is the path to the location of sampleWorkbook.xlsx: - - - +The workbook location is the relative path to the workbook that has resources that you are interested in accessing. For example, assume that you have a workbook named sampleWorkbook.xlsx, saved to a trusted SharePoint document library. In this example, following is the path to the location of sampleWorkbook.xlsx: -``` +```http http:///Docs/Documents/sampleWorkbook.xlsx ``` You take the relative path to the workbook ( `Docs/Documents/sampleWorkbook.xlsx`) and append it to the marker path. Following is the URL with the marker path and workbook location appended: - - - - - -``` +```http http:///_vti_bin/ExcelRest.aspx ``` - ### Resource Location The resource location is the path inside the workbook to the element that you request. For example, if you want to get a chart, the resource location would be similar to `/model/Charts('Chart 1')`. - - - -For the full URL, you append this to the marker path and the relative path to the workbook. Following is the full example URL: - - - - +For the full URL, you append this to the marker path and the relative path to the workbook. Following is the full example URL: -``` +```http http:///_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart 1') - ``` - ## See also +### Concepts -#### Concepts - - - - - - [Resources URI for Excel Services REST API](resources-uri-for-excel-services-rest-api.md) - - - - [Discovery in Excel Services REST API](discovery-in-excel-services-rest-api.md) +- [Resources URI for Excel Services REST API](resources-uri-for-excel-services-rest-api.md) +- [Discovery in Excel Services REST API](discovery-in-excel-services-rest-api.md) diff --git a/docs/general-development/bcs-client-object-model-reference-for-sharepoint.md b/docs/general-development/bcs-client-object-model-reference-for-sharepoint.md index 79242e367..802acb419 100644 --- a/docs/general-development/bcs-client-object-model-reference-for-sharepoint.md +++ b/docs/general-development/bcs-client-object-model-reference-for-sharepoint.md @@ -1,9 +1,9 @@ --- title: BCS client object model reference for SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Guidelines explaining what objects are available to create client-side scripts using the SharePoint client object model. +ms.date: 06/07/2022 ms.assetid: fe7d12a3-6ea9-47f9-b69e-f66da9e661dc -localization_priority: Normal +ms.localizationpriority: medium --- @@ -480,7 +480,7 @@ The namespace is **Microsoft.BusinessData.MetadataModel**.
-- **Does the tag need to be included in a CAML query when querying an external list** +- **Does the \ tag need to be included in a CAML query when querying an external list** No. diff --git a/docs/general-development/bcs-rest-api-reference-for-sharepoint.md b/docs/general-development/bcs-rest-api-reference-for-sharepoint.md index a8469ece0..3306bb260 100644 --- a/docs/general-development/bcs-rest-api-reference-for-sharepoint.md +++ b/docs/general-development/bcs-rest-api-reference-for-sharepoint.md @@ -1,9 +1,9 @@ --- title: BCS REST API reference for SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Reference for constructing Representational State Transfer (REST) URLs using Business Connectivity Services (BCS) in SharePoint. +ms.date: 06/07/2022 ms.assetid: 364fb8d7-87d9-4be7-affd-90caba3cd0c0 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/bdc-model-schema-reference-for-sharepoint.md b/docs/general-development/bdc-model-schema-reference-for-sharepoint.md index 01b825890..f1bdccae9 100644 --- a/docs/general-development/bdc-model-schema-reference-for-sharepoint.md +++ b/docs/general-development/bdc-model-schema-reference-for-sharepoint.md @@ -2,9 +2,8 @@ title: BDC model schema reference for SharePoint description: Contains reference documentation for the BDC model schema (BDCMetadata.xsd), which you can use to create external content types in SharePoint. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: 979a5ffc-f033-4e72-b2d1-11d8cb1b294a -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/build-farm-solutions-in-sharepoint.md b/docs/general-development/build-farm-solutions-in-sharepoint.md index 15c1d6cc0..a0892c7e9 100644 --- a/docs/general-development/build-farm-solutions-in-sharepoint.md +++ b/docs/general-development/build-farm-solutions-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Build farm solutions in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article providing links for documentation about developing, packaging and deploying build farm solutions in SharePoint. +ms.date: 06/07/2022 ms.assetid: 96c32f08-ad93-49af-b8d0-9d194a48cc79 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/build-localized-applications-for-windows-phone-based-on-the-sharepoint-templates.md b/docs/general-development/build-localized-applications-for-windows-phone-based-on-the-sharepoint-templates.md index c4c97c933..3b6e71d05 100644 --- a/docs/general-development/build-localized-applications-for-windows-phone-based-on-the-sharepoint-templates.md +++ b/docs/general-development/build-localized-applications-for-windows-phone-based-on-the-sharepoint-templates.md @@ -1,9 +1,9 @@ --- title: Build localized applications for Windows Phone based on the SharePoint templates -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links to learn how to build a localizable Windows Phone app using SharePoint templates. +ms.date: 06/07/2022 ms.assetid: c12d7fd4-8c6b-446b-970b-1eb0e5d0a9b2 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/build-mobile-apps-for-other-platforms-using-sharepoint.md b/docs/general-development/build-mobile-apps-for-other-platforms-using-sharepoint.md index f85a4e682..276d2d87d 100644 --- a/docs/general-development/build-mobile-apps-for-other-platforms-using-sharepoint.md +++ b/docs/general-development/build-mobile-apps-for-other-platforms-using-sharepoint.md @@ -1,106 +1,107 @@ --- title: Build mobile apps for other platforms using SharePoint +description: Learn how to use Representational State Transfer (REST) to create a SharePoint mobile app for any platform. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: 017df869-44fb-4ffe-82fb-4654e01329ad -localization_priority: Priority +ms.localizationpriority: high --- # Build mobile apps for other platforms using SharePoint Learn how to use Representational State Transfer (REST) to create a SharePoint mobile app for any platform. + Mobile devices have become more powerful and easy to use nowadays. Laptops, netbooks, tablet PCs, and mobile phones provide workers access to the information and applications that they need to do their jobs. And developing applications for mobile devices is now easier than ever. As a result, more and more business scenarios demand integrating client applications together with their business processes. This article describes how to integrate mobile client apps together with SharePoint. You can create a mobile app to browse SharePoint content from any location and connect with SharePoint lists and libraries to access data. - - - + + + To develop a mobile app that interacts with SharePoint, you can use common services that can be accessed using open protocols. SharePoint Foundation 2010 introduced the client object models, which enabled developers to perform remote communication with SharePoint by using the web programming technology of their choice: .NET Framework, Microsoft Silverlight, or JavaScript. SharePoint introduces a Representational State Transfer (REST) service that is fully comparable to the client object models. In SharePoint, nearly every API in the client object models will have a corresponding REST endpoint. Now, developers can interact remotely with the SharePoint object model by using any technology that supports REST web requests. REST can be consumed by any programming language that you want to use for your mobile application development. You can perform basic create, read, update, and delete (CRUD) operations by using the REST interface provided by SharePoint. REST exposes all of the SharePoint entities and operations that are available in the other SharePoint client APIs. One advantage of using REST is that you don't have to add references to any SharePoint libraries or client assemblies. Instead, you make HTTP requests to the appropriate endpoints to retrieve or update SharePoint entities, such as webs, lists, and list items. For a thorough introduction to the SharePoint REST interface and its architecture, see [Use OData query operations in SharePoint REST requests](https://msdn.microsoft.com/library/d4b5c277-ed50-420c-8a9b-860342284b72%28Office.15%29.aspx). - - - + + + ## REST endpoints in SharePoint To use the REST capabilities that are built into SharePoint, you can construct a RESTful HTTP request using the Open Data Protocol (OData) standard that corresponds to the desired client object model API. The client.svc web service handles the HTTP request and serves the appropriate response, in either Atom or JavaScript Object Notation (JSON) format. The client application must then parse that response. Figure 1 shows a high-level view of the SharePoint REST architecture. - - - + + + **Figure 1. SharePoint REST architecture** - - - - - - + + + + + + ![SharePoint REST architecture](../images/SP15Con_BuildSharePointAppsForMobileDevices_Fig2.png) - - - + + + The endpoints in the SharePoint REST service correspond to the types and members in the SharePoint client object models. By using HTTP requests, you can use these REST endpoints to perform typical CRUD operations against SharePoint artifacts, such as lists and sites. - - - + + + In general: - - - + + + - Endpoints that represent read operations map to HTTP **GET** commands. - - + + - Endpoints that represent update operations map to HTTP **POST** commands. - - + + - Endpoints that represent update or insert operations map to HTTP **PUT** commands. - - + + In choosing an HTTP request to use, you should also consider the following: - - - + + + - Use **POST** to create artifacts such as lists and sites. The SharePoint REST service supports sending **POST** commands that include object definitions to endpoints that represent collections. - - + + - For **POST** operations, any properties that are not required are set to their default values. If you try to set a read-only property as part of a **POST** operation, the service returns an exception. - - + + - Use **PUT**, **PATCH**, and **MERGE** operations to update existing SharePoint objects. Any service endpoint that represents an object property **set** operation supports both **PUT** requests and **MERGE** requests. For **MERGE** requests, setting properties is optional; any properties that you do not explicitly set retain their current property. But for **PUT** commands, any properties you do not explicitly set are set to their default properties. In addition, if you do not specify all settable properties in object updates when you use HTTP **PUT** commands, the REST service returns an exception. - - + + - Use the HTTP **DELETE** command against the specific endpoint URL to delete the SharePoint object represented by that endpoint. For recyclable objects, such as lists, files, and list items, this results in a **Recycle** operation. For more information, see [Get to know the SharePoint REST service](https://msdn.microsoft.com/library/2de035a0-ac75-43bd-9665-5c5a59c4c590%28Office.15%29.aspx). - - + + ## Authenticate users to SharePoint To authenticate your mobile app with SharePoint, you can use the MS-OFBA protocol. For more information, see [[MS-OFBA]: Office Forms Based Authentication Protocol Specification](https://msdn.microsoft.com/library/30c7bbe9-b284-421f-b866-4e7ed4866027%28Office.15%29.aspx). The protocol client is configured to store and transmit cookies. The protocol client relies on the remote protocol server to set the user's identity as one or more HTTP cookies. After the user's identity is established, the client then sends each cookie with each subsequent HHT request. - - - + + + When a user signs in to SharePoint, the user's token is validated and then used to sign in to SharePoint. The user's token is a security token that is issued by an identity provider. SharePoint supports several kinds of authentication. For more information, see [Authentication, authorization, and security in SharePoint](authentication-authorization-and-security-in-sharepoint.md). To authenticate a user, you can use the REST interface. The authorization process verifies that an authenticated subject (an app or a user the app is acting on behalf of.md) has permission to perform certain operations or to access specific resources (for example, a list or a SharePoint document folder.md). - - - + + + OData lets you access a data source, such as a database, by browsing to a specially constructed URL. This allows for a simplified approach for connecting to, and working with, data sources that are hosted within an organization. OData is a protocol that uses HTTP, Atom, and JavaScript Object Notation (JSON) to enable developers to write applications that communicate with an ever-growing number of data sources. Microsoft supports the creation of this standard as a way to enable the exchange of data between applications and data stores that can be accessed from the web. The new OData connector enables SharePoint to communicate with OData providers. For more information, see [Open Data Protocol](http://www.odata.org). - - - + + + The following code demonstrates how to authenticate your app to SharePoint using REST endpoints for basic or forms-based authentication. The following code example is written in C#, but any other programming language can be used to create the Http request, as per the requirement of the platform. - - - -```cs + + + +```csharp string SharePointUrl = "https://Target SharePoint site"; @@ -118,7 +119,7 @@ void odataAt_AuthenticationCompleted(object sender, AuthenticationCompletedEvent endpointRequest.Method = "GET"; endpointRequest.Accept = "application/json;odata=verbose"; endpointRequest.CookieContainer = (sender as ODataAuthenticator).CookieContainer; - + endpointRequest.BeginGetResponse(new AsyncCallback((IAsyncResult res) => { HttpWebRequest webReq = res.AsyncState as HttpWebRequest; @@ -136,21 +137,21 @@ void odataAt_AuthenticationCompleted(object sender, AuthenticationCompletedEvent ``` To authenticate an **HttpWebrequest** to the endpoint, you should first authenticate to SharePoint with the **ODataAuthenticator** class. Before calling the **Authenticate** method, register the **ODataAuthenticator** object to the **AuthenticationCompleted** event. - - - + + + After authentication is done inside the **OnAuthenticationCompleted** event, you can use the **CookieContainer** property on the **ODataAuthenticator** object, which can be attached to the **HttpWebRequest** object to authenticate the REST calls to SharePoint. - - - + + + ## Work with SharePoint list items using REST The following example shows how to **retrieve** all of a list's items. - - - + + + ``` @@ -166,9 +167,9 @@ headers: ``` The following example shows how to **retrieve** a specific list item. - - - + + + @@ -177,7 +178,7 @@ The following example shows how to **retrieve** a specific list item. url: http://site url/_api/web/lists/GetByTitle('Test')/items(item id) method: GET headers: - + // MS-OFBA protocol return a cookie. Cookie: cookie accept: "application/json;odata=verbose" or "application/atom+xml" @@ -185,9 +186,9 @@ headers: ``` The following XML shows an example of the list item properties that are returned when you request the XML content type. - - - + + + @@ -212,13 +213,13 @@ The following XML shows an example of the list item properties that are returned ``` The following example shows how to **create** a list item. - + > [!NOTE] -> +> > To do this operation, you must know the **ListItemEntityTypeFullName** property of the list and pass that as the value of **type** in the HTTP request body. - - - + + + @@ -229,7 +230,7 @@ url: http://site url/_api/web/lists/GetByTitle('Test')/items method: POST body: { '__metadata': { 'type': 'SP.Data.TestListItem' }, 'Title': 'Test'} headers: - + // MS-OFBA protocol returns a cookie. Cookie: cookie X-RequestDigest = form digest value @@ -239,12 +240,12 @@ headers: ``` The following example shows how to **update** a list item. - + > [!NOTE] > To do this operation, you must know the **ListItemEntityTypeFullName** property of the list and pass that as the value of **type** in the HTTP request body. - - - + + + @@ -266,9 +267,9 @@ headers: ``` The following example shows how to **delete** a list item. - - - + + + @@ -286,42 +287,19 @@ headers: ``` For more information, see [Complete basic operations using SharePoint REST endpoints](https://msdn.microsoft.com/library/e3000415-50a0-426e-b304-b7de18f2f7d9%28Office.15%29.aspx). - - - + + + ## See also - - - -- [Build Windows Phone apps that access SharePoint](build-windows-phone-apps-that-access-sharepoint.md) - - -- [Using the SharePoint REST service](https://docs.microsoft.com/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service) - - -- [Build Windows Phone apps that access SharePoint](build-windows-phone-apps-that-access-sharepoint.md) - - -- [Choose the right API set in SharePoint](choose-the-right-api-set-in-sharepoint.md) - - -- [Use OData query operations in SharePoint REST requests](https://msdn.microsoft.com/library/d4b5c277-ed50-420c-8a9b-860342284b72%28Office.15%29.aspx) - - -- [Get to know the SharePoint REST service](https://msdn.microsoft.com/library/2de035a0-ac75-43bd-9665-5c5a59c4c590%28Office.15%29.aspx) - - -- [Open Data Protocol](http://www.odata.org/) - - -- [Authorization and authentication of SharePoint Add-ins](https://msdn.microsoft.com/library/bde5647a-fff1-4b51-b67b-2139de79ce4a%28Office.15%29.aspx) - - -- [Windows Phone SDK 8.0](https://www.microsoft.com/download/details.aspx?id=35471) - - -- [Microsoft SharePoint SDK for Windows Phone 8](https://www.microsoft.com/download/details.aspx?id=36818) - - +- [Build Windows Phone apps that access SharePoint](build-windows-phone-apps-that-access-sharepoint.md) +- [Get to know the SharePoint REST service](../sp-add-ins/get-to-know-the-sharepoint-rest-service.md) +- [Build Windows Phone apps that access SharePoint](build-windows-phone-apps-that-access-sharepoint.md) +- [Choose the right API set in SharePoint](choose-the-right-api-set-in-sharepoint.md) +- [Use OData query operations in SharePoint REST requests](https://msdn.microsoft.com/library/d4b5c277-ed50-420c-8a9b-860342284b72%28Office.15%29.aspx) +- [Get to know the SharePoint REST service](https://msdn.microsoft.com/library/2de035a0-ac75-43bd-9665-5c5a59c4c590%28Office.15%29.aspx) +- [Open Data Protocol](http://www.odata.org/) +- [Authorization and authentication of SharePoint Add-ins](https://msdn.microsoft.com/library/bde5647a-fff1-4b51-b67b-2139de79ce4a%28Office.15%29.aspx) +- [Windows Phone SDK 8.0](https://www.microsoft.com/download/details.aspx?id=35471) +- [Microsoft SharePoint SDK for Windows Phone 8](https://www.microsoft.com/download/details.aspx?id=36818) diff --git a/docs/general-development/build-reusable-components-for-sharepoint.md b/docs/general-development/build-reusable-components-for-sharepoint.md index 7ff1b3bf8..2245e988a 100644 --- a/docs/general-development/build-reusable-components-for-sharepoint.md +++ b/docs/general-development/build-reusable-components-for-sharepoint.md @@ -1,9 +1,9 @@ --- title: Build reusable components for SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links summarizing the most common reusable components you can build in SharePoint. +ms.date: 06/07/2022 ms.assetid: bb4467e2-57f0-4cf1-91b8-4d3d8d2358cb -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/build-sites-for-sharepoint.md b/docs/general-development/build-sites-for-sharepoint.md index 1f583c9ff..32222ca2f 100644 --- a/docs/general-development/build-sites-for-sharepoint.md +++ b/docs/general-development/build-sites-for-sharepoint.md @@ -1,9 +1,9 @@ --- title: Build sites for SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links to learn about the new site authoring and publishing model for websites in SharePoint. +ms.date: 06/07/2022 ms.assetid: 3b372a63-7cdf-462a-abb4-750e611e967d -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/build-windows-phone-apps-that-access-sharepoint.md b/docs/general-development/build-windows-phone-apps-that-access-sharepoint.md index 0d46df6f8..0bcd5d7b8 100644 --- a/docs/general-development/build-windows-phone-apps-that-access-sharepoint.md +++ b/docs/general-development/build-windows-phone-apps-that-access-sharepoint.md @@ -1,38 +1,28 @@ --- title: Build Windows Phone apps that access SharePoint -ms.date: 12/22/2020 -ms.prod: sharepoint +ms.date: 06/09/2022 ms.assetid: 36681335-f772-4499-8445-f94481bc18e7 description: Create SharePoint Add-ins that integrate SharePoint and mobile devices such as Windows Phone 8 and Windows Phone 7. -localization_priority: Normal +ms.localizationpriority: medium --- - # Build Windows Phone apps that access SharePoint SharePoint provides an exciting opportunity for developers to build mobile apps that travel with users, are interactive and attractive, and are available whenever and wherever users want to work with them. You can combine Windows Phone 8 and Windows Phone 7 applications with on-premises SharePoint services and applications, or with remote SharePoint services and applications that run in the cloud (such as those that use SharePoint Online) to create powerful applications that extend the functionality beyond the traditional desktop or laptop and into a truly portable and much more accessible environment. - + The new mobility features offered by SharePoint are built on existing Microsoft tools and technologies, such as SharePoint, Windows Phone, Visual Studio, and Silverlight. Developers who are already familiar with those technologies and their related tools will be able to create SharePoint-powered mobile apps for Windows Phone without a steep learning curve. In this section, we explore some of the types of SharePoint-powered mobile apps you can build for Windows Phone 8 and Windows Phone 7 and the most common ways to customize those applications. SharePoint provides a framework and tools for developers, including Visual Studio 2010 project templates, to create mobile solutions that interact with SharePoint data both in on-premises SharePoint installations and in the cloud by using SharePoint Online. Figure 1 shows how a simple list application could look on Windows Phone. - - + **Figure 1. SharePoint list items in a Windows Phone app** ![SharePoint list items in a Windows Phone app](../images/9159345c-ce12-41a6-8994-fc2e9aa26fd6.gif) - - ## What skills do you need to create mobile apps? In this section, we assume that you're familiar with SharePoint, the .NET Framework, the Visual Studio development system, and Visual C#. It's also good to have some experience with Windows Phone 8 or Windows Phone 7 application development using Silverlight, and it helps to be familiar with XAML, the StackPanel and Pivot controls for Windows Phone, and concepts such as tombstoning, Silverlight data binding, and so on. If you are new to Windows Phone application development using Silverlight, we recommend that you check out the following resources. -- [Developing a Windows Phone Application from Start to Finish](https://msdn.microsoft.com/library/gg680270%28v=pandp.11%29.aspx) - -- [User interface for Windows Phone](https://msdn.microsoft.com/library/windowsphone/develop/ff967556%28v=vs.105%29.aspx) - -- [Quickstart: Creating a user interface with XAML for Windows Phone](https://msdn.microsoft.com/library/windowsphone/develop/jj207025%28v=vs.105%29.aspx) - -- [Pivot control architecture for Windows Phone](https://msdn.microsoft.com/library/windowsphone/develop/ff941097%28v=vs.105%29.aspx) - - +- [Developing a Windows Phone Application from Start to Finish](https://msdn.microsoft.com/library/gg680270%28v=pandp.11%29.aspx) +- [User interface for Windows Phone](https://msdn.microsoft.com/library/windowsphone/develop/ff967556%28v=vs.105%29.aspx) +- [Quickstart: Creating a user interface with XAML for Windows Phone](https://msdn.microsoft.com/library/windowsphone/develop/jj207025%28v=vs.105%29.aspx) +- [Pivot control architecture for Windows Phone](https://msdn.microsoft.com/library/windowsphone/develop/ff941097%28v=vs.105%29.aspx) ## Development overview for mobile apps using SharePoint @@ -40,34 +30,34 @@ You can build a wide variety of mobile apps using SharePoint. This section descr ### Windows Phone SharePoint Application template -This is the simplest type of mobile app you can build to bring a regular list to the phone. SharePoint offers a Visual Studio template to enable you to quickly and easily create SharePoint list applications for the Windows Phone. For example, you can build a "To Do List"-type Windows Phone application that brings your task list from SharePoint into the Windows Phone and enables the you to use your phone to update the status of a task on the go. Another example is having the product catalog for an inventory list in SharePoint available on the phone for the sales people. +This is the simplest type of mobile app you can build to bring a regular list to the phone. SharePoint offers a Visual Studio template to enable you to quickly and easily create SharePoint list applications for the Windows Phone. For example, you can build a "To Do List"-type Windows Phone application that brings your task list from SharePoint into the Windows Phone and enables the you to use your phone to update the status of a task on the go. Another example is having the product catalog for an inventory list in SharePoint available on the phone for the sales people. -Installing the Windows Phone SharePoint SDK makes two Windows Phone SharePoint Application templates available to you in Visual Studio 2010 or Visual Studio 2010 Express for Windows Phone (see [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md)). +Installing the Windows Phone SharePoint SDK makes two Windows Phone SharePoint Application templates available to you in Visual Studio 2010 or Visual Studio 2010 Express for Windows Phone (see [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md)). Using the Windows Phone SharePoint List Application template, you can follow the steps of a wizard to create a functional Windows Phone app that can access and manipulate data in a SharePoint list. ### New and enhanced mobility object model in SharePoint SharePoint adds several new classes to both the server and client object models to enable the SharePoint mobility scenarios that we described earlier in this article. - -To enable location-aware apps, there is a new native field type class, **SPFieldGeoLocation**, along with several associated classes for structuring the value of location fields and rendering them. These classes are also callable in the SharePoint client object model for Silverlight. The new field type also has a definition added to the standard SharePoint fldtypes.xml file and new user controls for rendering the field on the Display, Edit, and New forms. For an overview, see [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md). + +To enable location-aware apps, there is a new native field type class, **SPFieldGeoLocation**, along with several associated classes for structuring the value of location fields and rendering them. These classes are also callable in the SharePoint client object model for Silverlight. The new field type also has a definition added to the standard SharePoint fldtypes.xml file and new user controls for rendering the field on the Display, Edit, and New forms. For an overview, see [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md). To enable SharePoint authentication for Windows Phone users, the client object model includes a new **Authenticator** class and several associated classes. For an overview, see [Overview of the SharePoint mobile client authentication object model](overview-of-the-sharepoint-mobile-client-authentication-object-model.md). - + To enable automatic notifications to Windows Phone users of events on a SharePoint farm, the server object model includes several new classes, each of which is also callable from the client object model. These classes include methods that enable phone apps to register with SharePoint server apps for notifications about specified types of events. There are also methods that the server apps use to send notifications to registered subscribers. For an overview, see [Create a Windows Phone SharePoint list app to receive push notifications](how-to-configure-and-use-push-notifications-in-sharepoint-apps-for-windows.md#create-a-windows-phone-sharepoint-list-app-to-receive-push-notifications). - + With SharePoint, you're not limited to mobile app development just for Windows Phone 8 and Windows Phone 7. With the JavaScript programming interface and the new Representational State Transfer (REST) programming interface provided by SharePoint, you can create applications for non-Windows Phone mobile devices; you can interact with SharePoint sites by using JavaScript that executes as scripts in the browser, or remotely by using any technology that supports standard REST capabilities. The following section provides an overview of the REST and JavaScript programming interfaces. #### ECMAScript (JavaScript, JScript) object model architecture SharePoint Foundation 2010 introduced the client object models, which enabled developers to perform remote communication with SharePoint by using the web programming technology of their choice: the .NET Framework, Silverlight, or JavaScript. - + In SharePoint Foundation 2010, the client object models provide APIs that enable developers to interact with SharePoint sites from script that executes in the browser, from code (based on the .NET Framework 3.5 or later) that executes in a .NET Framework-managed application, or from code that executes in a Silverlight 2.0 application. The proxy .js and managed .dll files that compose the client object models are built on the client.svc web service, and handle the effective batching, serialization of requests, and parsing of replies. Figure 2 shows a high-level view of the SharePoint client object model architecture. **Figure 2. SharePoint client object model architecture** - + ![SharePoint client object model architecture](../images/SP15Con_BuildSharePointAppsForMobileDevices_Fig3.png) - + To learn how to use the JavaScript client object model against SharePoint data, see the [ECMAScript Client Object Model video](https://msdn.microsoft.com/SP2010DevTrainingCourse_ECMAScriptClientObjectModel.aspx). #### REST endpoints in SharePoint @@ -75,65 +65,44 @@ To learn how to use the JavaScript client object model against SharePoint data, To use the REST capabilities that are built into SharePoint, you can construct a RESTful HTTP request using the Open Data Protocol (OData) standard that corresponds to the desired client object model API. The client.svc web service handles the HTTP request and serves the appropriate response, in either Atom or JavaScript Object Notation (JSON) format. The client application must then parse that response. Figure 3 shows a high-level view of the SharePoint REST architecture. **Figure 3. SharePoint REST architecture** - + ![SharePoint REST architecture](../images/SP15Con_BuildSharePointAppsForMobileDevices_Fig2.png) - + Currently, the REST service in SharePoint is read-only. That is, only REST endpoints that represent an HTTP GET operation are available - + By default, the SharePoint REST service responses are formatted using the Atom protocol, according to the OData specification. In addition, the REST service supports HTTP Accept headers that enable developers to specify that the response is returned in JSON format. To learn more about REST services in SharePoint, see [Use OData query operations in SharePoint REST requests](https://msdn.microsoft.com/library/d4b5c277-ed50-420c-8a9b-860342284b72%28Office.15%29.aspx). - + The SharePoint REST service supports the following OData query operators: - Filter - Take - Expand - - ## Start developing mobile apps for SharePoint The following how-tos and overviews delve into the specific information you need to start your mobile app development: -- [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md) - -- [Overview of Windows Phone SharePoint application templates in Visual Studio](overview-of-windows-phone-sharepoint-application-templates-in-visual-studio.md) - -- [Architecture of the Windows Phone SharePoint List Application template](architecture-of-the-windows-phone-sharepoint-list-application-template.md) - -- [How to: Create a Windows Phone SharePoint list app](how-to-create-a-windows-phone-sharepoint-list-app.md) - -- [How to: Store and retrieve SharePoint list items on a Windows Phone](how-to-store-and-retrieve-sharepoint-list-items-on-a-windows-phone.md) - -- [How to: Implement business logic and data validation in a Windows Phone app for SharePoint](how-to-implement-business-logic-and-data-validation-in-a-windows-phone-app-for-s.md) - -- [How to: Support and convert SharePoint field types for Windows Phone apps](how-to-support-and-convert-sharepoint-field-types-for-windows-phone-apps.md) +- [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md) +- [Overview of Windows Phone SharePoint application templates in Visual Studio](overview-of-windows-phone-sharepoint-application-templates-in-visual-studio.md) +- [Architecture of the Windows Phone SharePoint List Application template](architecture-of-the-windows-phone-sharepoint-list-application-template.md) +- [How to: Create a Windows Phone SharePoint list app](how-to-create-a-windows-phone-sharepoint-list-app.md) +- [How to: Store and retrieve SharePoint list items on a Windows Phone](how-to-store-and-retrieve-sharepoint-list-items-on-a-windows-phone.md) +- [How to: Implement business logic and data validation in a Windows Phone app for SharePoint](how-to-implement-business-logic-and-data-validation-in-a-windows-phone-app-for-s.md) +- [How to: Support and convert SharePoint field types for Windows Phone apps](how-to-support-and-convert-sharepoint-field-types-for-windows-phone-apps.md) +- [How to: Customize list item queries and filter data for Windows Phone apps](how-to-customize-list-item-queries-and-filter-data-for-windows-phone-apps.md) +- [How to: Customize the user interface of a SharePoint list app for Windows Phone](how-to-customize-the-user-interface-of-a-sharepoint-list-app-for-windows-ph.md) +- [How to: Use multiple SharePoint lists in a Windows Phone app](how-to-use-multiple-sharepoint-lists-in-a-windows-phone-app.md) +- [How to: Configure and use push notifications in SharePoint apps for Windows Phone](how-to-configure-and-use-push-notifications-in-sharepoint-apps-for-windows.md) +- [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md) +- [How to: Create a mobile app in SharePoint that contains data from an external data source](how-to-create-a-mobile-app-in-sharepoint-that-contains-data-from-an-externa.md) +- [How to: Integrate maps with Windows Phone apps and SharePoint lists](how-to-integrate-maps-with-windows-phone-apps-and-sharepoint-lists.md) +- [How to: Build search-driven mobile apps with the Navigation and Event Logging REST interfaces](how-to-build-search-driven-mobile-apps-with-the-navigation-and-event-logging-res.md) -- [How to: Customize list item queries and filter data for Windows Phone apps](how-to-customize-list-item-queries-and-filter-data-for-windows-phone-apps.md) - -- [How to: Customize the user interface of a SharePoint list app for Windows Phone](how-to-customize-the-user-interface-of-a-sharepoint-list-app-for-windows-ph.md) - -- [How to: Use multiple SharePoint lists in a Windows Phone app](how-to-use-multiple-sharepoint-lists-in-a-windows-phone-app.md) - -- [How to: Configure and use push notifications in SharePoint apps for Windows Phone](how-to-configure-and-use-push-notifications-in-sharepoint-apps-for-windows.md) - -- [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md) - -- [How to: Create a mobile app in SharePoint that contains data from an external data source](how-to-create-a-mobile-app-in-sharepoint-that-contains-data-from-an-externa.md) - -- [How to: Integrate maps with Windows Phone apps and SharePoint lists](how-to-integrate-maps-with-windows-phone-apps-and-sharepoint-lists.md) - -- [How to: Build search-driven mobile apps with the Navigation and Event Logging REST interfaces](how-to-build-search-driven-mobile-apps-with-the-navigation-and-event-logging-res.md) - ## See also -- [Programming models in SharePoint](programming-models-in-sharepoint.md) -- [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md) -- [Windows Phone SDK 8.0](https://www.microsoft.com/download/details.aspx?id=35471) -- [Microsoft SharePoint SDK for Windows Phone 8](https://www.microsoft.com/download/details.aspx?id=36818) -- [Windows Phone SDK 7.1](https://www.microsoft.com/download/details.aspx?id=27570) -- [Microsoft SharePoint SDK for Windows Phone 7.1](https://www.microsoft.com/download/details.aspx?id=30476) -- [About Expression Blend](https://msdn.microsoft.com/library/cc296376%28Expression.40%29.aspx) - - - +- [Programming models in SharePoint](programming-models-in-sharepoint.md) +- [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md) +- [Windows Phone SDK 8.0](https://www.microsoft.com/download/details.aspx?id=35471) +- [Windows Phone SDK 7.1](https://www.microsoft.com/download/details.aspx?id=29233) +- [About Expression Blend](https://msdn.microsoft.com/library/cc296376%28Expression.40%29.aspx) diff --git a/docs/general-development/building-search-queries-in-sharepoint.md b/docs/general-development/building-search-queries-in-sharepoint.md index 346b021ba..d95fc24dd 100644 --- a/docs/general-development/building-search-queries-in-sharepoint.md +++ b/docs/general-development/building-search-queries-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Building search queries in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links about the search syntax supported in SharePoint for building query rules and search queries. +ms.date: 06/07/2022 ms.assetid: c4372fcc-4574-4c81-a345-a1bb282ca8f7 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/business-connectivity-services-in-sharepoint.md b/docs/general-development/business-connectivity-services-in-sharepoint.md index 09679533a..fa6d231e3 100644 --- a/docs/general-development/business-connectivity-services-in-sharepoint.md +++ b/docs/general-development/business-connectivity-services-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Business Connectivity Services in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links to learn about Business Connectivity Services (BCS) and get started developing BCS applications in SharePoint. +ms.date: 06/07/2022 ms.assetid: 64b7d032-4b83-4e9e-bc08-f0a161af5457 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/business-connectivity-services-programmers-reference-for-sharepoint.md b/docs/general-development/business-connectivity-services-programmers-reference-for-sharepoint.md index 39e8fe2c1..2350e05c9 100644 --- a/docs/general-development/business-connectivity-services-programmers-reference-for-sharepoint.md +++ b/docs/general-development/business-connectivity-services-programmers-reference-for-sharepoint.md @@ -1,9 +1,9 @@ --- title: Business Connectivity Services programmers reference for SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links to find reference information to create solutions using Business Connectivity Services (BCS) in SharePoint. +ms.date: 06/07/2022 ms.assetid: cfc9bdf8-ddf3-40e1-83d9-dbd304cebd57 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/changes-in-the-bdc-model-schema-for-sharepoint.md b/docs/general-development/changes-in-the-bdc-model-schema-for-sharepoint.md index fd9914afd..ceb41318b 100644 --- a/docs/general-development/changes-in-the-bdc-model-schema-for-sharepoint.md +++ b/docs/general-development/changes-in-the-bdc-model-schema-for-sharepoint.md @@ -2,9 +2,8 @@ title: Changes in the BDC model schema for SharePoint description: Learn what has changed in SharePoint for the BDC model schema. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: 882ea867-9acb-4313-99c9-865a523b72fd -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/choose-the-right-api-set-in-sharepoint.md b/docs/general-development/choose-the-right-api-set-in-sharepoint.md index 19978dc84..8734f8b1b 100644 --- a/docs/general-development/choose-the-right-api-set-in-sharepoint.md +++ b/docs/general-development/choose-the-right-api-set-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Choose the right API set in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links to learn about SharePoint APIs including the server object model, various client object models and the REST/OData web service. +ms.date: 06/07/2022 ms.assetid: f36645da-77c5-47f1-a2ca-13d4b62b320d -localization_priority: Priority +ms.localizationpriority: high --- # Choose the right API set in SharePoint diff --git a/docs/general-development/claims-based-identity-and-concepts-in-sharepoint.md b/docs/general-development/claims-based-identity-and-concepts-in-sharepoint.md index e664823bb..171dc84f4 100644 --- a/docs/general-development/claims-based-identity-and-concepts-in-sharepoint.md +++ b/docs/general-development/claims-based-identity-and-concepts-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Claims-based identity and concepts in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links to learn about the claims-based identity model and concepts in SharePoint. +ms.date: 06/07/2022 ms.assetid: d96c7cf4-2e48-4223-a3c0-42368d079b74 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/claims-based-identity-in-sharepoint.md b/docs/general-development/claims-based-identity-in-sharepoint.md index 9934beb0e..49a81f2c7 100644 --- a/docs/general-development/claims-based-identity-in-sharepoint.md +++ b/docs/general-development/claims-based-identity-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Claims-based identity in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article with links to learn about the fundamentals of claims-based identity architecture in SharePoint. +ms.date: 06/07/2022 ms.assetid: 32b6af2a-72f3-4302-a6af-5f00143cbf67 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/claims-based-identity-term-definitions.md b/docs/general-development/claims-based-identity-term-definitions.md index e7cb54d44..8fcf7b8d0 100644 --- a/docs/general-development/claims-based-identity-term-definitions.md +++ b/docs/general-development/claims-based-identity-term-definitions.md @@ -1,9 +1,9 @@ --- title: Claims-based identity term definitions -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Definitions of key terms related to claims-based identity. +ms.date: 06/07/2022 ms.assetid: 0f3decb5-dcd8-432f-9bb8-533f2d01bef7 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/claims-provider-in-sharepoint.md b/docs/general-development/claims-provider-in-sharepoint.md index ed648e69c..6c27c9da2 100644 --- a/docs/general-development/claims-provider-in-sharepoint.md +++ b/docs/general-development/claims-provider-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Claims provider in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article with links to learn about the claims provider in SharePoint. +ms.date: 06/07/2022 ms.assetid: 5918d5b6-5fd6-4f41-9473-a15b1491d056 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/client-side-web-parts-maintenance-mode.md b/docs/general-development/client-side-web-parts-maintenance-mode.md index 9e8a3b356..7a9543bcd 100644 --- a/docs/general-development/client-side-web-parts-maintenance-mode.md +++ b/docs/general-development/client-side-web-parts-maintenance-mode.md @@ -1,10 +1,9 @@ --- title: Maintenance mode for client-side web parts description: When working with client-side web parts, you can load them in maintenance mode. The maintenance mode can be helpful when trying to debug issues related to web parts placed on the page. -ms.date: 05/25/2021 -ms.prod: sharepoint +ms.date: 04/28/2023 ms.assetid: 3ebd2a11-8291-4228-add0-9e0cd899dd3c -localization_priority: Normal +ms.localizationpriority: medium --- # Maintenance mode for client-side web parts @@ -79,10 +78,10 @@ If the web part [integrates its properties with SharePoint](../spfx/web-parts/gu ## Disable SPFx web parts and extensions -If you need to troubleshoot a SharePoint page to see if there is a SharePoint Framework extension or web part causing issues you can append **?disable3PCode=1** to the URL to disable loading of SPFx components, for example: +If you need to troubleshoot a SharePoint page to see if there is a SharePoint Framework extension or web part causing issues you can append **?disable3PCode** to the URL to disable loading of SPFx components, for example: ```text -https://contoso.sharepoint.com/sites/team?disable3PCode=1 +https://contoso.sharepoint.com/sites/team?disable3PCode ``` This will prevent loading of any third party SPFx components on the page. diff --git a/docs/general-development/code-samples-for-sharepoint.md b/docs/general-development/code-samples-for-sharepoint.md index 284c8cd0c..dae9dde63 100644 --- a/docs/general-development/code-samples-for-sharepoint.md +++ b/docs/general-development/code-samples-for-sharepoint.md @@ -2,9 +2,8 @@ title: Code samples for SharePoint description: Find and download code samples for SharePoint, including samples that demonstrate SharePoint Framework, SharePoint Add-ins, user experience design, metadata management, workflows, mobile application development, REST, and other areas of SharePoint development. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: e6b52c6c-32f8-4689-8c1a-7b50039dcbe8 -localization_priority: Priority +ms.localizationpriority: high --- # Code samples for SharePoint diff --git a/docs/general-development/color-palettes-and-fonts-in-sharepoint.md b/docs/general-development/color-palettes-and-fonts-in-sharepoint.md index 338c7a2dd..8d613a05d 100644 --- a/docs/general-development/color-palettes-and-fonts-in-sharepoint.md +++ b/docs/general-development/color-palettes-and-fonts-in-sharepoint.md @@ -1,15 +1,16 @@ --- title: Color palettes and fonts in SharePoint description: Use this reference to define the color palette or font scheme that is used in a SharePoint site. -ms.date: 05/20/2020 -ms.prod: sharepoint +ms.date: 06/09/2022 ms.assetid: c17d375b-151f-48ae-ac32-f2ce9e68d63f -localization_priority: Priority +ms.localizationpriority: high --- # Color palettes and fonts in SharePoint Use this reference to define the color palette or font scheme that is used in a SharePoint site. +[!IMPORTANT] This extensibility option is only available for classic SharePoint experiences. You cannot use this option with modern experiences in SharePoint Online, like with communication sites. + ## Color palettes @@ -80,13 +81,6 @@ A color palette is the combination of colors that are used in a SharePoint site. -> **Tip:** -> You can use the SharePoint color palette tool to help you create SharePoint designs. You can [download the SharePoint color palette tool](https://www.microsoft.com/download/details.aspx?id=38182) from the Microsoft Download Center. - - - - - ### Color slot mapping @@ -380,7 +374,7 @@ In this example of using a web font, the following placeholders would be replace - _SmallImgFile_ is the relative URL to the small thumbnail image that you want to use in the font scheme picker. > [!NOTE] - > The paths to the files have to be the full URL (i.e. https://tenant.sharepoint.com/sites/sitename/_catalogs/theme/15/fontfile.wof) + > The paths to the files have to be the full URL (i.e. `https://tenant.sharepoint.com/sites/sitename/_catalogs/theme/15/fontfile.wof`) > The LargeImgFile and SmallImgFile attributes have to be present in the Latin tag even if given empty values. ### Font slots diff --git a/docs/general-development/common-error-messages-in-sharepoint-workflow-development.md b/docs/general-development/common-error-messages-in-sharepoint-workflow-development.md index 1fd9458c1..a0766bcf6 100644 --- a/docs/general-development/common-error-messages-in-sharepoint-workflow-development.md +++ b/docs/general-development/common-error-messages-in-sharepoint-workflow-development.md @@ -2,9 +2,8 @@ title: Common error messages in SharePoint workflow development description: A listing of common error messages that you might encounter while developing SharePoint workflows and guidance for solving the underlying problem. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: e9bf6878-c722-4b1f-b5b5-b302ae0ea4da -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/configuration-administration-and-resources-in-sharepoint.md b/docs/general-development/configuration-administration-and-resources-in-sharepoint.md index bae6b0c9b..c35d5e9ad 100644 --- a/docs/general-development/configuration-administration-and-resources-in-sharepoint.md +++ b/docs/general-development/configuration-administration-and-resources-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Configuration, administration, and resources in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Article with links to learn about the configuration, administration and resources in SharePoint. +ms.date: 06/07/2022 ms.assetid: e7d8c919-7aa6-466a-acb0-27366129061c -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/configure-search-in-sharepoint.md b/docs/general-development/configure-search-in-sharepoint.md index 12365e657..08992c761 100644 --- a/docs/general-development/configure-search-in-sharepoint.md +++ b/docs/general-development/configure-search-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Configure search in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article about configuring search in SharePoint. +ms.date: 06/07/2022 ms.assetid: e447127c-2b11-4d65-b46e-01a18cdcdee5 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/content-management-interoperability-services-cmis-in-sharepoint.md b/docs/general-development/content-management-interoperability-services-cmis-in-sharepoint.md index 3035ba961..c3d42c9d5 100644 --- a/docs/general-development/content-management-interoperability-services-cmis-in-sharepoint.md +++ b/docs/general-development/content-management-interoperability-services-cmis-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Content Management Interoperability Services (CMIS) in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article with links to learn about the SharePoint implementation of version 1.0 of the OASIS Content Management Interoperability Services (CMIS) standard. +ms.date: 06/07/2022 ms.assetid: a1def24c-b2db-4bf9-8d2c-02f5628832f8 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/content-search-web-part-in-sharepoint.md b/docs/general-development/content-search-web-part-in-sharepoint.md index c90d8bd9a..3d8aa8b79 100644 --- a/docs/general-development/content-search-web-part-in-sharepoint.md +++ b/docs/general-development/content-search-web-part-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Content Search web part in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article with links to learn about the Content Search web part (CSWP) in SharePoint. +ms.date: 06/07/2022 ms.assetid: 6fb4bf41-0846-4dca-ad9e-906afdfd3d2b -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/create-a-map-view-for-the-geolocation-field-in-sharepoint.md b/docs/general-development/create-a-map-view-for-the-geolocation-field-in-sharepoint.md index 622c209ee..1b6f5da34 100644 --- a/docs/general-development/create-a-map-view-for-the-geolocation-field-in-sharepoint.md +++ b/docs/general-development/create-a-map-view-for-the-geolocation-field-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Create a map view for the Geolocation field in SharePoint -ms.date: 05/09/2020 -ms.prod: sharepoint +description: Learn how to display location information by using a map view in SharePoint lists. +ms.date: 06/09/2022 ms.assetid: 0cd8ba27-3326-4b60-a2d0-d289a94f11bb -localization_priority: Priority +ms.localizationpriority: high --- # Create a map view for the Geolocation field in SharePoint @@ -15,7 +15,7 @@ To display a map view in a SharePoint list, you must use the Bing Maps services. The **Geolocation** field and the map view enable you to give spatial context to any information by integrating data from SharePoint into a mapping experience in web and mobile apps. This article does not explain how to render the **Geolocation** field or provide developer guidance for creating a location-based mobile application; it does provide instruction for creating map views programmatically and from the SharePoint UI by using Bing Maps. -An MSI package named SQLSysClrTypes.msi must be installed on every SharePoint front-end web server to view the **Geolocation** field value or data in a list. This package installs components that implement the new geometry, geography, and hierarchy ID types in SQL Server 2008. By default, this file is installed for SharePoint Online. However, it is not installed for an on-premises deployment of SharePoint. You must be a member of the Farm Administrators group to perform this operation. To download SQLSysClrTypes.msi, see [Microsoft SQL Server 2008 R2 SP1 Feature Pack](https://www.microsoft.com/download/details.aspx?id=26728) for SQL Server 2008, or [Microsoft SQL Server 2012 Feature Pack](https://www.microsoft.com/download/details.aspx?id=29065) for SQL Server 2012 in the Microsoft Download Center. +An MSI package named SQLSysClrTypes.msi must be installed on every SharePoint front-end web server to view the **Geolocation** field value or data in a list. This package installs components that implement the new geometry, geography, and hierarchy ID types in SQL Server 2008. By default, this file is installed for SharePoint Online. However, it is not installed for an on-premises deployment of SharePoint. You must be a member of the Farm Administrators group to perform this operation. To download SQLSysClrTypes.msi, see [Microsoft SQL Server 2008 R2 SP1 Feature Pack](https://www.microsoft.com/download/details.aspx?id=30437) for SQL Server 2008, or [Microsoft SQL Server 2012 Feature Pack](https://www.microsoft.com/download/details.aspx?id=29065) for SQL Server 2012 in the Microsoft Download Center. ## Prerequisites for creating a map view @@ -91,7 +91,7 @@ Follow these steps to create a map view for a SharePoint list programmatically. > [!NOTE] > The JSLink property is not supported on Survey or Events lists. A SharePoint calendar is an Events list. - ```cs + ```csharp class Program { static void Main(string[] args) diff --git a/docs/general-development/create-a-sharepoint-workflow-app-using-visual-studio-2012.md b/docs/general-development/create-a-sharepoint-workflow-app-using-visual-studio-2012.md index 26423c63a..6e650bcf0 100644 --- a/docs/general-development/create-a-sharepoint-workflow-app-using-visual-studio-2012.md +++ b/docs/general-development/create-a-sharepoint-workflow-app-using-visual-studio-2012.md @@ -2,9 +2,8 @@ title: Create a SharePoint workflow app using Visual Studio 2012 description: Walk through the process of creating a workflow SharePoint Add-in using Microsoft Visual Studio 2012. ms.date: 12/22/2020 -ms.prod: sharepoint ms.assetid: 7923d60d-84b9-44d6-8185-e5236efaf502 -localization_priority: Priority +ms.localizationpriority: high --- # Create a SharePoint workflow app using Visual Studio 2012 diff --git a/docs/general-development/create-a-workflow-with-elevated-permissions-by-using-the-sharepoint-workflo.md b/docs/general-development/create-a-workflow-with-elevated-permissions-by-using-the-sharepoint-workflo.md index 1822928ed..cf9ffd1c1 100644 --- a/docs/general-development/create-a-workflow-with-elevated-permissions-by-using-the-sharepoint-workflo.md +++ b/docs/general-development/create-a-workflow-with-elevated-permissions-by-using-the-sharepoint-workflo.md @@ -1,43 +1,36 @@ --- title: Create a workflow with elevated permissions by using the SharePoint Workflow platform description: Create SharePoint workflows that access objects in SharePoint that require elevated permissions. These solutions grant permissions to the workflow app and wrap actions with the App Step. -ms.date: 12/29/2017 -ms.prod: sharepoint +ms.date: 05/18/2023 ms.assetid: 4656f6a0-36fd-4b7d-898e-8cd4bdbbda57 -localization_priority: Priority +ms.localizationpriority: high --- - # Create a workflow with elevated permissions by using the SharePoint Workflow platform - - This article describes how to create SharePoint workflows that access objects in SharePoint that require elevated permissions. These solutions use two features: granting permissions to the workflow app and wrapping actions with the App Step. > [!NOTE] > SharePoint 2010 workflows have been retired since August 1, 2020 for new tenants and removed from existing tenants on November 1, 2020. If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions. For more info, see [SharePoint 2010 workflow retirement](https://support.microsoft.com/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f). - -> [!IMPORTANT] -> This article assumes that the SharePoint Workflow platform has been installed and configured and that SharePoint has been configured for add-ins. For more information about SharePoint Workflows and SharePoint Add-ins, including installation and configuration, see [Workflows in SharePoint](workflows-in-sharepoint.md) and [Install and manage SharePoint Add-ins](../sp-add-ins/sharepoint-add-ins.md). +> [!IMPORTANT] +> This article assumes that the SharePoint Workflow platform has been installed and configured and that SharePoint has been configured for add-ins. For more information about SharePoint Workflows and SharePoint Add-ins, including installation and configuration, see [Workflows in SharePoint](workflows-in-sharepoint.md) and [Install and manage SharePoint Add-ins](../sp-add-ins/sharepoint-add-ins.md). Imagine that as a SharePoint administrator, you would like to define some processes for managing user requests for purchases of add-ins from the Office Store. In the simplest case, you want to send an acknowledgment email when a user requests an add-in. In addition, you might also want to add structure to the request approval process. - -By default, workflow does not have permissions to access the app catalog. Catalog lists in SharePoint require owner (full control) permissions. Workflows generally run at a permission level equivalent to write. - + +By default, workflow does not have permissions to access the app catalog. Catalog lists in SharePoint require owner (full control) permissions. Workflows generally run at a permission level equivalent to write. + To solve this, you have to create a workflow with elevated permissions by doing the following in the Site Collection site: 1. Allow the workflow to use add-in permissions. - -2. Grant full control permission to the workflow. - -3. Develop the workflow to wrap actions inside an App Step. +1. Grant full control permission to the workflow. +1. Develop the workflow to wrap actions inside an App Step. ## Allow a workflow to use add-in permissions on a SharePoint site The first step is to allow the workflow to use add-in permissions. You configure a workflow to use add-in permissions on the **Site settings** page of the SharePoint site where the workflow runs. The following procedure configures the SharePoint site to allow the workflow to use add-in permissions. - -> [!IMPORTANT] + +> [!IMPORTANT] > The procedure must be completed by a user that has **Site Administrator** permissions. ### To allow workflow to use add-in permissions @@ -46,79 +39,71 @@ The first step is to allow the workflow to use add-in permissions. You configure ![Settings menu](../images/SPD15-WFAppPermissions1.png) -2. Go to **Site settings**. - -3. In the **Site Actions** section, select **Manage site features**. +1. Go to **Site settings**. +1. In the **Site Actions** section, select **Manage site features**. +1. Locate the feature called **Workflows can use app permissions**, as shown in the figure, and then select **Activate**. -4. Locate the feature called **Workflows can use app permissions**, as shown in the figure, and then select **Activate**. - - > [!WARNING] - > This feature will not activate unless you have properly configured the SharePoint Workflow platform and SharePoint Add-ins. + > [!WARNING] + > This feature will not activate unless you have properly configured the SharePoint Workflow platform and SharePoint Add-ins. - ![Workflow can use app permissions feature](../images/SPD15-WFAppPermissions2.png) - + ![Workflow can use app permissions feature](../images/SPD15-WFAppPermissions2.png) ## Grant full control permission to a workflow For the workflow to function properly, it must be granted full control on the site. The following procedure grants full control permission to the workflow. - -> [!IMPORTANT] + +> [!IMPORTANT] > The procedure must be completed by a user that has **Site Owner** permissions. The workflow must already be published to the SharePoint site. ### To grant full control permission to a workflow 1. Select the **Settings** icon. - + ![Settings menu](../images/SPD15-WFAppPermissions1.png) -2. Go to **Site settings**. - -3. In the **Users and Permissions** section, select **Site app permissions**. - -> [!IMPORTANT] -> In SharePoint Online, select **Site collection app permissions**. This option is only visible to **Site Collection Administrators**. - -4. Copy the **client** section of the **App Identifier**. This is the identifier between the last "|" and the "@" sign, as shown in the figure. - - ![Selecting App Identifier](../images/SPD15-WFAppPermissions3.png) - -5. Go to the **Grant permission to an app** page. This must be done by browsing to the appinv.aspx page of the site. - - Example: `http://{hostname}/{the Site Collection}/_layouts/15/appinv.aspx`. - - > [!NOTE] - > The 'app' in this step refers to the workflow add-in in general and not just a specific workflow. Individual workflows cannot be access controlled. When you enable add-in permissions, you are enabling for all workflows within the Site Collection. - - For more information about setting up a workflow, see the [Blog article from Sympraxis Consulting: Looping Through Content in a SharePoint Site Workflow](http://sympmarc.com/series/looping-through-content-in-a-sharepoint-2013-site-workflow/) - - The following figure shows an example. - - ![The appinv.aspx URL example and page.](../images/SPD15-WFAppPermissions4.png) - -6. Paste the client ID in the **App Id** field, and then select **Lookup**, as shown in the previous figure. - -7. Paste the following code in the **Permission Request XML** field to grant full control permission *(note: this code block was updated on 12/29/17 to include the `AllowAppOnlyPolicy`)*. - - ```XML +1. Go to **Site settings**. +1. In the **Users and Permissions** section, select **Site app permissions**. + + > [!IMPORTANT] + > In SharePoint Online, select **Site collection app permissions**. This option is only visible to **Site Collection Administrators**. + +1. Copy the **client** section of the **App Identifier**. This is the identifier between the last "|" and the "@" sign, as shown in the figure. + + ![Selecting App Identifier](../images/SPD15-WFAppPermissions3.png) + +1. Go to the **Grant permission to an app** page. This must be done by browsing to the appinv.aspx page of the site. + + Example: `http://{hostname}/{the Site Collection}/_layouts/15/appinv.aspx`. + + > [!NOTE] + > The 'app' in this step refers to the workflow add-in in general and not just a specific workflow. Individual workflows cannot be access controlled. When you enable add-in permissions, you are enabling for all workflows within the Site Collection. + + For more information about setting up a workflow, see the [Blog article from Sympraxis Consulting: Looping Through Content in a SharePoint Site Workflow](http://sympmarc.com/series/looping-through-content-in-a-sharepoint-2013-site-workflow/) + + The following figure shows an example. + + ![The appinv.aspx URL example and page.](../images/SPD15-WFAppPermissions4.png) + +1. Paste the client ID in the **App Id** field, and then select **Lookup**, as shown in the previous figure. +1. Paste the following code in the **Permission Request XML** field to grant full control permission *(note: this code block was updated on 12/29/17 to include the `AllowAppOnlyPolicy`)*. + + ```XML + ``` + + > [!WARNING] + > There are no placeholders in the **Scope** value. It is a literal value. Enter it exactly as it appears here. - ``` + The following figure shows an example of the completed page _(note that the code in the **Permission Request XML** area does not reflect the recent update to the code in Step 7)_. - > [!WARNING] - > There are no placeholders in the **Scope** value. It is a literal value. Enter it exactly as it appears here. + ![Looking up an App Id.](../images/SPD15-WFAppPermissions5.png) - The following figure shows an example of the completed page _(note that the code in the **Permission Request XML** area does not reflect the recent update to the code in Step 7)_. - - ![Looking up an App Id.](../images/SPD15-WFAppPermissions5.png) +1. Select **Create**. +1. You are then asked to trust the workflow add-in, as shown in the following figure. Select **Trust It**. -8. Select **Create**. - -9. You are then asked to trust the workflow add-in, as shown in the following figure. Select **Trust It**. - - ![Trust the Workflow app.](../images/SPD15-WFAppPermissions6.png) - + ![Trust the Workflow app.](../images/SPD15-WFAppPermissions6.png) ## Wrap actions inside an App Step @@ -126,73 +111,60 @@ Finally, you need to wrap the workflow actions inside an App Step. The following ### To wrap actions inside an App Step -1. Open the app catalog site in SharePoint Designer. - -2. Create a new Custom List on which to run the workflow. In this example, the list name is **App Demo**. - -3. Select **Workflows** in the navigation window. - -4. Create a new **List Workflow** for the **App Demo** list, as shown in the figure. +1. Open the app catalog site in SharePoint Designer. +1. Create a new Custom List on which to run the workflow. In this example, the list name is **App Demo**. +1. Select **Workflows** in the navigation window. +1. Create a new **List Workflow** for the **App Demo** list, as shown in the figure. + + ![Create a new List Workflow.](../images/SPD15-WFAppPermissions7.png) + +1. Insert an **App Step**, as shown in the figure. + + ![Adding an App Step.](../images/SPD15-WFAppPermissions8.png) + +1. Insert a **Send an Email** action in the **App Step**. +1. Select the **Address book** button. In the **To** field, select **Workflow Lookup for a User**, and then select **Add** as shown in the figure. - ![Create a new List Workflow.](../images/SPD15-WFAppPermissions7.png) + ![Select Workflow lookup for a user.](../images/SPD15-WFAppPermissions9.png) -5. Insert an **App Step**, as shown in the figure. - - ![Adding an App Step.](../images/SPD15-WFAppPermissions8.png) +1. Enter the **Created By** field as the lookup value, as shown in the figure. -6. Insert a **Send an Email** action in the **App Step**. - -7. Select the **Address book** button. In the **To** field, select **Workflow Lookup for a User**, and then select **Add** as shown in the figure. + ![Lookup for Person dialog.](../images/SPD15-WFAppPermissions10.png) - ![Select Workflow lookup for a user.](../images/SPD15-WFAppPermissions9.png) - -8. Enter the **Created By** field as the lookup value, as shown in the figure. +1. Enter **Email** from the **App Demo** list in the email message body. +1. Select **OK** to return to the workflow. The completed workflow is shown in the figure. - ![Lookup for Person dialog.](../images/SPD15-WFAppPermissions10.png) - -9. Enter **Email** from the **App Demo** list in the email message body. - -10. Select **OK** to return to the workflow. The completed workflow is shown in the figure. + ![Email action in App Step.](../images/SPD15-WFAppPermissions11.png) - ![Email action in App Step.](../images/SPD15-WFAppPermissions11.png) - -11. Select the **Workflow Settings** icon in the ribbon, as shown in the figure. - - ![Workflow Settings icon in ribbon.](../images/SPD15-WFAppPermissions12.png) +1. Select the **Workflow Settings** icon in the ribbon, as shown in the figure. -12. Clear the check box next to **Automatically update the workflow status to the current stage name**, and then select **Publish**. - - ![Clear automatic updates check mark and publish.](../images/SPD15-WFAppPermissions13.png) - + ![Workflow Settings icon in ribbon.](../images/SPD15-WFAppPermissions12.png) - +1. Clear the check box next to **Automatically update the workflow status to the current stage name**, and then select **Publish**. + + ![Clear automatic updates check mark and publish.](../images/SPD15-WFAppPermissions13.png) ## Understand how it works To understand why elevating permissions for a workflow is required, consider that workflows are fundamentally add-ins for SharePoint, and they follow the same authorization rules of the add-in model. The default configuration for workflow is that the effective permissions of the workflow are an intersection of user permissions and the add-in permissions, as shown in the figure. - + ![Permissions diagram.](../images/SPD15-WFAppPermissions14.png) - + Two reasons why it is necessary to elevate permissions to create a workflow in the App Request list are: - By default, workflow only has write permission. - - The user has no permissions. - -The first step to solve this problem is to allow the application to authorize by using only its identity and ignoring that of the user. This is done by enabling the App Step feature. The second step grants full control permission to the workflow. - + +The first step to solve this problem is to allow the application to authorize by using only its identity and ignoring that of the user. This is done by enabling the App Step feature. The second step grants full control permission to the workflow. + The following diagram illustrates the change in permissions. - + ![Permissions matrix.](../images/SPD15-WFAppPermissions15.png) - - ## See also - [Blog article from the SharePoint Designer team: Workflow package and deploy scenario](https://blogs.msdn.microsoft.com/sharepointdesigner/2012/08/29/packaging-sharepoint-2013-list-site-and-reusable-workflow-and-how-to-deploy-the-package/) - [What's new in workflow in SharePoint](what-s-new-in-workflows-for-sharepoint.md) -- [Getting started with SharePoint workflow](get-started-with-workflows-in-sharepoint.md) +- [Getting started with SharePoint workflow](get-started-with-workflows-in-sharepoint.md) - [Workflow actions and activities reference for SharePoint](workflow-actions-and-activities-reference-for-sharepoint.md) - [Workflow development in SharePoint Designer and Visio](workflow-development-in-sharepoint-designer-and-visio.md) - - diff --git a/docs/general-development/create-associations-in-sharepoint.md b/docs/general-development/create-associations-in-sharepoint.md index eecc62841..77deedd3e 100644 --- a/docs/general-development/create-associations-in-sharepoint.md +++ b/docs/general-development/create-associations-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Create associations in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This article contains links to create associations in SharePoint. +ms.date: 06/07/2022 ms.assetid: 202599e3-232e-4b3a-9da5-c11f6e972283 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/create-hybrid-connectivity-apps-for-sharepoint.md b/docs/general-development/create-hybrid-connectivity-apps-for-sharepoint.md index 45c8a3f3c..f88e805a7 100644 --- a/docs/general-development/create-hybrid-connectivity-apps-for-sharepoint.md +++ b/docs/general-development/create-hybrid-connectivity-apps-for-sharepoint.md @@ -1,231 +1,111 @@ --- title: Create hybrid connectivity apps for SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article with links to learn about the process of developing and deploying apps for SharePoint hybrid connectivity solutions. +ms.date: 05/18/2023 ms.assetid: 311f036e-3442-4497-b35e-442b665462d3 -localization_priority: Normal +ms.localizationpriority: medium --- - # Create hybrid connectivity apps for SharePoint + Learn about the process of developing and deploying apps for SharePoint hybrid connectivity solutions. + ## Hybrid connectivity in SharePoint and SharePoint Online - As businesses move to using SharePoint Online, they need a way to expose large amounts of proprietary data safely and securely. To help solve this challenge, SharePoint introduced hybrid connectivity. - - - + The Business Connectivity Services (BCS) hybrid connectivity capability lets SharePoint consume data housed on-premises, inside corporate firewalls, and secured by various forms of authentication. With hybrid connectivity functionality, SharePoint Online can access this data securely over the web as if it was on the same internal network. Once hybrid connectivity is configured, users can work with data that is secured within the business' infrastructure. They can access and manipulate the data according to the permissions that they have been granted in SharePoint. - - - + For a complete description of how to configure a working hybrid solution, see [Hybrid for SharePoint](https://technet.microsoft.com/library/jj838715.aspx). This series of articles walks you through all the requirements of configuring data sources, reverse proxies, search, security, networking, and everything else needed to set up the end-to-end scenario. - - - -> **Caution:** -> To configure a hybrid SharePoint environment, you need a combination of expert skills and significant hands-on experience with SharePoint, SharePoint Online, and related products and technologies. We recommend that you engage Microsoft Consulting Services to provide technical guidance and support during the design and deployment of your hybrid environment. > For more information, see [Microsoft Services](https://www.microsoft.com/microsoftservices/deploy.aspx). - - - +> [!CAUTION] +> To configure a hybrid SharePoint environment, you need a combination of expert skills and significant hands-on experience with SharePoint, SharePoint Online, and related products and technologies. We recommend that you engage Microsoft Consulting Services to provide technical guidance and support during the design and deployment of your hybrid environment. > For more information, see [Microsoft Services](https://www.microsoft.com/en-us/microsoft-365/products-apps-services). For you to be able to create an app that consumes data from an internal data source through BCS and the hybrid connection, this article assumes that you have already followed the procedures to configure your hybrid environment. - - - ## Create hybrid connectivity apps - Creating a hybrid SharePoint Add-in is essentially the same as creating any SharePoint Add-in. - - - -Follow these steps to create a hybrid app: - - - - -- [Prepare the data source](#bkmk_PrepareDataSource) - - -- [Create an SharePoint Add-in](#bkmk_CreateAnApp) - - -- [Create an external content type](#bkmk_CreateECT) - - -- [Deploy the hybrid app](#bkmk_DeployHybridApp) - - + +Follow these steps to create a hybrid app + +- [Prepare the data source](#prepare-the-data-source) +- [Create an SharePoint Add-in](#create-an-sharepoint-add-in) +- [To add an external content ty](#to-add-an-external-content-type) +- [Deploy the hybrid app](#deploy-the-hybrid-app) ### Prepare the data source - - -Most of the time, the data source is already in place and is servicing any number of business applications. However, that data may only be available from inside the corporate security infrastructure. If your data does exist on a server located on the inside of a corporate firewall, or is secured by some other means, the next step is to expose that data to BCS, which is also housed inside the firewall. A network device is configured to translate calls from SharePoint Online to the internal SharePoint farm. This device is referred to as a "reverse proxy" and allows the SharePoint Add-in located in the cloud to call into BCS located inside the firewall. BCS handles all the data connectivity from there. - - - -To make this data available to BCS, you should expose it as an OData source. You do this by creating an Internet Information Services (IIS) website that will host the service and allow BCS to talk to the data source through OData and Representational State Transfer (REST) endpoints. - - - -To create an OData endpoint, you will need to follow these steps for creating a Windows Communication Foundation (WCF) data service. - - - -### To create a WCF data service +Most of the time, the data source is already in place and is servicing any number of business applications. However, that data may only be available from inside the corporate security infrastructure. If your data does exist on a server located on the inside of a corporate firewall, or is secured by some other means, the next step is to expose that data to BCS, which is also housed inside the firewall. A network device is configured to translate calls from SharePoint Online to the internal ShePoint farm. This device is referred to as a "reverse proxy" and allows the SharePoint Add-in located in the cloud to call into BCS located inside the firewall. BCS handles all the data connectivity from there. + +To make this data available to BCS, you should expose it as an OData source. You do this by creating an Internet Information Services (IIS) website that will host the service and allow BCS to talk to the data source through OData and Representational State Transfer (REST) endpoints +To create an OData endpoint, you will need to follow these steps for creating a Windows Communication Foundation (WCF) data service. 1. Create an IIS website running at least Microsoft .NET Framework 4. Secure the site using basic authentication. - + > [!NOTE] - > It's not necessary for SharePoint to be installed on this server. In fact, for the sake of simplicity and performance, it's better if SharePoint is not installed on the server that hosts the WCF data service. - -2. Create a new project in Visual Studio 2012 using the **ASP.NET Empty Web Application** template. - - -3. In **Solution Explorer** add a new **ADO.NET Entity Data Model**. - - -4. Choose the **Generate from database** option in the **Entity Data Model Wizard**. - - -5. Select an existing connection, or create a new one. - - -6. Provide the URL and connection security information. - - -7. Select the items that you want to include in the model, and choose **Finish**. - - -8. Again in **Solution Explorer**, add a new **WCF Data Service** using the Visual Studio template. - - -9. Name the data service, and choose **Next**. - + > It's not necessary for SharePoint to be installed on this server. In fact, for the sake of simplicity and performance, it's better if SharePoint is not installed on the server thathosts the WCF data service + +1. Create a new project in Visual Studio 2012 using the **ASP.NET Empty Web Application** template. +1. In **Solution Explorer** add a new **ADO.NET Entity Data Model**. +1. Choose the **Generate from database** option in the **Entity Data Model Wizard**. +1. Select an existing connection, or create a new one. +1. Provide the URL and connection security information. +1. Select the items that you want to include in the model, and choose **Finish**. +1. Again in **Solution Explorer**, add a new **WCF Data Service** using the Visual Studio template. +1. Name the data service, and choose **Next**. + At this point, the entity model will be created and the resulting classes will be included in your project. - - -10. Set the security to the entities created by replacing the `/* TODO: put your data source class name here */` with the class name of the entity model you just created and specifying which entities you want to grant permissions to. - - -For a complete tutorial of how to set this up, see the following: - - - - -- [Getting Started With OData Part 1: Building an OData Service](https://msdn.microsoft.com/data/gg601462) - - -- [Quickstart (WCF Data Services)](https://msdn.microsoft.com/library/cc668796.aspx) - - -### Create an SharePoint Add-in - +1. Set the security to the entities created by replacing the `/* TODO: put your data source class name here */` with the class name of the entity model you just created and specifying which entities you want to grant permissions to. -One of the assumptions we are making here is that you are developing your app inside the corporate firewall. This represents a scenario where a developer working for a company would have a computer located behind the protection of the security infrastructure, developing and testing the app until it is ready to be deployed. This simplifies the process of connecting to the data source from Visual Studio, and uses Office Developer Tools for Visual Studio 2013 to automatically generate the external content type in the next step. - - - +For a complete tutorial of how to set this up, see the following: -### To create a new app +- [Getting Started With OData Part 1: Building an OData Service](https://msdn.microsoft.com/data/gg601462) +- [Quickstart (WCF Data Services)](https://msdn.microsoft.com/library/cc668796.aspx) +### Create an SharePoint Add-in -1. Open Visual Studio 2012 on your development computer that has Office Developer Tools for Visual Studio 2013 and SharePoint installed. - - -2. Create a new app for SharePoint. - - -3. Specify the name of the app, the local SharePoint URL that will host your site for testing, and how you want the app to be hosted. Choose **Finish**. - - +One of the assumptions we are making here is that you are developing your app inside the corporate firewall. This represents a scenario where a developer working for a company would have a computer located behind the protection of the security infrastructure, developing and testing the app until it is ready to be deployed. This simplifies the process of connecting to the data source from Visual Studio, and uses Office Developer Tools for Visual Studio 2013 to automatically generate the external content type in e next step. -### Create an external content type - +### To create a new app + +1. Open Visual Studio 2012 on your development computer that has Office Developer Tools for Visual Studio 2013 and SharePoint stalled. +1. Create a new app for SharePoint. +1. Specify the name of the app, the local SharePoint URL that will host your site for testing, and ### Create an external content type To add a BDC model or external content type to your project, do the following. - - - ### To add an external content type - 1. With your new project still open, open the shortcut menu for the solution, and choose **Add**, **Content types for an External Data source**. - - -2. The first page of the wizard is used to specify the URL of the data service. On the **Specify OData Source** page, enter the URL of the OData service that you want to connect to. The URL should resemble the following: **http://services.odata.org/Northwind/Northwind.svc/**. - - -3. Choose a name for your OData source, and then choose **Next**. - - -4. A list of data entities that are being exposed by the OData service appears. Make sure that the **Create list instances for the selected data entities** check box is selected. - - -5. Select one or more of the entities, and choose **Finish**. - - -6. The last thing you have to do before deployment is modify the URL in your newly created external content type file. - - Open the .ect file in an XML editor. - - -7. Modify the `ODataServiceMetadataUrl` property to point to the URL that allows access through the reverse proxy. - - -8. Modify the `ODataServiceUrl` property with the URL that allows access through the reverse proxy. - - +1. The first page of the wizard is used to specify the URL of the data service. On the **Specify OData Source** page, enter the URL of the OData service that you want to connect to. The URL should resemble the following: `http://services.odata.org/Northwind/Northwind.svc/`. +1. Choose a name for your OData source, and then choose **Next**. +1. A list of data entities that are being exposed by the OData service appears. Make sure that the +1. The last thing you have to do before deployment is modify the URL in your newly created external content type file. + + Open the **\*.ect** file in an XML editor. + +1. Modify the `ODataServiceMetadataUrl` property to point to the URL that allows access through the reverse proxy. +1. Modify the `ODataServiceUrl` property with the URL that allows access through the reverse proxy. + For information about how to add an OData-based external content type, see [How to: Create an external content type from an OData source in SharePoint](how-to-create-an-external-content-type-from-an-odata-source-in-sharepoint.md). - - - ### Deploy the hybrid app - When it is time to deploy your app, you have a couple of choices. You can deploy it directly to a tenancy using F5 deployment, or you can package it using the publishing features of Visual Studio to create an .app file. This file can then be given to the SharePoint Online tenant administrator and uploaded. - - - -For information about deploying SharePoint Add-ins, see the following: - - - - -- [Deploying and installing SharePoint Add-ins: methods and options](https://msdn.microsoft.com/library/d15a74a7-3c10-485a-9885-7ef11aaa0d90%28Office.15%29.aspx) - - -- [Publish SharePoint Add-ins by using Visual Studio](https://msdn.microsoft.com/library/8137d0fa-52e2-4771-8639-60af80f693bb%28Office.15%29.aspx) - - -You can also take the BDCM file created for the external content type and extract that to be used at any level above the app. This is demonstrated in [How to: Convert an add-in-scoped external content type to tenant-scoped](how-to-convert-an-add-in-scoped-external-content-type-to-tenant-scoped.md). - - - + +For information about deploying SharePoint Add-ins, see the following: + +- [Deploying and installing SharePoint Add-ins: methods and options](https://msdn.microsoft.com/library/d15a74a7-3c10-485a-9885-7ef11aaa0d90%28Office.15%29.aspx + +- [Publish SharePoint Add-ins by using Visual Studio](https://msdn.microsoft.com/library/8137d0fa-52e2-4771-8639-60af80f693bb%28Office.15%29.aspx) + +You can also take the BDCM file created for the external content type and extract that to be used at any level above the app. This is demonstrated in [How to: Convert an add-in-scoped external ## See also - - - -- [Hybrid for SharePoint](https://technet.microsoft.com/library/jj838715.aspx) - - -- [Business Connectivity Services in SharePoint](business-connectivity-services-in-sharepoint.md) - - -- [How to: Create an external content type from an OData source in SharePoint](how-to-create-an-external-content-type-from-an-odata-source-in-sharepoint.md) - - -- [Publish SharePoint Add-ins by using Visual Studio](https://msdn.microsoft.com/library/8137d0fa-52e2-4771-8639-60af80f693bb%28Office.15%29.aspx) - - +- [Hybrid for SharePoint](https://technet.microsoft.com/library/jj838715.aspx) +- [Business Connectivity Services in SharePoint](business-connectivity-services-in-sharepoint.md) +- [How to: Create an external content type from an OData source in SharePoint](how-to-create-an-external-content-type-from-an-odata-source-in-sharepoint.md) diff --git a/docs/general-development/create-sharepoint-no-code-solutions.md b/docs/general-development/create-sharepoint-no-code-solutions.md index 09cf487fc..746ba7d28 100644 --- a/docs/general-development/create-sharepoint-no-code-solutions.md +++ b/docs/general-development/create-sharepoint-no-code-solutions.md @@ -1,9 +1,9 @@ --- title: Create SharePoint no-code solutions -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article with links to learn about SharePoint Composites and creating no-code solutions. +ms.date: 06/07/2022 ms.assetid: 9511846c-d2c6-4f23-b5de-24be4749598a -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/creating-a-workflow-by-using-sharepoint-designer-and-the-sharepoint-wo.md b/docs/general-development/creating-a-workflow-by-using-sharepoint-designer-and-the-sharepoint-wo.md index f56cd518e..2a41cd9e9 100644 --- a/docs/general-development/creating-a-workflow-by-using-sharepoint-designer-and-the-sharepoint-wo.md +++ b/docs/general-development/creating-a-workflow-by-using-sharepoint-designer-and-the-sharepoint-wo.md @@ -1,212 +1,86 @@ --- title: Creating a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article with links to learn about creating a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform. +ms.date: 05/09/2023 ms.assetid: c05e0127-c6f5-48b8-b8f2-cbcc30149c8b -localization_priority: Priority +ms.localizationpriority: high --- +# Creating a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform +Learn how to install, open, and create a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform. -# Creating a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform -Learn how to install, open, and create a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform. - -> [!NOTE] -> SharePoint 2010 workflows have been retired since August 1, 2020 for new tenants and removed from existing tenants on November 1, 2020. If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions. For more info, see [SharePoint 2010 workflow retirement](https://support.microsoft.com/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f). +> [!CAUTION] +> SharePoint 2010 workflows have been retired since August 1, 2020 for new tenants and removed from existing tenants on November 1, 2020. If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions. For more information, see [SharePoint 2010 workflow retirement](https://support.microsoft.com/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f). +> [!CAUTION] +> SharePoint 2013 workflows are scheduled for retirement in April 2024. For more information, see: [SharePoint 2013 workflow retirement](https://support.microsoft.com/office/sharepoint-2013-workflow-retirement-4613d9cf-69aa-40f7-b6bf-6e7831c9691e). ## Install SharePoint Designer 2013 - -SharePoint Designer 2013 is a free download. To download and install SharePoint Designer 2013 follow these steps: - - - +SharePoint Designer 2013 is a free download. To download and install SharePoint Designer 2013 follow these steps: ### To install SharePoint Designer 2013 - -1. Open your web browser and navigate to the Microsoft Download Center: [https://www.microsoft.com/download](https://www.microsoft.com/download). - - -2. Type SharePoint Designer 2013 in the search field. - - -3. Click the link for "SharePoint Designer 2013". - - -4. Read the overview, system requirements, and installation instructions. Make sure your system is compatible. - - -5. Select your platform type: 64-bit ( **x64**) or 32-bit ( **x86**) as shown in the figure. - - -6. Follow the instructions to install SharePoint Designer 2013. - - +1. Open your web browser and navigate to the Microsoft Download Center: [https://www.microsoft.com/download](https://www.microsoft.com/download). +1. Type SharePoint Designer 2013 in the search field. +1. Click the link for "SharePoint Designer 2013". +1. Read the overview, system requirements, and installation instructions. Make sure your system is compatible. +1. Select your platform type: 64-bit ( **x64**) or 32-bit ( **x86**) as shown in the figure. +1. Follow the instructions to install SharePoint Designer 2013. **Figure: SharePoint Designer 2013 download page** - - - - - - - ![The SharePoint Designer 2013 Download page.](../images/SPD15-install-connect-1.png) - - - - - - - - - - - ## Open SharePoint Designer 2013 and connect to a SharePoint site - -SharePoint Designer 2013 installs as an Office 2013 application. To open SharePoint Designer 2013 and connect to a SharePoint site follow these steps: - - - -2013 -### To open SharePoint Designer 2013 and connect to a SharePoint site +SharePoint Designer 2013 installs as an Office 2013 application. To open SharePoint Designer 2013 and connect to a SharePoint site follow these steps: +### To open SharePoint Designer 2013 and connect to a SharePoint site -1. Open SharePoint Designer 2013 by selecting it on the **Start** menu. Click **Start** icon, click **All Programs**, click **Microsoft Office 2013**, and then click **SharePoint Designer 2013**. - - -2. Click **Open Site** on the SharePoint Designer 2013 start page. - - -3. Enter the SharePoint site that you want to connect to. For example, http://www.contoso.com/sites/a-sharepoint-site. - - -4. Click **Open** to open the site. - - -5. Enter your credentials, if prompted. (If security is not integrated with the computer you signed in on then you are prompted to enter your credentials.) Make sure to use credentials that have access to the SharePoint site. - - +1. Open SharePoint Designer 2013 by selecting it on the **Start** menu. Click **Start** icon, click **All Programs**, click **Microsoft Office 2013**, and then click **SharePoint Designer 2013**. +1. Click **Open Site** on the SharePoint Designer 2013 start page. +1. Enter the SharePoint site that you want to connect to. For example, `https://www.contoso.com/sites/a-sharepoint-site`. +1. Click **Open** to open the site. +1. Enter your credentials, if prompted. (If security is not integrated with the computer you signed in on then you are prompted to enter your credentials.) Make sure to use credentials that have access to the SharePoint site. ## Create a List workflow based on the SharePoint Workflow platform - SharePoint Designer 2013 can be used for many important tasks. The navigational pane is used to switch between different aspects of SharePoint Designer 2013. To create a new List workflow based on the SharePoint Workflow platform, follow these steps: - - - ### To create a workflow based on the SharePoint Workflow platform - 1. Click the Workflows node in the Navigation pane. - - -2. Click the **List Workflow** drop-down in the **New** section of the ribbon, as shown in the figure. - - -3. Select the list that you want to associate with the new workflow. - - -4. On the **Create List Workflow** dialog box, enter a name and description for the workflow and then make sure that the **Platform Type** is set to **SharePoint 2013 Workflow**, as shown in the figure. - +1. Click the **List Workflow** drop-down in the **New** section of the ribbon, as shown in the figure. +1. Select the list that you want to associate with the new workflow. +1. On the **Create List Workflow** dialog box, enter a name and description for the workflow and then make sure that the **Platform Type** is set to **SharePoint 2013 Workflow**, as shown in the figure. + > [!NOTE] - > If you do not see SharePoint Workflow as an available platform type then Workflow Manager is not configured to work with the SharePoint farm. See [Configure Workflow Manager to work with the SharePoint Server 2013 Farm](https://technet.microsoft.com/library/jj658588.aspx#section5). + > If you do not see SharePoint Workflow as an available platform type then Workflow Manager is not configured to work with the SharePoint farm. See [Configure Workflow Manager to work with the SharePoint Server 2013 Farm](https://technet.microsoft.com/library/jj658588.aspx#section5). -5. Click **OK** to create the workflow. - - +1. Click **OK** to create the workflow. **Figure: The ribbon button for creating a new list workflow** - - - - - - - ![SharePoint Designer 2013 - New List Workflow](../images/SPD15-install-connect-2.png) - - - - - - - - - - - **Figure: Create List Workflow dialog box** - - - - - - - ![Workflow Creation Dialog](../images/SPD15-install-connect-3.png) - - - - - - - - - - - -Now that the workflow is created, you can add Actions, Conditions, Stages, Steps, and Loops to build your workflow. These workflow components are available in the ribbon of SharePoint Designer 2013, as shown in the figure. - - - -**Figure: Workflow items for the SharePoint Workflow platform** +Now that the workflow is created, you can add Actions, Conditions, Stages, Steps, and Loops to build your workflow. These workflow components are available in the ribbon of SharePoint Designer 2013, as shown in the figure. - - - +**Figure: Workflow items for the SharePoint Workflow platform** - - - ![Workflow items in the ribbon.](../images/SPD15-install-connect-4.png) - + > [!NOTE] > The previous procedure is used to create a List workflow. A Reusable workflow or Site workflow can be created using the same procedure with the following modification. Instead of selecting the List Workflow button in the ribbon select the **Reusable Workflow** or **Site Workflow** button when creating the workflow. - - - To learn more about the available components of workflow development, see [Workflow actions quick reference (SharePoint Workflow platform)](workflow-actions-quick-reference-sharepoint-workflow-platform.md). - - - ## See also - - - -- [What's new in workflow in SharePoint](https://msdn.microsoft.com/library/6ab8a28b-fa2f-4530-8b55-a7f663bf15ea.aspx) - - -- [Getting started with SharePoint workflow](https://msdn.microsoft.com/library/cc73be76-a329-449f-90ab-86822b1c2ee8.aspx) - - -- [Workflow development in SharePoint Designer and Visio](workflow-development-in-sharepoint-designer-and-visio.md) - - - - - - +- [What's new in workflow in SharePoint](https://msdn.microsoft.com/library/6ab8a28b-fa2f-4530-8b55-a7f663bf15ea.aspx) +- [Getting started with SharePoint workflow](https://msdn.microsoft.com/library/cc73be76-a329-449f-90ab-86822b1c2ee8.aspx) +- [Workflow development in SharePoint Designer and Visio](workflow-development-in-sharepoint-designer-and-visio.md) diff --git a/docs/general-development/cross-site-publishing-in-sharepoint.md b/docs/general-development/cross-site-publishing-in-sharepoint.md index d19f8e005..bb0aac128 100644 --- a/docs/general-development/cross-site-publishing-in-sharepoint.md +++ b/docs/general-development/cross-site-publishing-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Cross-site publishing in SharePoint +description: SharePoint introduces a cross-site publishing feature that enables you to reuse content across multiple site collections. It uses built-in search capabilities to enable publishing scenarios and architectures. For the first time, you can design sites that cross SharePoint farms—enabling your sites to span the boundary between intranets and the Internet. ms.date: 06/18/2019 -ms.prod: sharepoint ms.assetid: 33f49e69-c1d3-4a6e-8887-5df683cba022 -localization_priority: Normal +ms.localizationpriority: medium --- # Cross-site publishing in SharePoint @@ -11,29 +11,29 @@ localization_priority: Normal SharePoint introduces a cross-site publishing feature that enables you to reuse content across multiple site collections. It uses built-in search capabilities to enable publishing scenarios and architectures. For the first time, you can design sites that cross SharePoint farms—enabling your sites to span the boundary between intranets and the Internet. > [!IMPORTANT] -> This capability is not available in SharePoint Online. Cross-site publishing capability is only available in on-premises deployments. +> This capability is not available in SharePoint Online. Cross-site publishing capability is only available in on-premises deployments. Consider a site with one authoring site collection that feeds multiple publishing site collections, with different domains, all crawled by public search engines and optimized for search engine optimization (SEO). Cross-site publishing enables this scenario and others like it, without requiring you to use content deployment. Cross-site publishing was designed with some common scenarios in mind, including: - + - Share an item list or a page library as a publishing catalog - Consume a catalog from search - Combine cross-site publishing with the variations feature to enable authoring multilingual sites from a common authoring site collection - + ## Catalogs Catalogs, introduced in SharePoint, include a list or library that is shared out to search for consumption on publishing sites. Catalogs enable content to be published across site collections—the cross-site publishing features depend on catalogs. You can use catalogs to really reuse content across your sites and across the boundary between your intranet sites, extranet sites, and Internet sites. For predefined search queries, catalogs are flagged in search. You can surface content stored in catalogs across site collections by using the [Content Search web part in SharePoint](content-search-web-part-in-sharepoint.md). - + ## When should I use cross-site publishing? There are some cases where cross-site publishing is not efficient or appropriate. Whether you have external data sources and how you connect to them, variations, site type, search database implementation, and use of the product catalog are all factors that should influence your decision. Table 1 provides more information about these design considerations. - - - + + + **Table 1. Design considerations for cross-site publishing** @@ -45,126 +45,126 @@ There are some cases where cross-site publishing is not efficient or appropriate |**Variations implementation**
|If you are implementing a basic variations site that makes a pages library, document library, and general lists available in a few languages, cross-site publishing makes sense. The same is true if you choose to implement managed navigation or structured navigation on a variations site.
Cross-site publishing works for some architectures but not others. For example, you can use cross-site publishing to publish content from a variations **SPSite** to a publishing site with variations enabled if the source **SPSite** is not consuming data from another variations site or site collection.
| |**Catalog implementation**
|Whether you implement the product catalog into your site architecture and how you implement it may affect whether cross-site publishing is the most effective or appropriate choice. If you are using the product catalog to support a multilingual variations site configuration and are publishing to an Internet site, you can implement cross-site publishing.
| |**Managed navigation**
|Cross-site publishing works with most implementations of managed navigation and the term store. In some implementations, navigation metadata transfer may not work as expected. For example, when one variations site depends on metadata from another variations site to drive site navigation, and you use cross-site publishing to publish content to the target site, navigation metadata transfer may not work as expected.
| - + ## How can I set up a catalog? -Category pages and catalog item pages are page layouts that you can use to show structured catalog content consistently across a site. SharePoint enables you to create and customize page layouts for SharePoint and above. For more information, see [Customize page layouts for a catalog-based site in SharePoint](https://msdn.microsoft.com/library/office/dn144674.aspx +Category pages and catalog item pages are page layouts that you can use to show structured catalog content consistently across a site. SharePoint enables you to create and customize page layouts for SharePoint and above. For more information, see [Customize page layouts for a catalog-based site in SharePoint](https://msdn.microsoft.com/library/office/dn144674.aspx ). - - - + + + ## Cross-site publishing APIs SharePoint introduces classes that you can use to support cross-site publishing implementation in your code. These APIs are available in the .NET server publishing library. Use them to customize how SharePoint shares lists as catalogs for content reuse or consumes a catalog from search. You can use the members of the following classes in custom code to support cross-site publishing tasks: - - - + + + - Use the **PublishingCatalogUtility** class to retrieve a list of available catalogs, get information about catalogs and their statuses, get information about lists and libraries that can be connected to catalogs, and start or stop sharing catalogs. - - - -```cs - + + + +```csharp + /// Retrieve available catalogs. public static List GetPublishingCatalogs(SPSite site, int startRow, int numberOfRows, string filterText, out int totalNumberOfCatalogs) ``` - - -```cs - + + +```csharp + ///Get catalog information that is saved for a list. public static bool GetCatalogConfiguration(SPList list, out CatalogShareSettings catalogSettings, out string selectedTaxonomyField) ``` - - -```cs - + + +```csharp + ///Stop sharing a list or library as a publishing catalog for cross-publishing content reuse. public static void UnPublishCatalog(SPList list) ``` - Use the **CatalogCollectionManager** class to consume catalogs from search. Learn about the connection that a catalog has to search, and get information about it. Add or remove a catalog from the internal collection of catalogs, and queue an operation to queue up a connection that is configured to rewrite URLs when the **Update** method is called. - - - -```cs - + + + +```csharp + /// Add catalog or site source into the internal CatalogInfo collection, but the source is not persisted into the property bag. public void AddCatalogConnection(CatalogConnectionSettings catalogInfo) ``` - - -```cs - + + +```csharp + /// Queues an Add operation to add a connection configured to rewrite URLs. The connection is added to the store when the Update method is called. -public void AddCatalogConnection(CatalogConnectionSettings catalogInfo, +public void AddCatalogConnection(CatalogConnectionSettings catalogInfo, string[] orderedPropertiesForUrlRewrite, -string webUrl, +string webUrl, string catalogTaxonomyManagedProperty, bool isManualRule) ``` - - -```cs - + + +```csharp + /// Update existing catalog/site source in the internal CatalogInfo collection. Edits are not committed until the Update method is called. public void UpdateCatalogConnection(CatalogConnectionSettings catalogInfo) ``` - - -```cs - + + +```csharp + /// Remove a catalog or site source. Deletion is not committed until the Update method is called. public void DeleteCatalogConnection(string catalogPath) ``` - - -```cs - + + +```csharp + /// Determine whether a connection exists to this source from the site. public bool Contains(string catalogPath) ``` - - -```cs - + + +```csharp + /// Get the settings for a catalog connected to this site. public CatalogConnectionSettings GetCatalogConnectionSettings(string catalogPath) ``` diff --git a/docs/general-development/custom-content-processing-with-the-content-enrichment-web-service-callout.md b/docs/general-development/custom-content-processing-with-the-content-enrichment-web-service-callout.md index e97ef5e14..7c4275829 100644 --- a/docs/general-development/custom-content-processing-with-the-content-enrichment-web-service-callout.md +++ b/docs/general-development/custom-content-processing-with-the-content-enrichment-web-service-callout.md @@ -1,177 +1,96 @@ --- title: Custom content processing with the Content Enrichment web service callout -ms.date: 09/25/2017 -ms.prod: sharepoint +description: This is an article to learn about custom content processing with the Content Enrichment web service callout. +ms.date: 05/18/2023 ms.assetid: bdda92c8-9c8d-416e-9a6b-4a9373686fa0 -localization_priority: Normal +ms.localizationpriority: medium --- - - # Custom content processing with the Content Enrichment web service callout + Learn about the content enrichment web service callout in SharePoint that enables developers to create an external web service to modify managed properties for crawled items during content processing. + Search in SharePoint enables users to modify the managed properties of crawled items before they are indexed by calling out to an external content enrichment web service. The ability to modify managed properties for items during content processing is helpful when performing tasks such as data cleansing, entity extraction, classification, and tagging. - - - +![Content enrichment within content processing](../images/SP15_Content_Enrichment.gif) **Figure 1. Content enrichment within content processing** - - - - - - - -![Content enrichment within content processing](../images/SP15_Content_Enrichment.gif) - - - -Figure 1 shows a part of the process that takes place in the content processing component. The content enrichment web service is a SOAP-based service that you can create to receive a callout from the web service client inside the content processing component. Based on Figure 1, the web service client refers to the Content Enrichment operator inside the content processing component; theweb service refers to the SOAP web service that you implement.The web service receives a configurable payload from the content processing component. Then, the resulting response from the web service is merged into the crawled item before it is added to the search index. The web service client works with managed properties that you can configure as input properties or as output properties. Input properties are sent to the web service; output properties are returned by the web service. Certain managed properties are hidden or are read-only and can't be sent to the web service or received from the web service. See [How to list all read-only managed properties for the Content Enrichment web service](#SP15contentprocess_read-only_managed_properties) for information about how to verify which managed properties are read-only. - -> **Important:** -> The content enrichment callout step can only be configured with a single web service endpoint. Any kind of fault tolerance, or routing capabilities to support multiple implementations must be handled by the developer implementing the web service. In addition, the developer may have various web service implementations hosted at different endpoints; however, at any given time, only one of these endpoints can be used in the configuration. - - - +Figure 1 shows a part of the process that takes place in the content processing component. The content enrichment web service is a SOAP-based service that you can create to receive a callout from the web service client inside the content processing component. Based on Figure 1, the web service client refers to the Content Enrichment operator inside the content processing component; the web service refers to the SOAP web service that you implement.The web service receives a configurable payload from the content processing component. Then, the resulting response from the web service is merged into the crawled item before it is added to the search index. The web service client works with managed properties that you can configure as input properties or as output properties. Input properties are sent to the web service; output properties are returned by the web service. Certain managed properties are hidden or are read-only and can't be sent to the web service or received from the web service. See [How to list all read-only managed properties for the Content Enrichment web service](#how-to-list-all-read-only-managed-properties-for-the-content-enrichment-web-service) for information about how to verify which managed properties are read-only. +> [!IMPORTANT] +> The content enrichment callout step can only be configured with a single web service endpoint. Any kind of fault tolerance, or routing capabilities to support multiple implementations must be handled by the developer implementing the web service. In addition, the developer may have various web service implementations hosted at different endpoints; however, at any given time, only one of these endpoints can be used in the configuration. ## Content enrichment web service contract - The web service client is a SOAP (version 1.1) RPC client with a predefined behavior. The web service contract has the following characteristics: - - - - The content processing component sends a SOAP RPC call to a configurable endpoint over HTTP. - - - The payload contains an array of property objects. - - - The web service performs some custom logic on the array of property objects, and returns an array of modified or new property objects. - - - The web service must send a response to the web service client within a given timeout. - - - No specific authentication or encryption mechanisms are supported as part of the contract. You can, however, apply your own security on the transport mechanism. - - ## Configuring the Content Enrichment web service client - To configure the web service client, you use the following Windows PowerShell cmdlets: - - - - -- [Get-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219783%28office.15%29.aspx) - - -- [Set-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219659%28office.15%29.aspx) - - -- [Remove-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219742%28office.15%29.aspx) - - -- [New-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219502%28office.15%29.aspx) - - + +- [Get-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219783%28office.15%29.aspx) +- [Set-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219659%28office.15%29.aspx) +- [Remove-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219742%28office.15%29.aspx) +- [New-SPEnterpriseSearchContentEnrichmentConfiguration](https://technet.microsoft.com/library/jj219502%28office.15%29.aspx) + Table 1 lists the properties you can configure through the Windows PowerShell cmdlets mentioned previously. - - - **Table 1. Properties that are configurable for the client by using Windows PowerShell cmdlets** - -|**Configuration property**|**Description**|**Default value**| -|:-----|:-----|:-----| -|**Endpoint**
|Specifies the URL of the external web service.
|Empty.
| -|**InputProperties**
|The managed properties that the external web service receives.
|Empty.
| -|**OutputProperties**
|The managed properties that the external web service returns.
|Empty.
| -|**Timeout**
|The amount of time until the web service times out in milliseconds.
Depending on **FailureMode**, the item fails to be processed or a warning is written to the ULS log.
|5000 milliseconds; Valid range [100, 30000].
| -|**SendRawData**
|Enables or disables sending raw data to the web service.
|False.
| -|**MaxRawDataSize**
|The maximum size of raw data sent to the web service in kilobytes (KB). If the binary data of an item exceeds this limit, the item is not sent. This does not prevent the **InputProperties** from being sent, and the **OutputProperties** from being received.
|5120 kilobytes.
| -|**FailureMode**
|Controls the behavior of the web service client when errors occur. When **FailureMode** is set to **ERROR**, any problems that occur during content enrichment processing send a failed callback for that particular item.
When **FailureMode** is set to **WARNING**, the item is indexed, without any modifications by the web service and a warning is written to the ULS log.
|Error.
| -|**DebugMode**
|A mode that when set to **true** enables the content enrichment client to send all managed properties to the client without expecting any properties in return. Any configured **Trigger** property, **InputProperties** property, and **OutputProperties** property are ignored.
|False.
| -|**Trigger**
|A **Boolean** predicate that is executed on every crawled item. If the predicate evaluates to **true**, the record is sent to the web service. Otherwise, the item is passed through to the search index.
|Empty.
| - +| **Configuration property** | **Description** | **Default value** | +| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------- | +| **Endpoint** | Specifies the URL of the external web service. | Empty. | +| **InputProperties** | The managed properties that the external web service receives. | Empty. | +| **OutputProperties** | The managed properties that the external web service returns. | Empty. | +| **Timeout** | The amount of time until the web service times out in milliseconds. Depending on **FailureMode**, the item fails to be processed or a warning is written to the ULS log. | 5000 milliseconds; Valid range [100, 30000]. | +| **SendRawData** | Enables or disables sending raw data to the web service. | False. | +| **MaxRawDataSize** | The maximum size of raw data sent to the web service in kilobytes (KB). If the binary data of an item exceeds this limit, the item is not sent. This does not prevent the **InputProperties** from being sent, and the **OutputProperties** from being received. | 5120 kilobytes. | +| **FailureMode** | Controls the behavior of the web service client when errors occur. When **FailureMode** is set to **ERROR**, any problems that occur during content enrichment processing send a failed callback for that particular item. When **FailureMode** is set to **WARNING**, the item is indexed, without any modifications by the web service and a warning is written to the ULS log. | Error. | +| **DebugMode** | A mode that when set to **true** enables the content enrichment client to send all managed properties to the client without expecting any properties in return. Any configured **Trigger** property, **InputProperties** property, and **OutputProperties** property are ignored. | False. | +| **Trigger** | A **Boolean** predicate that is executed on every crawled item. If the predicate evaluates to **true**, the record is sent to the web service. Otherwise, the item is passed through to the search index. | Empty. | ### How to list all read-only managed properties for the Content Enrichment web service - Certain managed properties are read-only and cannot be output from the web service. These properties can be listed by using the [Get-SPEnterpriseSearchServiceApplication](https://technet.microsoft.com/library/ff608050%28office.15%29.aspx) and [Get-SPEnterpriseSearchMetadataManagedProperty](https://technet.microsoft.com/library/ff607560%28office.15%29.aspx)Windows PowerShell cmdlets, shown in the following example: - - - - -``` +```powershell $ssa = Get-SPEnterpriseSearchServiceApplication Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $ssa | ?{$_.IsReadOnly -or $_.MappingDisallowed -or $_.DeleteDisallowed} - ``` - ## About trigger conditions for configuring the web service callout - A trigger condition is an expression that is used to configure the web service callout. If a trigger condition evaluates to **true**, the web service client performs a callout for that record. If a trigger condition evaluates to **false**, the web service client does not perform a callout and passes the crawled item to the search index. Alternatively, if no trigger condition is configured; all items are sent to the web service. - - - -Trigger conditions use an expression language to refer to the values of managed properties. You can use the operators and functions in the expression language to build simple or complex trigger conditions so you can determine when to perform a web service callout. - - - + +Trigger conditions use an expression language to refer to the values of managed properties. You can use the operators and functions in the expression language to build simple or complex trigger conditions so you can determine when to perform a web service callout. + Table 2 lists examples of trigger conditions. - - - **Table 2. Trigger condition examples for configuring the Content Enrichment web service callout** +| **Expression** | **Description** | **Requirements** | +| :-------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------- | +| MP1 > 2 | Returns **true** if the value of the managed property named MP1 is greater than 2. | MP1 must have a numeric type. | +| IsNull(MP2) | Returns **true** if the managed property named MP2 is not present for the crawled item or is empty/null. | MP2 can be of any type. | +| StartsWith(MP1, "sample") AND MP2 != 18 | Returns **true** if the value in the managed property MP1 starts with "sample" and the value of managed property MP2 is not 18. | MP1 must be of type **string** and MP2 must be a numeric type. | +| IsDay(MP1, 2009, 12, 24) | Checks whether the managed property MP1 contains a **DateTime** that falls on December 24, 2009. | MP1 must be of type **DateTime**. | -|**Expression**|**Description**|**Requirements**| -|:-----|:-----|:-----| -|MP1 > 2
|Returns **true** if the value of the managed property named MP1 is greater than 2.
|MP1 must have a numeric type.
| -|IsNull(MP2)
|Returns **true** if the managed property named MP2 is not present for the crawled item or is empty/null.
|MP2 can be of any type.
| -|StartsWith(MP1, "sample") AND MP2 != 18
|Returns **true** if the value in the managed property MP1 starts with "sample" and the value of managed property MP2 is not 18.
|MP1 must be of type **string** and MP2 must be a numeric type.
| -|IsDay(MP1, 2009, 12, 24)
|Checks whether the managed property MP1 contains a **DateTime** that falls on December 24, 2009.
|MP1 must be of type **DateTime**.
| - -See [Trigger expressions syntax in SharePoint](trigger-expressions-syntax-in-sharepoint.md) for the elements that can be used in a trigger expression and a list of supported functions. - - - +See [Trigger expressions syntax in SharePoint](trigger-expressions-syntax-in-sharepoint.md) for the elements that can be used in a trigger expression and a list of supported functions. ## Implementing the Content Enrichment external web service - -For a basic implementation, do the following: - - - +For a basic implementation, do the following: 1. Include the **Microsoft.Office.Server.Search.ContentProcessingEnrichment.dll** located in `C:\\Program Files\\Microsoft Office Servers\\15.0\\Search\\Applications\\External` in your project as a reference. - - -2. Implement **IContentProcessingEnrichmentService** as a web service. - - +1. Implement **IContentProcessingEnrichmentService** as a web service. ## See also - - - -- [Configure search in SharePoint](configure-search-in-sharepoint.md) - - -- [Custom content processing with the Content Enrichment web service callout](custom-content-processing-with-the-content-enrichment-web-service-callout.md) - - +- [Configure search in SharePoint](configure-search-in-sharepoint.md) +- [Custom content processing with the Content Enrichment web service callout](custom-content-processing-with-the-content-enrichment-web-service-callout.md) diff --git a/docs/general-development/custom-security-trimming-for-search-in-sharepoint-server.md b/docs/general-development/custom-security-trimming-for-search-in-sharepoint-server.md index c92b32cfd..dba0ab609 100644 --- a/docs/general-development/custom-security-trimming-for-search-in-sharepoint-server.md +++ b/docs/general-development/custom-security-trimming-for-search-in-sharepoint-server.md @@ -1,9 +1,9 @@ --- title: Custom security trimming for Search in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Learn about the two kinds of custom security trimmer interfaces, ISecurityTrimmerPre and ISecurityTrimmerPost, and the steps you must take to create a custom security trimmer. +ms.date: 06/09/2022 ms.assetid: fbbf0cc4-e135-426a-9996-34eb954dbd5a -localization_priority: Normal +ms.localizationpriority: medium --- @@ -11,192 +11,192 @@ localization_priority: Normal # Custom security trimming for Search in SharePoint Learn about the two kinds of custom security trimmer interfaces, **ISecurityTrimmerPre** and **ISecurityTrimmerPost**, and the steps you must take to create a custom security trimmer. At query time, Search in SharePoint performs security trimming of search results that are based on the identity of the user submitting the query, by using the security information obtained from the crawl component. - - - + + + You might have certain scenarios, however, in which the built-in security trimming results aren't sufficient for your requirements. In such scenarios, you need to implement custom security trimming. Search in SharePoint provides support for custom security trimming through the [ISecurityTrimmerPre](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPre.aspx) interface, [ISecurityTrimmerPost](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPost.aspx) interface, and [ISecurityTrimmer2](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmer2.aspx) interface (deprecated) in the [Microsoft.Office.Server.Search.Query](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.aspx) namespace. > [!NOTE] > Custom pre-trimmers don't support Windows SIDs in ACLs, only claims. If any of the SID claim types are returned from a custom pre-trimmer, the resulting ACEs in the index will be encoded as a claim, not as SID. Hence they do not match Windows user identities that are based on SIDs. - - - + + + ## Implementing the interfaces for custom security trimming The **ISecurityTrimmerPre** interface carries out pre-trimming, or pre-query evaluation, where the search query is rewritten to add security information before the search query is matched to the search index. The **ISecurityTrimmerPost** interface carries out post-trimming, or post-query evaluation, where the search results are pruned before they are returned to the user. - - - + + + We recommend the use of pre-trimming for performance and general correctness; pre-trimming prevents information leakage for refiner data and hit count instances. Post-trimmers can be used in cases where the security trimming cannot be represented accurately with query filters; for example, if there is a need to filter away documents depending on the local time of the user issuing the query, such as during official business hours only. - - - + + + ### Implementing the ISecurityTrimmerPre interface To create a custom security pre-trimmer for search results, you must create a component that implements the **ISecurityTrimmerPre** interface. - - - + + + The **ISecurityTrimmerPre** interface contains two methods that you must implement: [Initialize(NameValueCollection, SearchServiceApplication)](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPre.Initialize.aspx) and [AddAccess(Boolean, Claims)](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPre.AddAccess.aspx) . - - - + + + #### Initialize Method The **Initialize** method is executed when the security pre-trimmer is loaded into the worker process, and does not execute again until the worker process is recycled. Two parameters are passed into the method: - - - + + + - _staticProperties_: A [NameValueCollection](https://msdn.microsoft.com/library/System.Collections.Specialized.NameValueCollection.aspx) object containing the configuration properties that are specified for the security trimmer when it is registered with the Search service application. - - + + - _searchApplication_: A [SearchServiceApplication](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Administration.SearchServiceApplication.aspx) object that represents the Search service application. - - + + #### AddAccess Method The **AddAccess** method is executed once per pre-trimmer, for each incoming query before the query is evaluated. - - - -Two parameters are passed into this method: - - - + + + +Two parameters are passed into this method: + + + - _sessionProperties_: A **[T:System.Collections.Generic.IDictionary]** object that contains the properties of the query. - - + + - _userIdentity_: A [IIdentity](https://msdn.microsoft.com/library/System.Security.Principal.IIdentity.aspx) object that contains the user identity. - - + + ### Implementing the ISecurityTrimmerPost interface To create a custom security post-trimmer for search results, you must create a component that implements the **ISecurityTrimmerPost** interface. - - - -The **ISecurityTrimmerPost** interface contains two methods that you must implement: [Initialize(NameValueCollection, SearchServiceApplication)](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPost.Initialize.aspx) and **CheckAccess(IList, IList, IDictionary, IIdentity)**. - - - + + + +The **ISecurityTrimmerPost** interface contains two methods that you must implement: [Initialize(NameValueCollection, SearchServiceApplication)](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPost.Initialize.aspx) and **CheckAccess(IList\, IList\, IDictionary\, IIdentity)**. + + + #### Initialize method The **Initialize** method is executed when the security trimmer is loaded into the worker process, and does not execute again until the worker process is recycled. Two parameters are passed into the method:and - - - + + + - _staticProperties_: A [NameValueCollection](https://msdn.microsoft.com/library/System.Collections.Specialized.NameValueCollection.aspx) object containing the configuration properties specified for the security trimmer when it is registered with the Search service application. - - + + - _searchApplication_: A [SearchServiceApplication](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Administration.SearchServiceApplication.aspx) object that represents the Search service application. - - + + #### CheckAccess method The **CheckAccess** method is executed once per post-trimmer, for each result set query, after the query is evaluated. - - - + + + Four parameters are passed into this method: - - - + + + - _documentUrls_: A [IList\](https://msdn2.microsoft.com/library/5y536ey6) object that contain the URLs for each content item from the search results that match the crawl rule. - - + + - _documentAcls_: A [IList\](https://msdn2.microsoft.com/library/5y536ey6) object containing item ACLs for each content item whose access is to be determined by the security trimmer implementation. - - + + - _sessionProperties_: A [IDictionary\](https://msdn2.microsoft.com/library/s4ys34ea) object containing the transient property bag. - - + + - _userIdentity_: An [IIdentity](https://msdn.microsoft.com/library/System.Security.Principal.IIdentity.aspx) object from which implementers can retrieve the user's identity. - - + + The **CheckAccess** method returns a [BitArray](https://msdn.microsoft.com/library/System.Collections.BitArray.aspx) object that represents an array of **true** or **false** values, one for each content item URL in the **IList** object that is passed as the first parameter of the method. The query processing component uses these values to perform the security post-trimming of the results. If the array value for a particular content item is **true**, the item is included in the returned results; if the array value is **false**, the item is removed. - - - + + + When implementing the **CheckAccess** method, you can use two pieces of information for each item to determine whether to return **true** or **false** for the item: the identity of the user who submitted the query and the URL of the content item. Alternatively, you can also pass custom document ACL information from the connector to the **CheckAccess** method. - - - + + + #### Retrieving the user identity for your security trimmer You can retrieve the user's identity by accessing the thread's current principal, as shown in the following code example. - - - -```cs + + + +```csharp IIdentity userIdentity = System.Threading.Thread.CurrentPrincipal.Identity; ``` You must also include the following namespace directive. - - - -```cs + + + +```csharp using System.Security.Principal; ``` You can also retrieve the identity of the user from the **CheckAccess** method's **passedUserIdentity** parameter. - - - + + + #### Passing document ACLs from the connector to your security trimmers A connector, as the name implies, is a communication bridge between SharePoint and the external system that hosts the external data. If you are working with custom connectors, you can pass the document's ACL information directly to the post-trimmer by setting the **docaclmeta** document property. As long as the configured connectors and post-trimmers have the same format and interpretation of the field, you are free to use it to pass custom data. - - - + + + The strings stored in **docaclmeta** by the connector will surface in the _documentAcls_ parameter when the **CheckAccess** method of the custom security trimmer is invoked. The regular document ACLs in the **docacl** property are processed by basic security trimming and are not visible to the custom security trimmer. Similarly, the **docaclmeta** property does not have any effect on basic security trimming. - - - + + + #### Post-trimmers and their effect on refiner count for security trimmers When working with post-trimmers, it is important to notice that there are two types of result tables: **RelevantResults** and the **RefinementResults**. Post-trimmers are applied only to the result hits in the **RelevantResults**. Consequently, there may be refiners related to the post-trimmed hits and the **RefinementResults** count may be larger than or equal to the **RelevantResults**. You can address this behavior in two ways: - - - + + + - Exclude the sensitive refiners from the refinement panel in the default web part so that no information is leaked via the refiners. - - + + - Use a custom web part to display results or refiners when using post-trimmers so that the **RefinementResults** may be elegantly hidden in cases where the **RefinementResults** count exceeds the **RelevantResults** count. - - + + ### Retrieving individual configuration properties for your security trimmer You can access an individual configuration property by using the property name that was specified when the security post-trimmer was registered. For example, the following code retrieves the value for a configuration property named **CheckLimit**. - - - -```cs + + + +```csharp public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication) { if (staticProperties["CheckLimitProperty"] != null) @@ -211,55 +211,55 @@ public void Initialize(NameValueCollection staticProperties, SearchServiceApplic After you create the custom security trimmer, you must deploy it to the global assembly cache on any server in the Query role. Step 2 in [How to: Use a custom security trimmer for SharePoint Server search results](how-to-use-a-custom-security-trimmer-for-sharepoint-server-search-results.md) describes the process for deploying the custom security trimmer to the global assembly cache. - - - + + + ## Registering the custom security trimmer For post-trimmers, you must associate a custom security trimmer registration with a specific Search service application and crawl rule; for pre-trimmers, this is optional. - - - + + + You use the **SPEnterpriseSearchSecurityTrimmer** cmdlet of the SharePoint Management Shell to register a custom security trimmer. - - - + + + The following table describes the parameters that the cmdlet uses. - - - + + + **Table 1. Parameters used by the SPEnterpriseSearchSecurityTrimmer cmdlet** -|**Parameter**|**Description**| +|Parameter|Description| |:-----|:-----| | _SearchApplication_
|Required. The name of the Search service application, for example "Search Service Application".
| | _typeName_
|Required. The strong name of the custom security trimmer assembly.
| | _RulePath_
|Required for post-trimmers; optional for pre-trimmers. The crawl rule for the security trimmer.
**Note**: We recommend using one crawl rule per content source. | | _id_
|Required. The security trimmer identifier (ID). This value is unique; if a security trimmer is registered with an ID that is already registered for another security trimmer, the registration for the first trimmer is overwritten with the registration for the second trimmer.
| | _properties_
|Optional. The name-value pairs specifying the configuration properties. Must be in the following format: `Name1~Value1~Name2~Value~???`
| - + For an example of a basic command for registering a custom security trimmer and a sample that specifies the configuration properties, see [How to: Use a custom security trimmer for SharePoint Server search results](how-to-use-a-custom-security-trimmer-for-sharepoint-server-search-results.md). - - - + + + ## See also - [How to: Use a custom security trimmer for SharePoint Server search results](how-to-use-a-custom-security-trimmer-for-sharepoint-server-search-results.md) - - + + - [ISecurityTrimmerPre](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPre.aspx) - - + + - [ISecurityTrimmerPost](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.ISecurityTrimmerPost.aspx) - - + + - [Overview of Business Connectivity Services in SharePoint](https://technet.microsoft.com/library/ee661740.aspx) - - + + diff --git a/docs/general-development/custom-word-breakers-in-sharepoint-server.md b/docs/general-development/custom-word-breakers-in-sharepoint-server.md index 7e2ccff51..c4869dcbb 100644 --- a/docs/general-development/custom-word-breakers-in-sharepoint-server.md +++ b/docs/general-development/custom-word-breakers-in-sharepoint-server.md @@ -1,293 +1,99 @@ --- title: Custom word breakers in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes word breaking in SharePoint and provides steps on how to switch to a custom word breaker in SharePoint. +ms.date: 05/09/2023 ms.assetid: d18b48d4-987c-4228-9932-30d5b30f86a2 -localization_priority: Normal +ms.localizationpriority: medium --- - # Custom word breakers in SharePoint -Learn about word breaking in SharePoint. -Word breaking is one of the key Natural Language Processing (NLP) features that enable search and improve search results (or recall). Word breakers split a stream of text into individual words or tokens on which you can base additional language processing. Word breakers are language-specific. In addition to built-in word breakers, Search in SharePoint enables the use of custom word breakers so that users can tune word breaking behavior according to their needs. See [Supported languages for word breaker customizations in SharePoint](#SP15_SupportedLanguages) for a list languages supported for word breaker customization. - - - -For information on how to write a word breaker refer to the following articles -- [Implementing a Word Breaker](https://msdn.microsoft.com/library/ms693186%28v=vs.85%29.aspx) - - -- [IWordBreaker interface](https://msdn.microsoft.com/library/ms691079%28v=vs.85%29.aspx) - - +Word breaking is one of the key Natural Language Processing (NLP) features that enable search and improve search results (or recall). Word breakers split a stream of text into individual words or tokens on which you can base additional language processing. Word breakers are language-specific. In addition to built-in word breakers, Search in SharePoint enables the use of custom word breakers so that users can tune word breaking behavior according to their needs. See [Supported languages for word breaker customizations in SharePoint](#supported-languages-for-word-breaker-customizations-in-sharepoint) for a list languages supported for word breaker customization. -## How to switch to a custom word breaker in SharePoint - +For information on how to write a word breaker refer to the following articles + +- [Implementing a Word Breaker](https://msdn.microsoft.com/library/ms693186%28v=vs.85%29.aspx) +- [IWordBreaker interface](https://msdn.microsoft.com/library/ms691079%28v=vs.85%29.aspx) +## How to switch to a custom word breaker in SharePoint -> **Caution:** -> When you replace existing word breakers, you modify the registry at your own risk. Serious problems might occur if you modify the registry incorrectly by using Registry Editor or by using another method. These problems might require that you reinstall the operating system. Microsoft cannot ensure that these problems can be solved. Switching to a different word breaker might also cause serious problems during indexing and querying. Before you modify the registry, back up the registry and ensure that you know how to restore the registry if a problem occurs. - - - +> [!CAUTION] +> When you replace existing word breakers, you modify the registry at your own risk. Serious problems might occur if you modify the registry incorrectly by using Registry Editor or by using another method. These problems might require that you reinstall the operating system. Microsoft cannot ensure that these problems can be solved. Switching to a different word breaker might also cause serious problems during indexing and querying. Before you modify the registry, back up the registry and ensure that you know how to restore the registry if a problem occurs. Take the following steps to replace the existing word breaker with a custom word breaker or replace the existing word breaker with a word breaker in another language. - - - 1. Open the Registry Editor, as follows: - 1. Choose **Start**, and then choose **Run**. - - -2. In the **Open** dialog box, type **Regedit**, and then choose **OK**. - - -2. In Registry Editor, select the following registry subkey: - +1. In the **Open** dialog box, type **Regedit**, and then choose **OK**. +1. In Registry Editor, select the following registry subkey: + **HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Office Server\\15.0\\Search\\Setup\\ContentIndexCommon\\LanguageResources\\Default\\** _language from the list below_ - - -3. In the right pane, open the shortcut menu for the **WBDLLPathOverride** registry value, and then choose **Modify**. - - -4. In the **Edit String** dialog box, in the **Value data** box, type the path to your custom word breaker DLL, and then choose **OK**. The new DLL should be located in the same path as the existing DLL that is being replaced. - - -5. In the right pane, open the shortcut menu for the **WBreakerClass** registry value, and then choose **Modify**. - - -6. In the **Edit String** dialog box, in the **Value data** box, type the class ID of your custom word breaker, and then choose **OK**. - - -7. Restart the SharePoint Search Host Controller and SharePoint. - - -8. Do a full re-crawl. - - + +1. In the right pane, open the shortcut menu for the **WBDLLPathOverride** registry value, and then choose **Modify**. +1. In the **Edit String** dialog box, in the **Value data** box, type the path to your custom word breaker DLL, and then choose **OK**. The new DLL should be located in the same path as the existing DLL that is being replaced. +1. In the right pane, open the shortcut menu for the **WBreakerClass** registry value, and then choose **Modify**. +1. In the **Edit String** dialog box, in the **Value data** box, type the class ID of your custom word breaker, and then choose **OK** + + Restart the SharePoint Search Host Controller and SharePoint. + +1. Do a full re-crawl. ## Supported languages for word breaker customizations in SharePoint - The following languages are supported for word breaker customization: - - - -Arabic - - - -Bengali - - - -Bulgarian - - - -Catalan - - - -Chinese (People's Republic of China) - - - -Chinese (Taiwan) - - - -Croatian - - - -Czech - - - -Danish - - - -Dutch (Dutch) - - - -English (United States) - - - -Estonian - - - -Finnish - - - -French (Standard) - - - -German (Standard) - - - -Greek - - - -Gujarati - - - -Hebrew - - - -Hindi - - - -Hungarian - - - -Icelandic - - - -Indonesian - - - -Italian (Default) - - - -Japanese - - - -Kannada - - - -Kazakh - - - -Korean - - - -Latvian - - - -Lithuanian - - - -Malay - - - -Malayalam - - - -Marathi - - - -Norwegian - - - -Polish - - - -Portuguese (Portuguese) - - - -Punjabi - - - -Romanian - - - -Russian - - - -Serbian (Cyrillic) - - - -Slovak - - - -Slovenian - - - -Spanish (Modern Sort) - - - -Swedish - - - -Tamil - - - -Telugu - - - -Thai - - - -Turkish - - - -Ukrainian - - - -Urdu - - - -Vietnamese - - - -## See also - +- Arabic +- Bengali +- Bulgarian +- Catalan +- Chinese (People's Republic of China) +- Chinese (Taiwan) +- Croatian +- Czech +- Danish +- Dutch (Dutch) +- English (United States) +- Estonian +- Finnish +- French (Standard) +- German (Standard) +- Greek +- Gujarati +- Hebrew +- Hindi +- Hungarian +- Icelandic +- Indonesian +- Italian (Default) +- Japanese +- Kannada +- Kazakh +- Korean +- Latvian +- Lithuanian +- Malay +- Malayalam +- Marathi +- Norwegian +- Polish +- Portuguese (Portuguese) +- Punjabi +- Romanian +- Russian +- Serbian (Cyrillic) +- Slovak +- Slovenian +- Spanish (Modern Sort) +- Swedish +- Tamil +- Telugu +- Thai +- Ukrainian +- Urdu +- Vietnamese +## See also -- [Configure search in SharePoint](configure-search-in-sharepoint.md) - - -- [Implementing a Word Breaker](https://msdn.microsoft.com/library/ms693186%28v=vs.85%29.aspx) - - -- [IWordBreaker interface](https://msdn.microsoft.com/library/ms691079%28v=vs.85%29.aspx) - - - +- [Configure search in SharePoint](configure-search-in-sharepoint.md) +- [Implementing a Word Breaker](https://msdn.microsoft.com/library/ms693186%28v=vs.85%29.aspx) +- [IWordBreaker interface](https://msdn.microsoft.com/library/ms691079%28v=vs.85%29.aspx) diff --git a/docs/general-development/customizing-ranking-models-to-improve-relevance-in-sharepoint.md b/docs/general-development/customizing-ranking-models-to-improve-relevance-in-sharepoint.md index 7588699e5..51c54d1a6 100644 --- a/docs/general-development/customizing-ranking-models-to-improve-relevance-in-sharepoint.md +++ b/docs/general-development/customizing-ranking-models-to-improve-relevance-in-sharepoint.md @@ -1,10 +1,9 @@ --- title: Customizing ranking models to improve relevance in SharePoint description: Improve search relevance by customizing ranking models to calculate rank scores (relevance rank) accurately using rank features in SharePoint. -ms.date: 12/14/2020 -ms.prod: sharepoint +ms.date: 07/15/2022 ms.assetid: c166ecdd-7f93-4bbb-b543-2687992dd2bc -localization_priority: Priority +ms.localizationpriority: high --- # Customizing ranking models to improve relevance in SharePoint @@ -79,7 +78,7 @@ $twoLinearStagesRankingModel.RankingModelXML > filename.xml ### To deploy a custom ranking model 1. From the list of available ranking models, copy the GUID of the ranking model that you want to use as a template. (See [To list all available ranking models](#to-list-all-available-ranking-models) for the sequence of Windows PowerShell cmdlets to use.) -1. Run the following sequence of Windows PowerShell cmdlets using the GUID copied in step 1 for __. +1. Run the following sequence of Windows PowerShell cmdlets using the GUID copied in step 1 for _\_. ```powershell $ssa = Get-SPEnterpriseSearchServiceApplication @@ -133,7 +132,7 @@ To retrieve the rank detail, you need to be the administrator of the Search serv ### To retrieve the rank detail 1. Open the SharePoint Management Shell as an Administrator. -1. Run the following sequence of Windows PowerShell cmdlets, and substitute __ and __ with actual values. +1. Run the following sequence of Windows PowerShell cmdlets, and substitute _\_ and _\_ with actual values. ```powershell $app = Get-SPEnterpriseSearchServiceApplication @@ -151,7 +150,7 @@ $resultTables[([Microsoft.Office.Server.Search.Query.ResultType]::RelevantResult SharePoint provides the **ExplainRank** page that is located in the layouts folder ( `/_layouts/15/`). This page contains detailed information on the rank score for each rank feature based on a given search query, a document ID, and an optional ranking model ID. The information is obtained and parsed from the rank detail. -You can access the **ExplainRank** page with the following URL: **http:///_layouts/15/ExplainRank.aspx?q={x}&d={y}&rm={z}** +You can access the **ExplainRank** page with the following URL: **http://\/_layouts/15/ExplainRank.aspx?q={x}&d={y}&rm={z}** Where: diff --git a/docs/general-development/customizing-search-results-in-sharepoint.md b/docs/general-development/customizing-search-results-in-sharepoint.md index 200602632..9fcec7243 100644 --- a/docs/general-development/customizing-search-results-in-sharepoint.md +++ b/docs/general-development/customizing-search-results-in-sharepoint.md @@ -1,150 +1,91 @@ --- title: Customizing search results in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Learn how to group similar items or remove duplicate items in a search result set in SharePoint so you can display these results in a concise, readable way. +ms.date: 06/09/2022 ms.assetid: 1b30f6df-643a-4570-ae5c-d3d8df5609b8 -localization_priority: Priority +ms.localizationpriority: high --- - - # Customizing search results in SharePoint + Learn how to group similar items or remove duplicate items in a search result set in SharePoint so you can display these results in a concise, readable way. + In search results, grouping collapses two or more similar items in a search result set to make their display more readable for a user. Duplicate removal of search results is a part of grouping, where items that are identical or nearly identical are removed from the result set. Depending on the settings set by the SharePoint administrator, the user might be able to expand the search result set later and see the individual results that were collapsed. - - - The following are examples of ways to group search results: + - Duplicate detection, where nearly identical documents are removed from the result set. - - - Site collapsing, where only the most relevant item found in each site is shown in the result set. - - - Document set collapsing, where only one hit is displayed for each document library in SharePoint. - - + You can specify the criteria for collapsing or duplicate trimming programmatically by using the following [KeywordQuery](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.aspx) properties within the Query object model: -- [CollapseSpecification](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.CollapseSpecification.aspx) - - -- [TrimDuplicates](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.Query.TrimDuplicates.aspx) - - -- [TrimDuplicatesOnProperty](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.TrimDuplicatesOnProperty.aspx) - - -- [TrimDuplicatesKeepCount](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.TrimDuplicatesKeepCount.aspx) - - -- [TrimDuplicatesIncludeId](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.TrimDuplicatesIncludeId.aspx) - - + +- [CollapseSpecification](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.CollapseSpecification.aspx) +- [TrimDuplicates](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.Query.TrimDuplicates.aspx) +- [TrimDuplicatesOnProperty](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.TrimDuplicatesOnProperty.aspx) +- [TrimDuplicatesKeepCount](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.TrimDuplicatesKeepCount.aspx) +- [TrimDuplicatesIncludeId](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.TrimDuplicatesIncludeId.aspx) ## Collapse similar search results using the CollapseSpecification property - The **CollapseSpecification** property takes a _Spec_ parameter that can contain multiple fields separated either by a comma or a space, which evaluated together specify a set of criteria used for collapsing. - - - - **Syntax** - - - - `CollapseSpecification = Spec` - - - + +**Syntax** +`CollapseSpecification = Spec` + The following table lists the fields of the _Spec_ parameter. - - - **Table 1. Spec parameter fields** - -|**Element in parameter**|**Description**| +|Element in parameter|Description| |:-----|:-----| -| _Spec_
| `Subspec(Subspec)*`
| -| _Subspec_
| `Prop(','Prop)*[':'Dups]`
| -| _Prop_
|A valid managed property or an alias of a managed property. _Prop_ is case-insensitive. The managed property must be queryable and either sortable or refineable.
| -| _Dups_
|An integer specifying the number of items to retain. The default value is 1.
| -| __
|Properties are combined by using the **OR** operator.
| -| _,_
|Properties are combined by using the **AND** operator.
| -| _*_
|Indicates more items.
| -| _() or []_
|Indicates optional items.
| - +| _Spec_| `Subspec(Subspec)*`| +| _Subspec_| `Prop(','Prop)*[':'Dups]`| +| _Prop_|A valid managed property or an alias of a managed property. _Prop_ is case-insensitive. The managed property must be queryable and either sortable or refineable.| +| _Dups_|An integer specifying the number of items to retain. The default value is 1. | +| _\_|Properties are combined by using the **OR** operator.| +| _,_|Properties are combined by using the **AND** operator.| +| _*_|Indicates more items. | +| _() or []_|Indicates optional items. | + If the fields in _Spec_ are separated by commas, the fields are combined by using the **AND** operator. If all of the specified fields are matched, the items are collapsed. - - - + In contrast, if the fields in _Spec_ are separated by spaces, the fields (or _Subspecs_) are combined by using an expansion that includes both the **AND** operator and **OR** operator. For example, an expression such as `Category:3 Product:2` is internally transformed to the following expression `(Category AND Product) OR (Category)` with a counter for each; hence a maximum of two of the former and three of the latter. Items are collapsed if some of the specified fields are matched. - - - ### Examples of using CollapseSpecification The following table shows a product catalog from the Contoso company. The next set of examples use this catalog to show how the **CollapseSpecification** property works. - - - - -|**Category**|**Product**|**Variant**|**Title**| +|Category|Product|Variant|Title| |:-----|:-----|:-----|:-----| -|Laptops
|WWI
|19W X0196 Black
|Computer 1
| -|Laptops
|Adventure Works
|12 M1201 Red
|Computer 2
| -|Laptops
|Adventure Works
|15.4W M1548 White
|Computer 3
| -|Laptops
|Proseware
|19 X910 Black
|Computer 4
| -|Laptops
|Proseware
|Laptop19 X910 Black
|Computer 5
| -|Desktops
|Adventure Works
|2.33 XD233 Silver
|Computer 6
| -|Desktops
|WWI
|2.33 X2330 Black
|Computer 7
| -|Desktops
|Adventure Works
|1.60 ED160 White
|Computer 8
| -|Desktops
|WWI
|3.0 M0300 Silver
|Computer 9
| - - - - - +|Laptops |WWI |19W X0196 Black |Computer 1 | +|Laptops |Adventure Works |12 M1201 Red |Computer 2 | +|Laptops |Adventure Works |15.4W M1548 White |Computer 3 | +|Laptops |Proseware |19 X910 Black |Computer 4 | +|Laptops |Proseware |Laptop19 X910 Black |Computer 5 | +|Desktops |Adventure Works |2.33 XD233 Silver |Computer 6 | +|Desktops |WWI |2.33 X2330 Black |Computer 7 | +|Desktops |Adventure Works |1.60 ED160 White |Computer 8 | +|Desktops |WWI |3.0 M0300 Silver |Computer 9 | #### Example: group by Category First, group the items based on **Category** and show the top two (hence `"Category:2"`) for each group. Then, for each **Category**, show a corresponding number of unique (hence "Product:1") **Products**. - - - - **Syntax** - - - - `CollapseSpecification="Category:2 Product:1"` - - - -This should return the following results. - - - +**Syntax** +`CollapseSpecification="Category:2 Product:1"` -|**Category**|**Product**|**Variant**|**Title**| -|:-----|:-----|:-----|:-----| -|Laptops
|WWI
|19W X0196 Black
|Computer 1
| -|Laptops
|Adventure
|12 M1201 Red
|Computer 2
| -|Desktops
|Adventure Works
|2.33 XD233 Silver
|Computer 6
| -|Desktops
|WWI
|2.33 X2330 Black
|Computer 7
| - -Use the following code to collapse the search results by using the **CollapseSpecification** property. - - - - +This should return the following results. +|Category|Product|Variant|Title| +|:-----|:-----|:-----|:-----| +|Laptops |WWI |19W X0196 Black |Computer 1 | +|Laptops |Adventure |12 M1201 Red |Computer 2 | +|Desktops |Adventure Works |2.33 XD233 Silver |Computer 6 | +|Desktops |WWI |2.33 X2330 Black |Computer 7 | -```cs +Use the following code to collapse the search results by using the **CollapseSpecification** property. +```csharp using (var context = new ClientContext("http://localhost")) { var query = new KeywordQuery(context) @@ -163,131 +104,64 @@ using (var context = new ClientContext("http://localhost")) Console.WriteLine(result["Title"]); } } - ``` - #### Example: group by Category and Product First, group the items based on both **Category** and **Product**. Then, show each unique combination. - - - - **Syntax** - - - - `CollapseSpecification="Category,Product:1"` - - - -This should return the following results. - - - +**Syntax** +`CollapseSpecification="Category,Product:1"` + +This should return the following results. -|**Category**|**Product**|**Variant**|**Title**| +|Category|Product|Variant|Title| |:-----|:-----|:-----|:-----| -|Laptops
|WWI
|19W X0196 Black
|Computer 1
| -|Laptops
|Adventure Works
|12 M1201 Red
|Computer 2
| -|Laptops
|Proseware
|19 X910 Black
|Computer 4
| -|Desktops
|Adventure Works
|2.33 XD233 Silver
|Computer 6
| -|Desktops
|WWI
|2.33 X2330 Black
|Computer 7
| - +|Laptops |WWI |19W X0196 Black |Computer 1 | +|Laptops |Adventure Works |12 M1201 Red |Computer 2 | +|Laptops |Proseware |19 X910 Black |Computer 4 | +|Desktops |Adventure Works |2.33 XD233 Silver |Computer 6 | +|Desktops |WWI |2.33 X2330 Black |Computer 7 | ## Trim duplicate search results using the TrimDuplicates property - Use **TrimDuplicates** to specify whether to trim away the duplicate search results from the result set. **TrimDuplicates** is **true** by default. - - - + If you use **TrimDuplicates** with either **TrimDuplicatesOnProperty** or preferably **CollapseSpecification**, **TrimDuplicates** is set to **false**. - - - - **Syntax** - - - - `TrimDuplicates = <$true | $false>` - - - + +**Syntax** +`TrimDuplicates = <$true | $false>` ### Trim duplicate search results using the TrimDuplicatesOnProperty property - Use **TrimDuplicatesOnProperty** to specify whether to use a non-default managed property as the basis for duplicate trimming. The default value is the **DocumentSignature** managed property. The managed property must be of type **Integer** or **String**. By using a managed property that represents a grouping of items, you can use this feature for field collapsing. - - - - **Syntax** - - - - `TrimDuplicatesOnProperty = ` - + +**Syntax** +`TrimDuplicatesOnProperty = ` + > [!NOTE] > In SharePoint, use **CollapseSpecification** wherever possible. **TrimDuplicatesOnProperty** is available for backward compatibility only. - - - - ### Trim duplicate search results using the TrimDuplicatesKeepCount property - Use **TrimDuplicatesKeepCount** to specify the number of documents to retain when **TrimDuplicates** is **true**. If **TrimDuplicates** is based on a managed property that can be used as a group identifier, for example a site ID, you can control how many results are returned for each group. The items returned are those with the highest dynamic rank within each group. - - - - **Syntax** - - - - `TrimDuplicatesKeepCount = ` - - - + +**Syntax** +`TrimDuplicatesKeepCount = ` ### Retrieve duplicate search results using the TrimDuplicatesIncludeId property - Use **TrimDuplicatesIncludeId** to retrieve the duplicates of a document when **TrimDuplicates** is **true** and **TrimDuplicatesOnProperty** or **CollapseSpecification** is set to **false**. - - - + The document ID, _docid_, is used to retrieve the duplicates of a particular document. - - - - **Syntax** - - - - `TrimDuplicatesIncludeId = ` - + +**Syntax** +`TrimDuplicatesIncludeId = ` + > [!NOTE] > The _fcoid_ managed property in FAST Search Server 2010 for SharePoint has been replaced with the _docid_ managed property in SharePoint. - - - - ## See also - - - -- [KeywordQuery](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.aspx) - - -- [Overview of the search schema in SharePoint](https://technet.microsoft.com/library/jj219669%28office.15%29.aspx) - - - - - - +- [KeywordQuery](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Query.KeywordQuery.aspx) +- [Overview of the search schema in SharePoint](https://technet.microsoft.com/library/jj219669%28office.15%29.aspx) diff --git a/docs/general-development/debugging-sharepoint-server-workflows.md b/docs/general-development/debugging-sharepoint-server-workflows.md index 88396467f..9ae9d211d 100644 --- a/docs/general-development/debugging-sharepoint-server-workflows.md +++ b/docs/general-development/debugging-sharepoint-server-workflows.md @@ -1,10 +1,9 @@ --- title: Debugging SharePoint workflows description: Demonstrates how SharePoint now relies on Workflow Manager 1.0 for all workflow processing and management, and demonstrates debugging options. -ms.date: 12/14/2020 -ms.prod: sharepoint +ms.date: 10/15/2022 ms.assetid: a5adf39b-8640-4871-be60-b786dcf9fafc -localization_priority: Priority +ms.localizationpriority: high --- # Debugging SharePoint workflows @@ -126,7 +125,7 @@ The first step is to first define the default proxy configuration for .NET Frame - `%systemdrive%\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\Config\\machine.config` - `%systemdrive%\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\Config\\machine.config` -Next, add the following markup to the bottom of each file, just before the closing **** element: +Next, add the following markup to the bottom of each file, just before the closing **\** element: ```xml diff --git a/docs/general-development/deciding-between-sharepoint-add-ins-and-sharepoint-solutions.md b/docs/general-development/deciding-between-sharepoint-add-ins-and-sharepoint-solutions.md index d51e00d0b..3ae112357 100644 --- a/docs/general-development/deciding-between-sharepoint-add-ins-and-sharepoint-solutions.md +++ b/docs/general-development/deciding-between-sharepoint-add-ins-and-sharepoint-solutions.md @@ -1,9 +1,9 @@ --- title: Deciding between SharePoint Add-ins and SharePoint solutions -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Provides a link to the SharePoint Add-ins compared with SharePoint solutions topic for a modern solution. +ms.date: 06/09/2022 ms.assetid: 8459e265-b8fd-4bf8-911e-d63cae8bf96f -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/develop-access-web-apps.md b/docs/general-development/develop-access-web-apps.md index 7808170f4..bf36fae11 100644 --- a/docs/general-development/develop-access-web-apps.md +++ b/docs/general-development/develop-access-web-apps.md @@ -1,9 +1,9 @@ --- title: Develop Access web apps -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to develop web-based applications using Microsoft Access 2013 and provides information on Access 2013's new features. +ms.date: 06/09/2022 ms.assetid: 41131b27-d750-4d11-b3c7-c17ad4d666e2 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/develop-sharepoint-workflows-using-visual-studio.md b/docs/general-development/develop-sharepoint-workflows-using-visual-studio.md index d7892e82e..18e73ac33 100644 --- a/docs/general-development/develop-sharepoint-workflows-using-visual-studio.md +++ b/docs/general-development/develop-sharepoint-workflows-using-visual-studio.md @@ -1,10 +1,9 @@ --- title: Develop SharePoint workflows using Visual Studio description: "SharePoint supports two primary workflow development environments for authoring workflows: SharePoint Designer and Visual Studio. This article summarizes both and discusses the advantages and disadvantages of each." -ms.date: 02/05/2021 -ms.prod: sharepoint +ms.date: 06/09/2022 ms.assetid: 28f5d3b1-6fe8-4b1f-8c4e-b11105fe6f46 -localization_priority: Priority +ms.localizationpriority: high --- # Develop SharePoint workflows using Visual Studio @@ -95,7 +94,7 @@ To debug on-premises workflows in Visual Studio, you need to temporarily allow t To debug SharePoint Online workflows in Visual Studio, perform the following steps: -1. If you're behind a firewall, you may need to install a proxy client (such as the [Forefront Threat Management Gateway (TMG) Client](https://www.microsoft.com/download/details.aspx?displaylang=en&id=10504)), depending on your company's network topology. +1. If you're behind a firewall, you may need to install a proxy client (such as the [Forefront Threat Management Gateway (TMG) Client](/previous-versions/tn-archive/cc441520(v=technet.10))), depending on your company's network topology. 1. Register for a Microsoft Azure account if you haven't already, and then sign into that account. For information about how to register for a Microsoft Azure account, see [Microsoft Azure](https://azure.microsoft.com/). diff --git a/docs/general-development/develop-the-site-design-in-sharepoint.md b/docs/general-development/develop-the-site-design-in-sharepoint.md index 08c11f813..65fe1a84b 100644 --- a/docs/general-development/develop-the-site-design-in-sharepoint.md +++ b/docs/general-development/develop-the-site-design-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Develop the site design in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to develop the site design in SharePoint using the Design Manager feature and provides links to other resources. +ms.date: 06/09/2022 ms.assetid: 4c061484-2ba5-45ea-9860-aec9d7c8f80e -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/developing-with-duet-enterprise-2-0.md b/docs/general-development/developing-with-duet-enterprise-2-0.md index dfd236f27..1a9d4abed 100644 --- a/docs/general-development/developing-with-duet-enterprise-2-0.md +++ b/docs/general-development/developing-with-duet-enterprise-2-0.md @@ -1,172 +1,89 @@ --- title: Developing with Duet Enterprise 2.0 -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes Duet Enterprise 2.0's features and details how to set up the developer environment, how to add an external content type, and more. +ms.date: 05/09/2023 ms.assetid: c3ef38aa-559e-4832-95c7-75e222c77624 -localization_priority: Normal +ms.localizationpriority: medium --- - # Developing with Duet Enterprise 2.0 ## Overview - Duet Enterprise 2.0 is the latest version of a collaborative effort between Microsoft and SAP to give SharePoint users the ability to work with data from SAP systems.It combines components from SAP as well as SharePoint and SharePoint Online. It gives a developer the ability to create components that will allow users to bring data from SAP systems into the familiar SharePoint environment. - - - ## Features of Duet Enterprise 2.0 - When properly installed and configured, Duet Enterprise 2.0 will provide the following features: - - - - You can work with data in SAP systems within SharePoint using Business Data Web parts, External lists and custom components. - - - Use SAP data in SharePoint without code by using built-in components. - - - Use SAP reporting systems inside of an app. - - - Use special web parts installed with Duet Enterprise 2.0 to add SAP information to SharePoint pages - - - Use SAP workflow in an app. - - - Developers can use client-side JavaScript to interact with SAP external data. - - - Secure data using OAuth for authentication. - - ## Setting up the development environment - Developing SharePoint Add-ins using Duet Enterprise 2.0, for the most part, is exactly the same as creating standard SharePoint Add-ins. You can use Visual Studio to extend your apps and work within the robust framework of the Visual Studio integrated development environment. - - - ## Adding external content types - In order to access the external data housed on the SAP system, you will have to add an external content type. Since SAP data is exposed through OData endpoints, the auto-generation tools installed in Visual Studio can be used to [How to: Create an external content type from an OData source in SharePoint](how-to-create-an-external-content-type-from-an-odata-source-in-sharepoint.md) that is scoped at the app level. - - - + Follow these steps to create an external content type: - - - ### Creating an external content type from an SAP OData endpoint 1. In **Solution Explorer**, open the shortcut menu for the project, and choose **Add**, **Content types for External Data source**. - - -2. On the **Specify OData Source** page, enter the URL of the Duet Enterprise Workflow Service. - - -3. Choose a name for your OData source. - - -4. Select the entities that are needed. - - -5. Choose **Finish**. - - +1. On the **Specify OData Source** page, enter the URL of the Duet Enterprise Workflow Service. +1. Choose a name for your OData source. +1. Select the entities that are needed. +1. Choose **Finish**. + Visual Studio will create a new folder named External Content Types where you will find the newly created BDC model. - - - ## Configuring the BDC model - The most important thing to make the project work, is to add the **ODataExtensionProvider** property to the BDC model. This property defines the extension provider that provides BCS with the SAP extensions needed for creating app code. - - - -This sample shows the properties added to the BDC model: - - - - - -```XML +This sample shows the properties added to the BDC model: +```xml - - - https://:443/sap/opu/odata/sap/ - ZANDY_PO_HEADER_SRV/$metadata - 2.0 - - OBA.Server.Canary.ObaOdataServerExtensionProvider, - OBA.Server.SSOProvider, - Version=15.0.0.0, - Culture=neutral, - PublicKeyToken=71e9bce111e9429c - SAP-PASSPORT - - + + + https://:443/sap/opu/odata/sap/ + ZANDY_PO_HEADER_SRV/$metadata + 2.0 + + OBA.Server.Canary.ObaOdataServerExtensionProvider, + OBA.Server.SSOProvider, + Version=15.0.0.0, + Culture=neutral, + PublicKeyToken=71e9bce111e9429c + SAP-PASSPORT + ``` - ## Using Duet starter services to develop custom apps - -Duet Enterprise 2.0 installs several starter services to the file system on the SharePoint server. In a default installation, the files are found at C:\\Program Files\\Duet Enterprise\\2.0\\Solutions\\Starter Services. Among these are: - - - +Duet Enterprise 2.0 installs several starter services to the file system on the SharePoint server. In a default installation, the files are found at **C:\\Program Files\\Duet Enterprise\\2.0\\Solutions\\Starter Services**. Among these are: - OBACustomerWorkspace - - - OBAOrderToCash - - - OBAPortal - - - OBAProductCenter - - + Each of these solutions contains WSP files, solution and other supporting files needed to implement them. - - - + These solutions can be used to see what can be done with Duet Enterprise 2.0 and what the development patterns are, but they are not supported for use in SharePoint Add-ins. - - - ## See also - - - -- [Duet Enterprise for Microsoft SharePoint and SAP Server 2.0](https://technet.microsoft.com/library/ff972436.aspx) - - -- [How to: Create an external content type from an OData source in SharePoint](how-to-create-an-external-content-type-from-an-odata-source-in-sharepoint.md) - - -- [Visual Studio Developer Center](https://msdn.microsoft.com/vstudio/default) - - -- [Office Development with Visual Studio](https://msdn.microsoft.com/office/hh133430) - - +- [Duet Enterprise for Microsoft SharePoint and SAP Server 2.0](https://technet.microsoft.com/library/ff972436.aspx) +- [How to: Create an external content type from an OData source in SharePoint](how-to-create-an-external-content-type-from-an-odata-source-in-sharepoint.md) +- [Visual Studio Developer Center](https://msdn.microsoft.com/vstudio/default) +- [Office Development with Visual Studio](https://msdn.microsoft.com/office/hh133430) diff --git a/docs/general-development/discovery-in-excel-services-rest-api.md b/docs/general-development/discovery-in-excel-services-rest-api.md index dfb344a93..8e8ef0626 100644 --- a/docs/general-development/discovery-in-excel-services-rest-api.md +++ b/docs/general-development/discovery-in-excel-services-rest-api.md @@ -1,153 +1,86 @@ --- title: Discovery in Excel Services REST API -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes the discovery mechanisms built into the Excel Services REST API and provides code examples. +ms.date: 05/09/2023 ms.assetid: e3a8e057-f803-446d-81c9-4eb8ef3691e1 -localization_priority: Normal +ms.localizationpriority: medium --- - # Discovery in Excel Services REST API This topic discusses the discovery mechanisms built into the Excel Services REST API. - -> [!NOTE] -> The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of the [Microsoft Graph](http://graph.microsoft.io/docs/api-reference/v1.0/resources/excel -) endpoint. - - - +> [!NOTE] +> The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of the [Microsoft Graph](/graph/api/overview) endpoint. ## Discovery Base URL and Discovery Example -Discovery enables developers and users to discover information about and the content of a workbook manually or programmatically. The discovery mechanism supplies the [Atom](http://tools.ietf.org/html/rfc4287) feed that contains information about the resources in a workbook. By using discovery, you can explore and view the resources in the workbook. Resources that you can explore and access are ranges, charts, tables, and PivotTables. - - - -Following is the construct of the REST URL to a specific element in a workbook: - - - - - +Discovery enables developers and users to discover information about and the content of a workbook manually or programmatically. The discovery mechanism supplies the [Atom](http://tools.ietf.org/html/rfc4287) feed that contains information about the resources in a workbook. By using discovery, you can explore and view the resources in the workbook. Resources that you can explore and access are ranges, charts, tables, and PivotTables. -``` +Following is the construct of the REST URL to a specific element in a workbook: +```http http:///_vti_bin/ExcelRest.aspx/// ``` -As described in the [Basic URI Structure and Path](basic-uri-structure-and-path.md) topic, following is the REST URL to access a workbook named **sampleWorkbook.xlsx** and further view the chart called **SampleChart**: - - - +As described in the [Basic URI Structure and Path](basic-uri-structure-and-path.md) topic, following is the REST URL to access a workbook named **sampleWorkbook.xlsx** and further view the chart called **SampleChart**: - - -``` +```http http:///_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart') ``` To start and explore the resources in the workbook and view the resources by using discovery, go to the model page by using a URI that follows this example: - - - - - -``` +```http http:///_vti_bin/ExcelRest.aspx///model ``` -Using the "sampleWorkbook.xlsx" example, following is the URI: - - - - +Using the **sampleWorkbook.xlsx** example, following is the URI: - -``` +```http http:///_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model ``` Following is a screen shot of the model page. - - - **Excel Services REST model URL** - - - - - - - ![Excel Services REST model URL](../images/SharePointServer14Con_XLSvcs_RESTModel.gif) - - - + The URL to the model page is where you start the discovery. The model page displays four resource collections that the Excel Services REST API currently supports. The resource collections are ranges, charts, tables, or PivotTables. You can explore those resources in a particular workbook by clicking **Ranges**, **Charts**, **Tables**, or **PivotTables** on the model page. - - - -For example, to access the chart in the workbook by using discovery, do the following: - - - - - - - -1. On the model page, click **Charts**. Clicking the **Charts** link brings another Atom feed—this resulting feed lists all the charts that are available in the sampleWorkbook.xlsx workbook. The sampleWorkbook.xlsx workbook contains three charts named **Chart 1**, **Chart 3**, and **SampleChart**. Therefore, three chart names are listed, as seen in the following screen shot. - - **Excel Services REST discovery chart list** +For example, to access the chart in the workbook by using discovery, do the following: - +1. On the model page, click **Charts**. Clicking the **Charts** link brings another Atom feed—this resulting feed lists all the charts that are available in the sampleWorkbook.xlsx workbook. The sampleWorkbook.xlsx workbook contains three charts named **Chart 1**, **Chart 3**, and **SampleChart**. Therefore, three chart names are listed, as seen in the following screen shot. - ![Excel Services REST discovery chart list](../images/19126dce-b896-4623-8686-92f2fa807283.gif) - + **Excel Services REST discovery chart list** - + ![Excel Services REST discovery chart list](../images/19126dce-b896-4623-8686-92f2fa807283.gif) - -2. On the model page, click **SampleChart**. This displays the chart named **SampleChart** that resides in **sampleWorkbook.xlsx**, as shown in the following screen shot. - - **Viewing chart using REST** +1. On the model page, click **SampleChart**. This displays the chart named **SampleChart** that resides in **sampleWorkbook.xlsx**, as shown in the following screen shot. - + **Viewing chart using REST** - ![Viewing chart using REST](../images/11734dcf-1b57-40cc-b1e8-8b10b7e5d5cb.gif) - + ![Viewing chart using REST](../images/11734dcf-1b57-40cc-b1e8-8b10b7e5d5cb.gif) - - - -3. Similarly, clicking **Chart 1** or **Chart 3** displays the chart with the corresponding name. Clicking **SampleChart** navigates to the actual chart URL. Following is the URL to the **SampleChart** image (as can be seen in the screen shot): - -``` - http:///_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart%20')?$format=image -``` +1. Similarly, clicking **Chart 1** or **Chart 3** displays the chart with the corresponding name. Clicking **SampleChart** navigates to the actual chart URL. Following is the URL to the **SampleChart** image (as can be seen in the screen shot): + ```http + http:///_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart%20')?$format=image + ``` ## Atom Feed -Using the [Atom](http://tools.ietf.org/html/rfc4287) feed provided by the REST API gives you an easier way of getting to the data that you are interested in. If you view the source of the webpage, you get the XML. An example from the charts in **sampleWorkbook.xlsx** is shown below. - - - -As can be seen in the XML, the feed contains traversable elements that enable code to discover what elements exist in the workbook. Each Atom entry corresponds to a chart that can be accessed. This same mechanism applies to discovering ranges, tables, and PivotTables. - - - - +Using the [Atom](http://tools.ietf.org/html/rfc4287) feed provided by the REST API gives you an easier way of getting to the data that you are interested in. If you view the source of the webpage, you get the XML. An example from the charts in **sampleWorkbook.xlsx** is shown below. +As can be seen in the XML, the feed contains traversable elements that enable code to discover what elements exist in the workbook. Each Atom entry corresponds to a chart that can be accessed. This same mechanism applies to discovering ranges, tables, and PivotTables. -```XML +```xml - + Charts http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts 2010-01-19T19:32:53Z @@ -191,14 +124,8 @@ As can be seen in the XML, the feed contains traversable elements that enable co ``` - ## See also - #### Concepts - - - - - [Resources URI for Excel Services REST API](resources-uri-for-excel-services-rest-api.md) +- [Resources URI for Excel Services REST API](resources-uri-for-excel-services-rest-api.md) diff --git a/docs/general-development/ediscovery-in-sharepoint.md b/docs/general-development/ediscovery-in-sharepoint.md index 85c23e308..357513132 100644 --- a/docs/general-development/ediscovery-in-sharepoint.md +++ b/docs/general-development/ediscovery-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: eDiscovery in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes eDiscovery features in SharePoint and provides details on prerequisites, site holds, the eDiscovery programming model, and eDiscovery types. +ms.date: 06/09/2022 ms.assetid: 45cb324a-75f5-444d-a0fa-5c223df19016 -localization_priority: Priority +ms.localizationpriority: high --- @@ -93,7 +93,7 @@ SharePoint provides a Microsoft .NET server programming model that you can use t **Table 1. eDiscovery types** -|**Type**|**Description**| +|Type|Description| |:-----|:-----| | [Case](https://msdn.microsoft.com/library/Microsoft.Office.Server.Discovery.Case.aspx)
|Represents an eDiscovery case. Associated with a specified [SPWeb](https://msdn.microsoft.com/library/Microsoft.SharePoint.SPWeb.aspx) object, a case can be closed by a specified date or as a specific action. Cases can contain source groups, locations, mailboxes, custodians, saved searches, exports, export configurations for specified IDs, queries, and lists of all of the source groups, custodians, and locations in this **Case** object.
| | [Custodian](https://msdn.microsoft.com/library/Microsoft.Office.Server.Discovery.Custodian.aspx)
|Represents the person who is responsible for keeping records for an eDiscovery case.
| diff --git a/docs/general-development/enhancing-the-bdc-model-file-for-search-in-sharepoint.md b/docs/general-development/enhancing-the-bdc-model-file-for-search-in-sharepoint.md index 4be73106e..d02762ca1 100644 --- a/docs/general-development/enhancing-the-bdc-model-file-for-search-in-sharepoint.md +++ b/docs/general-development/enhancing-the-bdc-model-file-for-search-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Enhancing the BDC model file for Search in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes enhancing the BDC model file for Search in Sharepoint and provides a table of search properties for BDC model files. +ms.date: 06/09/2022 ms.assetid: 3c67b1cf-5fca-4805-a1b5-c9ac1ff8aede -localization_priority: Normal +ms.localizationpriority: medium --- @@ -47,7 +47,7 @@ The following table describes the BDC model properties that are applicable to Se **Table 1. Search properties for BDC model files** -|**Name**|**Metadata Object**|**Description**| +|Name|Metadata Object|Description| |:-----|:-----|:-----| |ShowInSearchUI
|Model
|Specifies that an **LobSystemInstance** element in the model file should be displayed in the search user interface. This value is ignored for custom connectors.
| |InputUriProcessor
|LobSystem
|Specifies the name of the class that processes the input URL before passing it to the connector. Applies to .NET and custom BCS indexing connectors. For more information, see [Creating a Custom Indexing Connector](https://msdn.microsoft.com/library/ec2df34d-178c-4ae1-a2b0-a6af04ee57bd%28Office.15%29.aspx).
| diff --git a/docs/general-development/excel-services-alerts.md b/docs/general-development/excel-services-alerts.md index 4084c756c..0fe8939f2 100644 --- a/docs/general-development/excel-services-alerts.md +++ b/docs/general-development/excel-services-alerts.md @@ -1,12 +1,12 @@ --- title: Excel Services Alerts -ms.date: 09/25/2017 +description: Describes Excel service alerts and provides details on "stop" alerts, "continue" alerts, exceptions, and error codes. +ms.date: 06/09/2022 keywords: errors f1_keywords: - errors -ms.prod: sharepoint ms.assetid: a4e7030b-05c2-484e-b21f-46cba937b803 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/excel-services-architecture.md b/docs/general-development/excel-services-architecture.md index 0f5ec3552..9604e1dee 100644 --- a/docs/general-development/excel-services-architecture.md +++ b/docs/general-development/excel-services-architecture.md @@ -1,12 +1,12 @@ --- title: Excel Services Architecture -ms.date: 09/25/2017 +description: Describes the Excel Services architecture and provides details on web front-end and back-end application servers, Excel web access, and more. +ms.date: 06/09/2022 keywords: excel services design f1_keywords: - excel services design -ms.prod: sharepoint ms.assetid: e0349b4a-2d52-46c4-a167-801e9c24eaca -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/excel-services-best-practices.md b/docs/general-development/excel-services-best-practices.md index a049a1453..436f5ccbc 100644 --- a/docs/general-development/excel-services-best-practices.md +++ b/docs/general-development/excel-services-best-practices.md @@ -1,237 +1,124 @@ --- title: Excel Services Best Practices -ms.date: 09/25/2017 +description: Describes the best practices for working with Excel Services and provides general advice and details on mitigating threats. +ms.date: 05/09/2023 keywords: guidelines f1_keywords: - guidelines -ms.prod: sharepoint ms.assetid: 56fa3913-c156-49da-bed0-a6a106fc129f -localization_priority: Normal +ms.localizationpriority: medium --- - # Excel Services Best Practices This topic contains a list of best-practice recommendations for working with Excel Services. - - - - ## Mitigating Threats - ### Anonymous Access and Information Disclosure The following settings combination gives anonymous users access to any files in the share to which the process account has access. Therefore, the following combination of settings is not recommended, because of the possibility of information disclosure: - - - - Anonymous access to Microsoft SharePoint Foundation is turned on. - - - You have a UNC trusted location and the **Process account** is turned on. - + > [!NOTE] > The **Process account** is a global Excel Services setting that affects all trusted locations. - - - - ### To view the Process account option - 1. On the **Start** menu, click **All Programs**. - - -2. Point to **Microsoft SharePoint 2010 Products**, and then click **SharePoint Central Administration**. - - -3. Under **Application Management**, click **Manage service applications**. - - -4. On the Manage Service Applications page, click **Excel Services Application**. - - -5. On the **Excel Services Application** page, click **Global Settings**. - - -6. In the **Security** section, look under **File Access Method** for the **Process account** option. - - +1. Point to **Microsoft SharePoint 2010 Products**, and then click **SharePoint Central Administration**. +1. Under **Application Management**, click **Manage service applications**. +1. On the Manage Service Applications page, click **Excel Services Application**. +1. On the **Excel Services Application** page, click **Global Settings**. +1. In the **Security** section, look under **File Access Method** for the **Process account** option. ### Denial of Service Attack In a denial of service attack against a Web service, an attacker generates very large, individual requests against the Web service. The purpose is to attempt to exploit the limits of one or more Web service input values. - - - + We recommend that you use the Microsoft Internet Information Services (IIS) setting to set the maximum request size for the Web service. - - - + Use the **maxRequestLength** attribute in the **httpRuntime** element in the **system.web** element to prevent denial of service attacks that are caused by users posting large files to the server. The default size is 4096 KB (4 MB). - - - + For more information, see [\ Element](https://msdn.microsoft.com/library/e9b81350-8aaf-47cc-9843-5f7d0c59f369.aspx) and [\ Element](https://msdn.microsoft.com/library/fd52b2c5-5014-4e6f-b869-4ea666dc83d6.aspx). - - - ### Sniffing Between the Calling Application and the Web Service Computer If the calling application and Excel Web Services are deployed to different computers, an attacker can listen to the network traffic for data transfer between the calling application and the Web service. This threat is also called "sniffing" or "eavesdropping." - - - + To help mitigate this threat, we recommend that you: - - - - Use Secure Sockets Layer (SSL) to set up a secure channel to protect data transfer between the client and the server. The SSL protocol helps to protect data against packet sniffing by anyone with physical access to the network. - - - Physically protect the relevant network if a custom application using Excel Web Services is running in a confined network—for example, if Excel Web Services is deployed on a Web front-end computer within the enterprise. - - -For more information, see [Securing Your Network](https://msdn.microsoft.com/library/af62ece0-0dd7-4b8e-ad12-4d13f2d60816.aspx) and [SOAP Security](https://msdn.microsoft.com/library/aa912494.aspx). - - - + +For more information, see [Securing Your Network](https://msdn.microsoft.com/library/af62ece0-0dd7-4b8e-ad12-4d13f2d60816.aspx) and [SOAP Security](https://msdn.microsoft.com/library/aa912494.aspx). + For information about Excel Services topology, scalability, performance, and security, see the Microsoft SharePoint Server 2010 TechCenter. - - - ### Spoofing We recommend that you use SSL to help mitigate the threats of hijacked Web service Internet Protocol (IP) addresses and ports, and to help prevent attackers from receiving requests and replying on behalf of the Web service. - - - + The SSL certificate is matched against a few properties, one of which is the IP address from which the message is coming. The attacker cannot spoof the IP address if it does not have the Web service SSL certificate. - - - + For more information, see [Securing Your Network](https://msdn.microsoft.com/library/af62ece0-0dd7-4b8e-ad12-4d13f2d60816.aspx). - - - ## Excel Services User-Defined Functions (UDFs) - ### Strong Name Dependencies In some cases, a user-defined function (UDF) assembly depends on other assemblies that are deployed with it. These dependent DLLs load successfully if they are in the global assembly cache, or if they are located in the same folder as the UDF assembly. - - - + In the latter case, however, it is possible for the load to fail if Excel Calculation Services has already loaded another assembly with the same name. (It fails either because the assembly is not strongly named, or because another version with the same name has been deployed and loaded.) - - - + Consider the following scenario, with the following directory structure: - - - -1. C:\\Udfs\\Udf01 - +1. ***C:\\Udfs\\Udf01*** + The Udf01 folder contains: - - - Udf01.dll - - - - dependent.dll (not strongly named) - - + + - Udf01.dll + - dependent.dll (not strongly named) The Udf01.dll file has a dependency on the dependent.dll file. - - -2. C:\\Udfs\\Udf02 - + +1. **C:\\Udfs\\Udf02** + The Udf02 folder contains: - - - Udf02.dll (which depends on Interop.dll) - - - - dependent.dll (which is not strongly named) - - + + - Udf02.dll (which depends on Interop.dll) + - dependent.dll (which is not strongly named) The Udf02.dll file has a dependency on the dependent.dll file. Udf01.dll's dependency and Udf02.dll's dependency share the same name. But Udf02.dll's dependent.dll file is not the same as Udf01.dll's dependent.dll file. - - + Assume the following flow: - - - - -1. Udf01.dll is the first DLL to be loaded. Excel Calculation Services looks for dependent.dll and loads Udf01.dll's dependency, which in this case is dependent.dll. - - -2. Udf02.dll is loaded after Udf01.dll. Excel Calculation Services sees that Udf02.dll depends on dependent.dll. However, a DLL with the name "dependent.dll" is already loaded. Therefore, Udf02.dll's dependent.dll file is not loaded, and the currently loaded dependent.dll file is used as the dependency. - - + +1. Udf01.dll is the first DLL to be loaded. Excel Calculation Services looks for dependent.dll and loads Udf01.dll's dependency, which in this case is dependent.dll. +1. Udf02.dll is loaded after Udf01.dll. Excel Calculation Services sees that Udf02.dll depends on dependent.dll. However, a DLL with the name "dependent.dll" is already loaded. Therefore, Udf02.dll's dependent.dll file is not loaded, and the currently loaded dependent.dll file is used as the dependency. + As a result, the object—in this case, the dependent.dll file that Udf02.dll needs—is not loaded into memory. - - - + To avoid name collision, we recommend that you strongly name your dependencies, and name them uniquely. - - - ## General - ### Naming Managed-Code DLLs To ensure that your assembly names are unique, use the fully qualified class name, following the [Namespace Naming Guidelines](https://msdn.microsoft.com/library/c08bc0d8-9b3a-4564-9af6-71699f62e00d.aspx). - - - -For example, use CompanyName.Hierarchichal.Namespace.ClassName instead ofNamespace.ClassName. - - - -## See also +For example, use `CompanyName.Hierarchichal.Namespace.ClassName` instead of `Namespace.ClassName`. +## See also #### Tasks - - - - - [How to: Trust a Location](how-to-trust-a-location.md) +- [How to: Trust a Location](how-to-trust-a-location.md) #### Concepts - - - - - [Excel Services Architecture](excel-services-architecture.md) - - - - [Accessing the SOAP API](accessing-the-soap-api.md) - - - - [Excel Services Alerts](excel-services-alerts.md) - - - - [Excel Services Known Issues and Tips](excel-services-known-issues-and-tips.md) - - - - [Excel Services Blogs, Forums, and Resources](excel-services-blogs-forums-and-resources.md) +- [Excel Services Architecture](excel-services-architecture.md) +- [Accessing the SOAP API](accessing-the-soap-api.md) +- [Excel Services Alerts](excel-services-alerts.md) +- [Excel Services Known Issues and Tips](excel-services-known-issues-and-tips.md) +- [Excel Services Blogs, Forums, and Resources](excel-services-blogs-forums-and-resources.md) diff --git a/docs/general-development/excel-services-blogs-forums-and-resources.md b/docs/general-development/excel-services-blogs-forums-and-resources.md index d4ae8038c..f938e4ce4 100644 --- a/docs/general-development/excel-services-blogs-forums-and-resources.md +++ b/docs/general-development/excel-services-blogs-forums-and-resources.md @@ -1,83 +1,44 @@ --- title: Excel Services Blogs, Forums, and Resources -ms.date: 09/25/2017 +description: Provides links to Excel Services blogs, forums, and resources, as well as links to articles on Excel Services concepts. +ms.date: 06/27/2022 keywords: blogger f1_keywords: - blogger -ms.prod: sharepoint ms.assetid: c0b137cd-126d-4c74-a3f7-eb9debe3c35f -localization_priority: Normal +ms.localizationpriority: medium --- - - # Excel Services Blogs, Forums, and Resources The following are links to blogs, forums, and additional resources related to Excel Services and SharePoint: - - - - - -|**Blog Name**|**Links**| -|:-----|:-----| -|Cum Grano Salis
| [Home page](https://blogs.msdn.com/cumgranosalis/)
[Excel Services page](https://blogs.msdn.microsoft.com/cumgranosalis/tag/excel-services/)
| -|Microsoft Excel: The official blog of the Microsoft Excel product team
| [Home page](https://www.microsoft.com/microsoft-365/blog/excel)
| - +| Blog Name | Links | +| :--------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------- | +| Cum Grano Salis | [Home page](https://blogs.msdn.com/cumgranosalis/) [Excel Services page](/archive/blogs/cumgranosalis/#excel-services) | +| Microsoft Excel: The official blog of the Microsoft Excel product team | [Home page](https://www.microsoft.com/microsoft-365/blog/excel) | +| Forum Name | Links | +| :----------------------------------- | :------------------------------------------------------------------------------------------------------------------ | +| SharePoint - Excel Services | [Excel Services forum home page](/sharepoint/dev/general-development/excel-services-blogs-forums-and-resources) | +| SharePoint Products and Technologies | [List of SharePoint Products and Technologies forums](https://social.msdn.microsoft.com/forums/category/sharepoint) | -|**Forum Name**|**Links**| -|:-----|:-----| -|SharePoint - Excel Services
| [Excel Services forum home page](/sharepoint/dev/general-development/excel-services-blogs-forums-and-resources)
| -|SharePoint Products and Technologies
| [List of SharePoint Products and Technologies forums](https://social.msdn.microsoft.com/forums/category/sharepoint)
| - - - -|**Additional Resources**|**Links**| -|:-----|:-----| -|Excel Services Resource Center
| [Excel Services Resource Center on MSDN](https://msdn.microsoft.com/office/bb203828.aspx)
| -|IT Pro \\ Administration Documentation
| [TechNet](https://technet.microsoft.com/library/ee424401%28office.14%29.aspx)
| -|Microsoft Excel Online, part of Office Online, also supports Excel workbooks in the browser.
|For more information about Excel Online, see the [documentation](https://technet.microsoft.com/library/ee855124.aspx) on Technet.
| - +| Additional Resources | Links | +| :------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | +| IT Pro \\ Administration Documentation | [TechNet](https://technet.microsoft.com/library/ee424401%28office.14%29.aspx) | +| Microsoft Excel Online, part of Office Online, also supports Excel workbooks in the browser. | For more information about Excel Online, see the [documentation](https://technet.microsoft.com/library/ee855124.aspx) on Technet. | ## See also - #### Concepts +- [Excel Services Overview](excel-services-overview.md) +- [Excel Services Development Roadmap](excel-services-development-roadmap.md) +- [Excel Services Architecture](excel-services-architecture.md) +- [Excel Services Best Practices](excel-services-best-practices.md) +- [Excel Services Alerts](excel-services-alerts.md) +- [Excel Services Known Issues and Tips](excel-services-known-issues-and-tips.md) - - - - [Excel Services Overview](excel-services-overview.md) - - - - [Excel Services Development Roadmap](excel-services-development-roadmap.md) - - - - [Excel Services Architecture](excel-services-architecture.md) - - - - [Excel Services Best Practices](excel-services-best-practices.md) - - - - [Excel Services Alerts](excel-services-alerts.md) - - - - [Excel Services Known Issues and Tips](excel-services-known-issues-and-tips.md) #### Other resources - - - - - [Walkthrough: Developing a Custom Application Using Excel Web Services](walkthrough-developing-a-custom-application-using-excel-web-services.md) - - - - [Unsupported Features in Excel Services](https://msdn.microsoft.com/library/5868e672-4786-4fed-9168-07ff538f6f5c%28Office.15%29.aspx) +- [Walkthrough: Developing a Custom Application Using Excel Web Services](walkthrough-developing-a-custom-application-using-excel-web-services.md) +- [Unsupported Features in Excel Services](https://msdn.microsoft.com/library/5868e672-4786-4fed-9168-07ff538f6f5c%28Office.15%29.aspx) diff --git a/docs/general-development/excel-services-development-roadmap.md b/docs/general-development/excel-services-development-roadmap.md index cb0e00517..dc34273fa 100644 --- a/docs/general-development/excel-services-development-roadmap.md +++ b/docs/general-development/excel-services-development-roadmap.md @@ -1,12 +1,12 @@ --- title: Excel Services Development Roadmap -ms.date: 09/25/2017 +description: Provides a roadmap for developing with Excel Services, focusing on Excel Web Service and the REST API. +ms.date: 06/09/2022 keywords: roadmap f1_keywords: - roadmap -ms.prod: sharepoint ms.assetid: 5c789f58-9cdb-4601-9047-9c6f83f2fbba -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/excel-services-ecmascript-javascript-jscript.md b/docs/general-development/excel-services-ecmascript-javascript-jscript.md index 9f6937d3c..6df58ec48 100644 --- a/docs/general-development/excel-services-ecmascript-javascript-jscript.md +++ b/docs/general-development/excel-services-ecmascript-javascript-jscript.md @@ -1,9 +1,9 @@ --- title: Excel Services ECMAScript (JavaScript, JScript) -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes ECMAScript (JavaScript and JScript) in Excel Services and provides links to ECMAScript tutorials. +ms.date: 06/09/2022 ms.assetid: 2355ffd0-8190-4385-955c-3f72bce7efc6 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/excel-services-ecmascript-overview.md b/docs/general-development/excel-services-ecmascript-overview.md index 9cd373897..7e56e839e 100644 --- a/docs/general-development/excel-services-ecmascript-overview.md +++ b/docs/general-development/excel-services-ecmascript-overview.md @@ -1,9 +1,9 @@ --- title: Excel Services ECMAScript Overview -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Provides an overview on ECMAScript in Excel Services and describes how to use the ECMAScript object model. +ms.date: 06/09/2022 ms.assetid: f8c1be86-df19-44c3-a3bc-c0da2b80df10 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/excel-services-error-codes.md b/docs/general-development/excel-services-error-codes.md index 646a87b3a..0d11ea32f 100644 --- a/docs/general-development/excel-services-error-codes.md +++ b/docs/general-development/excel-services-error-codes.md @@ -5,9 +5,8 @@ ms.date: 09/25/2017 keywords: alerts f1_keywords: - alerts -ms.prod: sharepoint ms.assetid: ff128d67-f3ac-4a8f-ae8e-1e19e343014e -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/excel-services-in-sharepoint.md b/docs/general-development/excel-services-in-sharepoint.md index 48dca018b..907f02be8 100644 --- a/docs/general-development/excel-services-in-sharepoint.md +++ b/docs/general-development/excel-services-in-sharepoint.md @@ -2,9 +2,8 @@ title: Excel Services in SharePoint description: Learn about the new capabilities in Excel Services in SharePoint and how you can use them in your own development efforts. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: f7e13fcb-a86a-4a1e-af59-3bace98ce9d7 -localization_priority: Normal +ms.localizationpriority: medium --- # Excel Services in SharePoint diff --git a/docs/general-development/excel-services-known-issues-and-tips.md b/docs/general-development/excel-services-known-issues-and-tips.md index 82ec5ef5e..66fa55c00 100644 --- a/docs/general-development/excel-services-known-issues-and-tips.md +++ b/docs/general-development/excel-services-known-issues-and-tips.md @@ -1,328 +1,163 @@ --- title: Excel Services Known Issues and Tips -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes known issues and tips for working with Excel Services and provides links to related documentation. +ms.date: 05/09/2023 ms.assetid: b4a41437-4f00-4f88-8510-627fa0252004 -localization_priority: Normal +ms.localizationpriority: medium --- - # Excel Services Known Issues and Tips The following are a known issues and tips for working with Excel Services. - - - - ## Excel Web Service - ### Viewing the WSDL Location You can view the Excel Web Services Web Services Description Language (WSDL) page by navigating to the following URL on the server: `http:////_vti_bin/excelservice.asmx?WSDL` - - - -If you do not have a custom site, you can view the WSDL by using the following URL: - - - - `http:///_vti_bin/excelservice.asmx?WSDL` - - - -For more information, see [Accessing the SOAP API](accessing-the-soap-api.md). - - - + +If you do not have a custom site, you can view the WSDL by using the following URL: `http:///_vti_bin/excelservice.asmx?WSDL` + +For more information, see [Accessing the SOAP API](accessing-the-soap-api.md). ### Understanding Excel Web Services and Namespaces The following are Excel web services and namespaces: - - - - The single web service object that contains all the API methods: **ExcelService** - - -- The schema namespace: `http://schemas.microsoft.com/office/excel/server/webservices` - - -- The web service page name: ExcelService.asmx - - +- The schema namespace: `http://schemas.microsoft.com/office/excel/server/webservices` +- The web service page name: **ExcelService.asmx** ### Linking Locally or to a Web Service -In certain scenarios, you should link directly to Microsoft.Office.Excel.Server.WebServices.dll and access it as you would any local assembly, instead of calling it as a web service through SOAP over HTTP. - - - +In certain scenarios, you should link directly to Microsoft.Office.Excel.Server.WebServices.dll and access it as you would any local assembly, instead of calling it as a web service through SOAP over HTTP. + For more information and guidelines on when to use direct linking, see [Loop-Back SOAP Calls and Direct Linking](loop-back-soap-calls-and-direct-linking.md). - - - ### Understanding Invalid Characters The calls to the **GetCell** and **GetRange** methods will fail if the workbook cells contain characters that are invalid in an XML response. - - - + For example, if a cell contains characters with hexadecimal values 0x1, 0x2 ... 0x8, the ASP.NET parser will throw an exception that the value of the character being written to the XML response is invalid: - - - - **System.InvalidOperationException: Client found response content type of 'text/html; charset=utf-8', but expected 'text/xml'. The request failed with the error message: -- ' ', hexadecimal value 0x01, is an invalid character.** - - - + +**System.InvalidOperationException: Client found response content type of 'text/html; charset=utf-8', but expected 'text/xml'. The request failed with the error message: -- \ \ \' ', hexadecimal value 0x01, is an invalid character.** + This behavior is expected. The XML specification that defines which characters are allowed in a valid XML response specifies that hexadecimal values 0x1, 0x2 ... 0x8 are invalid XML characters: - - - - **Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */** - - - -For more information, see [W3C Extensible Markup Language (XML) Specification](http://www.w3.org/TR/REC-xml) (http://www.w3.org/TR/REC-xml#NT-Char). - - - + +**Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */** + +For more information, see [W3C Extensible Markup Language (XML) Specification](http://www.w3.org/TR/REC-xml#NT-Char). ### Saving a Workbook When you make changes to a workbook—for example, by setting values to a range using Excel Web Services—the changes to the workbook are preserved only for that particular session. The changes are not saved or persisted back to the original workbook. When the current workbook session ends (for example, when you call the **CloseWorkbook** method, or the session times out), changes you made will be lost. - - - + If you want to save changes to a workbook, you can use the **GetWorkbook** method and then save the workbook using the API of the destination file store. For more information, see [How to: Get an Entire Workbook or a Snapshot](how-to-get-an-entire-workbook-or-a-snapshot.md) and [How to: Save a Workbook](https://msdn.microsoft.com/library/feb74f7a-2d8f-4672-911b-de85f8852aea%28Office.15%29.aspx). - - - ### Understanding the Url Property of an Excel Web Services Proxy Class -Do not use the **Url** property of an Excel Web Services proxy for the location of the workbook you want to open. The **Url** property of a web service proxy class generated by Visual Studio gets or sets the base URL of the XML web service the client is requesting. In the case of Excel Web Services, this is usually: - - - - `http:///_vti_bin/ExcelService.asmx` - - - -To specify the location of a workbook, use the **OpenWorkbook** method instead of the **Url** property as shown in the following code example. - - - - +Do not use the **Url** property of an Excel Web Services proxy for the location of the workbook you want to open. The **Url** property of a web service proxy class generated by Visual Studio gets or sets the base URL of the XML web service the client is requesting. In the case of Excel Web Services, this is usually: `http:///_vti_bin/ExcelService.asmx` +To specify the location of a workbook, use the **OpenWorkbook** method instead of the **Url** property as shown in the following code example. -``` - +```csharp //Instantiate the web service and make a status array object. ExcelService xlservice = new ExcelService(); -string sheetName = "Sheet1"; +string sheetName = "Sheet1"; //Set the path to the workbook to open. //TODO: Change the path to the workbook - //to point to a workbook you have access to. +//to point to a workbook you have access to. //The workbook must be in a trusted location. -string targetWorkbookPath = - "http://myserver02/example/Shared%20Documents/Book1.xlsx"; +string targetWorkbookPath = "http://myserver02/example/Shared%20Documents/Book1.xlsx"; //Set credentials for requests. xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials; -//Call the open workbook, and point to the trusted +//Call the open workbook, and point to the trusted //location of the workbook to open. -string sessionId = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", - "en-US", out outStatus); - +string sessionId = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", out outStatus); ``` -For more information, see [WebClientProtocol.Url Property](https://go.microsoft.com/fwlink/?LinkId=64908) (https://msdn.microsoft.com/library/default.asp?url=/library/cpref/html/frlrfSystemWebServicesProtocolsWebClientProtocolClassUrlTopic.asp). - - - +For more information, see [WebClientProtocol.Url Property](https://msdn.microsoft.com/library/default.asp?url=/library/cpref/html/frlrfSystemWebServicesProtocolsWebClientProtocolClassUrlTopic.asp). ## Understanding Security - ### Using Workbook Permissions Beware of the following issues regarding workbook permissions: - - - - Excel Web Services uses the Microsoft SharePoint Foundation authorization scheme to verify that the caller has the right to call APIs (that is, make web service calls) on the SharePoint Foundation site (that is, the website where Excel Web Services is located) remotely. If the caller does not have the "Use Remote API" right, the Excel Web Services returns an "HTTP 401 (Unauthorized)" error, and logs an "API authorization failed" event. Excel Web Services performs these authorization checks only for calls that originate as SOAP calls. Calls from applications that link locally to Microsoft.Office.Excel.Server.WebServices.dll are not considered remote calls. Therefore, they are not subject to authorization checks. However, if the application that links locally to Microsoft.Office.Excel.Server.WebServices.dll is itself a SOAP service, and handles the service's SOAP calls, the call to Excel Web Services will seem like a SOAP call (even though the application links directly to Microsoft.Office.Excel.Server.WebServices.dll). In this scenario, Excel Web Services will perform the authorization checks. - - - To get the entire workbook (for example, by calling the **GetWorkbook** method using the `WorkbookType.FullWorkbook` argument), the caller needs "open" permission for the workbook or "read" permission in a file share. - - - To call the **GetApiVersion** method, no permission is necessary. - - - For the rest of the Excel Web Services methods, besides credentials, the caller needs "view" permission (in SharePoint Foundation) or "read" permission (in a file share) for the workbook. - - ### Trusted Location The workbooks you want to open in Excel Services must be placed in a trusted location. If not, the Excel Web Services calls to open the workbook will fail. - - - + For information about how to trust a location, see [How to: Trust a Location](how-to-trust-a-location.md) and [How to: Trust Workbook Locations Using Script](https://msdn.microsoft.com/library/79ab6ced-7a0c-4275-b852-bb246fc6be57%28Office.15%29.aspx). - - - ## Visual Studio - ### Microsoft Visual Studio Proxy Behavior -When Microsoft Visual Studio creates a proxy class for a client project that calls Excel Web Services, it has the following behavior: - - - +When Microsoft Visual Studio creates a proxy class for a client project that calls Excel Web Services, it has the following behavior: + If a method has no return value, and one or more **out** arguments, the first **out** argument is moved to become the return value. That is, the method in the proxy class will have one less **out** argument in the method signature. But the signature will have a return value with the type and content of what used to be the first **out** argument. - - - + The affected Excel Web Services methods are: - - - - **Calculate** - - - **CalculateA1** - - - **CalculateWorkbook** - - - **CancelRequest** - - - **CloseWorkbook** - - - **GetSessionInformation** - - - **Refresh** - - - **SetCell** - - - **SetCellA1** - - - **SetRange** - - - **SetRangeA1** - - ## Excel Services User-Defined Functions - ### Global Assembly Cache is Checked First, Then the Local Folder By design in the Microsoft .NET Framework, an assembly in a global assembly cache will be loaded instead of the same assembly in a local folder. The common language runtime will look for an assembly in the global assembly cache first before searching in the local folders. - - - + Therefore, if an assembly is installed in the global assembly cache and is in the UDF list but disabled (or removed from the UDF list altogether), and an identical assembly is installed in a local folder and enabled, the assembly in the global assembly cache will still get loaded and used instead of the same assembly in the local folder. - - - + This does not affect upgrade scenarios in which the assembly version has been modified, which means the assembly is not the same anymore. - - - ## General - ### Order of Strings in Sharedstring.xml is Not Maintained -Excel Services does not maintain the original order of strings in a workbook shared-string table (the Sharedstrings.xml part within the Microsoft Office Excel XML Format file). For example, execute the following steps: - - - - -1. Open a file using Excel. - - -2. Save the file in .xlsx file format. - - -3. Upload the file to a document library that is a trusted location. - - -4. Open the file in the document library by using Excel Web Access. - - -5. Click **Open in Excel**. - - -6. Save the file in .xlsx file format. - - -If you compare the Sharedstrings.xml file created in Step 2 with the one created in Step 6, you will find the order of the Sharedstrings.xml parts might be different. - - - +Excel Services does not maintain the original order of strings in a workbook shared-string table (the **Sharedstrings.xml** part within the Microsoft Office Excel XML Format file). For example, execute the following steps: + +1. Open a file using Excel. +1. Save the file in .xlsx file format. +1. Upload the file to a document library that is a trusted location. +1. Open the file in the document library by using Excel Web Access. +1. Click **Open in Excel**. +1. Save the file in .xlsx file format. + +If you compare the **Sharedstrings.xml** file created in Step 2 with the one created in Step 6, you will find the order of the **Sharedstrings.xml** parts might be different. + You should not write an application that assumes the order of strings in the shared-string table is fixed. For example, you cannot replace the shared-string table with an existing localized translation table. You must adjust to the new ordering of strings in the shared-string table. - - - ## See also - #### Tasks +- [How to: Trust a Location](how-to-trust-a-location.md) - - - - [How to: Trust a Location](how-to-trust-a-location.md) #### Concepts - - - - - [Excel Services Best Practices](excel-services-best-practices.md) - - - - [Excel Services Alerts](excel-services-alerts.md) - - - - [Excel Services Architecture](excel-services-architecture.md) - - - - [Supported and Unsupported Features](supported-and-unsupported-features.md) - - - - [Accessing the SOAP API](accessing-the-soap-api.md) - - - - [Excel Services Blogs, Forums, and Resources](excel-services-blogs-forums-and-resources.md) +- [Accessing the SOAP API](accessing-the-soap-api.md) +- [Excel Services Alerts](excel-services-alerts.md) +- [Excel Services Architecture](excel-services-architecture.md) +- [Excel Services Best Practices](excel-services-best-practices.md) +- [Excel Services Blogs, Forums, and Resources](excel-services-blogs-forums-and-resources.md) +- [Supported and Unsupported Features](supported-and-unsupported-features.md) diff --git a/docs/general-development/excel-services-overview.md b/docs/general-development/excel-services-overview.md index 5bc2b52e2..0a6a80f2e 100644 --- a/docs/general-development/excel-services-overview.md +++ b/docs/general-development/excel-services-overview.md @@ -1,9 +1,9 @@ --- title: Excel Services Overview +description: "Excel Services is a service application that enables you to load, calculate, and display Microsoft Excel workbooks on Microsoft SharePoint." ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: 5fa22ebb-e507-4ffc-a425-e755502feae2 -localization_priority: Priority +ms.localizationpriority: high --- @@ -283,7 +283,7 @@ From there you can use OData system query options to get specific information ab - [Walkthrough: Developing a Custom Application Using Excel Web Services](walkthrough-developing-a-custom-application-using-excel-web-services.md) -- [Frequently Asked Questions About Excel Services UDFs](frequently-asked-questions-about-excel-services-udfs.md) +- [Frequently Asked Questions About Excel Services UDFs](frequently-asked-questions-about-excel-services-udfs.yml) - [Unsupported Features in Excel Services](https://msdn.microsoft.com/library/5868e672-4786-4fed-9168-07ff538f6f5c%28Office.15%29.aspx) diff --git a/docs/general-development/excel-services-rest-api-overview.md b/docs/general-development/excel-services-rest-api-overview.md index 3eda94642..7062be383 100644 --- a/docs/general-development/excel-services-rest-api-overview.md +++ b/docs/general-development/excel-services-rest-api-overview.md @@ -1,9 +1,9 @@ --- title: Excel Services REST API Overview -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Provides an overview of the Excel Services REST API and provides a link to an article about the Microsoft Graph REST API endpoint. +ms.date: 06/09/2022 ms.assetid: 5872f311-e180-4578-ac80-2519c1081951 -localization_priority: Priority +ms.localizationpriority: high --- @@ -12,7 +12,7 @@ localization_priority: Priority The REST API in Excel Services is new in Microsoft SharePoint Server 2010. By using the REST API, you can access workbook parts or elements directly through a URL. > [!NOTE] -> The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For For Office 365 Education, Business, and Enterprise accounts,, use the Excel REST APIs that are part of the [Microsoft Graph](http://graph.microsoft.io/docs/api-reference/v1.0/resources/excel) endpoint. +> The Excel Services REST API for SharePoint Online will no longer be supported for Microsoft 365 accounts from February 28th, 2022 forward. Instead, please use the REST API that’s part of the [Microsoft Graph](http://graph.microsoft.io/docs/api-reference/v1.0/resources/excel) endpoint. diff --git a/docs/general-development/excel-services-rest-api.md b/docs/general-development/excel-services-rest-api.md index a2994cd39..29229c636 100644 --- a/docs/general-development/excel-services-rest-api.md +++ b/docs/general-development/excel-services-rest-api.md @@ -1,9 +1,9 @@ --- title: Excel Services REST API -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes the Representational State Transfer (REST) API in Excel Services and provides links to articles and tutorials about the REST API. +ms.date: 06/09/2022 ms.assetid: 32033fea-873c-4781-900a-6946906066b0 -localization_priority: Priority +ms.localizationpriority: high --- @@ -12,7 +12,7 @@ localization_priority: Priority This section contains information about the Representational State Transfer (REST) API in Excel Services and explains how to use it. > [!NOTE] -> The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of the [Microsoft Graph](http://graph.microsoft.io/docs/api-reference/v1.0/resources/excel +> The Excel Services REST API for SharePoint Online will no longer be supported for Microsoft 365 accounts from February 28th, 2022 forward. Instead, please use the REST API that’s part of the [Microsoft Graph](http://graph.microsoft.io/docs/api-reference/v1.0/resources/excel ) endpoint. diff --git a/docs/general-development/excel-services-user-defined-functions.md b/docs/general-development/excel-services-user-defined-functions.md index e35a8b74f..df735d7df 100644 --- a/docs/general-development/excel-services-user-defined-functions.md +++ b/docs/general-development/excel-services-user-defined-functions.md @@ -1,12 +1,12 @@ --- title: Excel Services User-Defined Functions +description: "This section contains information about user-defined functions (UDFs) and how to use UDF attributes in your code." ms.date: 09/25/2017 keywords: functions f1_keywords: - functions -ms.prod: sharepoint ms.assetid: 27dd8024-7e00-40de-a688-afc67c880603 -localization_priority: Normal +ms.localizationpriority: medium --- @@ -35,7 +35,7 @@ This section contains information about user-defined functions (UDFs) and how to > Get step-by-step instructions about developing Excel Services UDFs by using Microsoft Visual C#. - [Frequently Asked Questions About Excel Services UDFs](frequently-asked-questions-about-excel-services-udfs.md) + [Frequently Asked Questions About Excel Services UDFs](frequently-asked-questions-about-excel-services-udfs.yml) diff --git a/docs/general-development/excel-web-access.md b/docs/general-development/excel-web-access.md index 3d7c15135..104fbd172 100644 --- a/docs/general-development/excel-web-access.md +++ b/docs/general-development/excel-web-access.md @@ -1,9 +1,9 @@ --- title: Excel Web Access -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes the Excel Web Access web part and provides its reference and links to tutorials related to Excel Web Access. +ms.date: 06/09/2022 ms.assetid: eef8991d-0844-4b35-a092-33c957102dee -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/excel-web-services.md b/docs/general-development/excel-web-services.md index 6b6f1de2f..843b43fa3 100644 --- a/docs/general-development/excel-web-services.md +++ b/docs/general-development/excel-web-services.md @@ -1,9 +1,9 @@ --- title: Excel Web Services -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes Excel Web Services, explains how to use it to develop custom applications, and provides links to articles and tutorials. +ms.date: 06/09/2022 ms.assetid: e30ef4e3-72ff-43de-beba-b377141d4d19 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/exporting-and-importing-search-configuration-settings-in-sharepoint.md b/docs/general-development/exporting-and-importing-search-configuration-settings-in-sharepoint.md index 27604eae6..e91a6b31a 100644 --- a/docs/general-development/exporting-and-importing-search-configuration-settings-in-sharepoint.md +++ b/docs/general-development/exporting-and-importing-search-configuration-settings-in-sharepoint.md @@ -1,29 +1,29 @@ --- title: Exporting and importing search configuration settings in SharePoint +description: Get code examples that show you how to export and import customized search configuration settings. These settings include all customized query rules, result sources, result types, ranking models, and site search settings. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: d00679a3-ffa2-4281-ad8b-70fc2c4a14e2 -localization_priority: Normal +ms.localizationpriority: medium --- # Exporting and importing search configuration settings in SharePoint -Get code examples that show you how to export and import customized search configuration settings. These settings include all customized query rules, result sources, result types, ranking models, and site search settings. SharePoint exposes this functionality through the [Microsoft.Office.Server.Search.Portability](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Portability.aspx) namespace.You can also export customized search configuration settings from a Search service application (SSA) and import the settings to site collections and sites. +Get code examples that show you how to export and import customized search configuration settings. These settings include all customized query rules, result sources, result types, ranking models, and site search settings. SharePoint exposes this functionality through the [Microsoft.Office.Server.Search.Portability](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Portability.aspx) namespace.You can also export customized search configuration settings from a Search service application (SSA) and import the settings to site collections and sites. > [!NOTE] -> You can't import customized search configuration settings to an SSA, or export the default search configuration settings. - - - +> You can't import customized search configuration settings to an SSA, or export the default search configuration settings. + + + ## Export search configuration settings The following code shows how to use [SearchConfigurationPortability](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Portability.SearchConfigurationPortability.aspx) to export your site's search configuration settings. The code uses an example site `http://yoursite/sites/publishing1`, which you'd replace with your own site. _fileName_ refers to the file where the search configuration settings are stored; _owner_ specifies the [SPWeb](https://msdn.microsoft.com/library/Microsoft.SharePoint.SPWeb.aspx) level at which the search configuration settings are obtained. - - - + + + ``` @@ -43,11 +43,11 @@ private static void Export(string fileName) The following code shows how to import search configuration settings from a file by using [SearchConfigurationPortability](https://msdn.microsoft.com/library/Microsoft.Office.Server.Search.Portability.SearchConfigurationPortability.aspx) and replace the existing search settings on a specified site, `http://yoursite/sites/publishing1`. _fileName_ refers to the file where the search configuration settings are stored; _owner_ specifies the [SPWeb](https://msdn.microsoft.com/library/Microsoft.SharePoint.SPWeb.aspx) level at which the search configuration settings are obtained. - - - -```cs + + + +```csharp private static void Import(string fileName) { @@ -66,13 +66,13 @@ private static void Import(string fileName) - [Search in SharePoint](search-in-sharepoint.md) - - + + - [Export and import customized search configuration settings in SharePoint](https://technet.microsoft.com/library/jj871675.aspx) - - - - - + + + + + diff --git a/docs/general-development/extend-the-fixed-format-export-feature-in-word-automation-services.md b/docs/general-development/extend-the-fixed-format-export-feature-in-word-automation-services.md index f1f88a285..752362eb0 100644 --- a/docs/general-development/extend-the-fixed-format-export-feature-in-word-automation-services.md +++ b/docs/general-development/extend-the-fixed-format-export-feature-in-word-automation-services.md @@ -2,9 +2,8 @@ title: Extend the fixed-format export feature in Word Automation Services description: Extend Word Automation Services in Microsoft Office 2013 to replace the library used by the fixed-format export feature. ms.date: 12/14/2020 -ms.prod: sharepoint ms.assetid: d8375505-432e-438e-971b-221a1d9bb601 -localization_priority: Normal +ms.localizationpriority: medium --- # Extend the fixed-format export feature in Word Automation Services diff --git a/docs/general-development/external-content-types-in-sharepoint.md b/docs/general-development/external-content-types-in-sharepoint.md index a30bd15d9..c7760d0d2 100644 --- a/docs/general-development/external-content-types-in-sharepoint.md +++ b/docs/general-development/external-content-types-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: External content types in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes external content types in SharePoint and provides the prerequisites and steps to create external content types. +ms.date: 06/09/2022 ms.assetid: 11d7adb5-5388-4517-ae03-beb7be1c6981 -localization_priority: Priority +ms.localizationpriority: high --- @@ -129,7 +129,7 @@ Table 1 contains examples of tasks that illustrate working with external content **Table 1. Basic tasks for working with external content types** -|**Task**|**Description**| +|Task|Description| |:-----|:-----| | [How to: Create an external content type from an OData source in SharePoint](how-to-create-an-external-content-type-from-an-odata-source-in-sharepoint.md)
|Learn how to use Visual Studio 2012 to discover a published OData source, and create a reusable external content type for use in SharePoint Business Connectivity Services (BCS).
| | [How to: Create external content types for SQL Server in SharePoint](how-to-create-external-content-types-for-sql-server-in-sharepoint.md)
|Learn how to create an external content type based on a SQL Server database.
| diff --git a/docs/general-development/external-events-and-alerts-in-sharepoint.md b/docs/general-development/external-events-and-alerts-in-sharepoint.md index 235ad0494..056ad3528 100644 --- a/docs/general-development/external-events-and-alerts-in-sharepoint.md +++ b/docs/general-development/external-events-and-alerts-in-sharepoint.md @@ -1,289 +1,167 @@ --- title: External events and alerts in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Learn the concepts behind creating remote event receivers in SharePoint that can be attached to external lists and execute when the external data that the list represents is updated. +ms.date: 05/18/2023 ms.assetid: e48e4812-a185-43c5-b243-04b1d79b88ee -localization_priority: Normal +ms.localizationpriority: medium --- - - # External events and alerts in SharePoint + Learn the concepts behind creating remote event receivers in SharePoint that can be attached to external lists and execute when the external data that the list represents is updated. -## What are event receivers? - -An event receiver is a piece of managed code that responds to SharePoint triggering events such as adding, moving, deleting, checking in, and checking out. When these events occur, and the event receiver's criteria are met, the code that you write to provide additional functionality is executed. When SharePoint objects, such as lists, workflows and features, are configured to wait on these events to occur, they are called event hosts. - - - -Event receivers let you perform business logic when a specific event occurs. Essentially, these are the hooks where you can create code to handle certain conditions, make notifications, update other systems, and so on. When you create event receivers, a DLL is generated. You can place that DLL into the global assembly cache, so that the event receivers are invoked in response to any changes in an external system. - - - -The following example contains a simple external event receiver in C# that executes when a new item is added to the list. - - - +## What are event receivers? +An event receiver is a piece of managed code that responds to SharePoint triggering events such as adding, moving, deleting, checking in, and checking out. When these events occur, and the event receiver's criteria are met, the code that you write to provide additional functionality is executed. When SharePoint objects, such as lists, workflows and features, are configured to wait on these events to occur, they are called event hosts. +Event receivers let you perform business logic when a specific event occurs. Essentially, these are the hooks where you can create code to handle certain conditions, make notifications, update other systems, and so on. When you create event receivers, a DLL is generated. You can place that DLL into the global assembly cache, so that the event receivers are invoked in response to any changes in an external system. -```cs +The following example contains a simple external event receiver in C# that executes when a new item is added to the list. +```csharp public class EntryContentEventReceiver : SPItemEventReceiver { - public override void ItemAdded(SPItemEventProperties properties) - { - base.ItemAdded(properties); - - // properties.ExternalNotificationMessage holds the message sent by the external - // system. - } + public override void ItemAdded(SPItemEventProperties properties) + { + base.ItemAdded(properties); + // properties.ExternalNotificationMessage holds the message sent by the external system + } +} ``` -External event receivers can also be extended to work against an entity event receiver and as remote event receivers deployed as a service on-premises or in Microsoft Azure. - - - +External event receivers can also be extended to work against an entity event receiver and as remote event receivers deployed as a service on-premises or in Microsoft Azure. ## What are remote event receivers? - Remote event receivers are new for SharePoint. In a traditional SharePoint solution, you use an event receiver to handle events such as users creating or deleting lists or items in lists. In an SharePoint Add-in, you use a remote event receiver to handle similar events. Remote event receivers work similarly to regular event receivers, except that remote event receivers handle events that occur when an SharePoint Add-in is on a different system from its host web application. - - - + Business Connectivity Services (BCS) uses remote event receivers attached to external lists and entities to allow you to write code that can react to changes in data hosted in the external system. - - - + To accommodate this, two stereotypes have been added to the schema of the BDC model: **EventSubscriber** and **EventUnsubscriber**. - -> [!NOTE] -> Event receivers are not supported in sandboxed solutions. - - - +> [!NOTE] +> Event receivers are not supported in sandboxed solutions. ## What features and capabilities does the new external event receiver infrastructure provide? - By using and extending the SharePoint event receiver features, BCS is able to add alerts, external list event receivers, and entity receivers to provide extended functionality. - - - - -- **Alerts:** Alerts have been an integral part of SharePoint for several versions, but until SharePoint, they would not work with external lists. Now a user can create alerts on an external list that have the same behavior as alerts on a standard SharePoint list. - - -- **External list event receivers:** Event receivers can now be attached to external lists just like they can for standard lists. This provides an extensibility mechanism that lets you write code that is executed at specific times. - - + +- **Alerts:** Alerts have been an integral part of SharePoint for several versions, but until arePoint, they would not work with external lists. Now a user can create alerts on an external list that have the same behavior as alerts on a standard SharePoint list. +- **External list event receivers:** Event receivers can now be attached to external lists just like they can for standard lists. This provides an extensibility mechanism that lets you write de that is executed at specific times. - **Entity event receivers:** Entity event receivers provide flexibility by letting you write more robust code that allows other operations like providing user context for filtering data. This can allow better personalization and customized security. - - + Remote eventing in SharePoint makes several interesting scenarios possible. For example, you might have a "Sales Lead Tracking" application that lets a sales team be notified when new sales leads are entered into an external lead application. When a new sales lead is entered, SharePoint is notified through the notification system that is part of the lead application. SharePoint receives the notification and then creates new tasks for the specified salespeople to follow up on each new lead. By configuring the sales lead entry application on the external system to send a notification to SharePoint on the creation of each new lead, SharePoint is kept completely up to date. - - - ## Prerequisites for using event receivers for external lists - To use event receivers for external lists, you need the following: - - - - SharePoint - - - Visual Studio 2012 - - + For more information about setting up a SharePoint development environment, see [Set up a general development environment for SharePoint](set-up-a-general-development-environment-for-sharepoint.md). - - - ## Configure the external system to notify SharePoint of external events - For external events to work, a number of components have to be installed and configured on both the SharePoint host and the external system. - - - + You have to configure the external system so that it can do the following: - - - - **Determine when underlying data changes.** For the external system to know when changes have been made, you have to create a mechanism for polling for specific changes. You can do this by using a timed service that polls the data source at specific intervals. - - -- **Receive and record requests for subscriptions to change notifications.** The external system has to implement a subscription store so that it can store who should receive change notifications. The simplest solution is probably a database table. The table (or whatever mechanism you choose) should record SubscriptionID, Delivery Address, Event Type, and Entity Name. - - -- **Post notifications to Representational State Transfer (REST) endpoints.** To let SharePoint subscribers know that a change has occurred, the external system application needs to send an HTTP WebRequest to the delivery address recorded in the subscription store. This delivery address is a RESTful endpoint generated by SharePoint during the subscription process. - - +- **Receive and record requests for subscriptions to change notifications.** The external system has to implement a subscription store so that it can store who should receive change notifications. The simplest solution is probably a database table. The table (or whatever anism you choose) should record SubscriptionID, Delivery Address, Event Type, and Entity Name. +- **Post notifications to Representational State Transfer (REST) endpoints.** To let SharePoint subscribers know that a change has occurred, the external system application needs to send an HTTPWebRequest to the delivery address recorded in the subscription store. This delivery address is a RESTful endpoint generated by SharePoint during the subscription process ## Configure SharePoint to allow communication with external systems - To allow communication with the external system, SharePoint must be configured with the following: - - - - A BDC model with **EventSubscriber** and **EventUnsubscriber** stereotypes configured - - - Event receivers - - ### How is external eventing enabled? You can enable external eventing in SharePoint through **Site Settings** or by adding the following custom feature id to your project - - - - -```XML +```xml ``` Eventing for an external system is enabled when SharePoint creates the delivery address and sends it to the external system during the Subscribe process. - - - ## Overall flow of external eventing between SharePoint and external systems - In Figure 1, notice that there are three distinct steps involved when using external event receivers: subscribe, notification, and unsubscribe. - - - **Figure 1 Complete data flow for external notifications** - - - - - - - -![Data flow for external event notifications](../images/ExtEvtsAndAlrts_Figure1.jpg) - - - - - - - - - - - +[Data flow for external event notifications](../images/ExtEvtsAndAlrts_Figure1.jpg) ## EventSubscriber: subscribe to notifications - For a user (SharePoint object) to receive notifications when the underlying data has changed, the user must subscribe to the notifications for an entity. To allow this, the BDC Model schema has been extended to include the **Subscribe** stereotype. The **Subscribe** stereotype is used by SharePoint to let the external system know that the sender is requesting to be notified of changes to the underlying data. - - - + Figure 2 demonstrates the flow of information between SharePoint and the external system during the Subscribe process. - - - **Figure 2. Subscribe process flow** - - - - - - - ![External eventing Subscribe method process flow](../images/ExtEvtsAndAlerts_Figure2.jpg) - - - -The following describes the general flow of the subscription process: - - - - - - +The following describes the general flow of the subscription process: 1. **User requests a subscription for notifications.** Using a custom user interface (a button on a page or a ribbon), SharePoint initiates a request to the external system app for notifications. - - -2. **SharePoint generates a delivery address.** As part of the Subscribe process, SharePoint creates a REST endpoint where notifications will be delivered. - - -3. **Subscription request is sent to the external system.** SharePoint then encapsulates the requestor information along with the dynamically generated REST URL, and sends a web request to the external system. - - -4. **External system receives request.** There are different possibilities for implementing a subscription store. In this example, you will use a SQL Server database table. - - -5. **External system generates a subscriptionId.** A new **subscriptionId** is generated using code in the line-of-business (LOB) application. The **subscriptionId** should be a GUID. - - -6. **External system records the subscription.** The external system application records the **subscriptionId**, delivery address, event type, and other information sent from SharePoint into the subscription store. - - -7. **External system sends the subscriptionId back to SharePoint.** For SharePoint to correctly route the updates that are sent by the external system, the **subscriptionId** is sent back to SharePoint and SharePoint records that information in its database. - - The BDC model is working against a **Subscribe** function import. The metadata for function import is shown in this example. - +1. **SharePoint generates a delivery address.** As part of the Subscribe process, SharePoint creates a REST endpoint where notifications will be delivered. +1. **Subscription request is sent to the external system.** SharePoint then encapsulates the requestor information along with the dynamically generated REST URL, and sends a web request to the external system. +1. **External system receives request.** There are different possibilities for implementing a subscription store. In this example, you will use a SQL Server database table. +1. **External system generates a subscriptionId.** A new **subscriptionId** is generated using code in the line-of-business (LOB) application. The **subscriptionId** should be a GUID. +1. **External system records the subscription.** The external system application records the **subscriptionId**, delivery address, event type, and other information sent from SharePoint into the subscription store. +1. **External system sends the subscriptionId back to SharePoint.** For SharePoint to correctly route the updates that are sent by the external system, the **subscriptionId** is sent back to SharePoint and SharePoint records that information in its database. + The BDC model is working against a **Subscribe** function import. The metadata for function import is shown in this example. -```XML - FunctionImport - +```xml - - - + + + - - - + + + - ``` - ### Code example: BDC model with Subscribe The following is an example of a BDC model with the **Subscribe** method added. - - - - -```XML +```xml /EntitySubscribes @@ -318,7 +196,7 @@ The following is an example of a BDC model with the **Subscribe** method added. - Customers @@ -368,148 +246,72 @@ The following is an example of a BDC model with the **Subscribe** method added. ``` Table 1 lists the important attributes of the BDC model that are needed to make the **Subscribe** stereotype work. - - - **Table 1. BDC model attributes** - -|**Attribute**|**Description**| -|:-----|:-----| -|**IsDeliveryAddress**
|A **Boolean** flag used on a **TypeDescriptor** to indicate whether the delivery address provided is to be used to deliver notifications.
| -|**IsEventType**
|A **Boolean** flag used on a **TypeDescriptor** to indicate whether the event type provided is to be used as the event type. Valid event types are **ItemAdded**, **ItemUpdated**, **ItemDeleted**, and so on.
| -|**SubscriptionIdName**
|A string used on a **TypeDescriptor** that represents the name of a **subscriptionId** part.
| - +| **Attribute** | **Description** | +| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **IsDeliveryAddress** | A **Boolean** flag used on a **TypeDescriptor** to indicate whether the delivery address provided is to be used to deliver notifications. | +| **IsEventType** | A **Boolean** flag used on a **TypeDescriptor** to indicate whether the event type provided is to be used as the event type. Valid event types are **ItemAdded**, **ItemUpdated**, **ItemDeleted**, and so on. | +| **SubscriptionIdName** | A string used on a **TypeDescriptor** that represents the name of a **subscriptionId** part. | ## Notifications - In SharePoint, the event-handling infrastructure has been enhanced to allow external data sources to notify SharePoint when information in the external system has been modified. Then, when SharePoint receives a notification, event receivers that are associated with the SharePoint external list or entity can execute code to perform specified actions. - - - + When a subscription is created, the external system needs a way to tell SharePoint about the changes that have occurred on a particular entity. The external system is expected to deliver notifications to the delivery address as provided by SharePoint to the external system during the Subscribe process using an OData Atom-formatted payload. - - - + Figure 3 shows the communication flow between the external system and SharePoint when a new record is added to the data in the external system. - - - **Figure 3 Notification process** - - - - - - - ![External event notification process](../images/ExtEvtsAndAlerts_Figure3.jpg) - - - - - - - 1. **New record is added to external system.** In this example, a new record is added to the external system using the application user interface or directly into the database. - - -2. **External system application is notified of the change.** The external system application has to be made aware of the changes that are happening to the underlying data. There are a number of ways to do this. You can use SQL triggers that fire when data changes on specific tables, or you can create a polling mechanism to query the data store for changes. There are other ways to accomplish this, but each will have to be evaluated with performance in mind. - - -3. **External system sends notification request to SharePoint through delivery address.** To communicate the changes, an Atom-formatted request has to be sent to the delivery address that is stored in the LOB application's subscription store. - - +1. **External system application is notified of the change.** The external system application has to be made aware of the changes that are happening to the underlying data. There are a number of ways to do this. You can use SQL triggers that fire when data changes on specific tables, or you can create a polling mechanism to query the data store for changes. There are other ways to accomplish this, but each will have to be evaluated with performance in mind. +1. **External system sends notification request to SharePoint through delivery address.** To communicate the changes, an Atom-formatted request has to be sent to the delivery address that is stored in the LOB application's subscription store. ### Notification payload In constructing the notification, the LOB system has to create an HTTP payload that includes either the full details of the item that changed, or just the identity of the item that changed. - - - - **Identity:** When the payload is sent as an identity, the payload is expected to have only information about the identity of the changed item. For example, for a customer in a Customers entity, the payload would only contain the ID of the customer that has changed. - - - **Full item:** In this case, the payload is an entire record that has changed in the external system. In the customer example, the entire changed customer record is included. - + > [!NOTE] -> The full item is only supported when you use the OData connector. - - - +> The full item is only supported when you use the OData connector. The type of payload that is being sent by the external system must be indicated during the subscription process. - - - -The following is an example of the BDC model property used for notifications. - - - - +The following is an example of the BDC model property used for notifications. -```XML - +```xml ODataEntryContentNotificationParser - ``` If it is not specified, the default payload is an identity payload. - - - ### Notification delivery address (virtual address) The subscription process initiated from SharePoint results in a virtual address being created by SharePoint, allowing an entry point for the external system to post notifications. The delivery address is used by the external system to post those notifications. The delivery address is also passed to the external system during the subscription request. - - - ## EventUnsubscriber: remove subscription from the notifications list - The **Unsubscribe** operation removes a subscription from the notifications list. - - - - Figure 4 shows that the **UnSubscribe** method is much simpler. Because the subscription ID was sent back to SharePoint, and SharePoint recorded it, all that is needed is to send the UnSubscribe request with the correct subscription ID. - - - -**Figure 4 Code flow for UnSubscribe method** +Figure 4 shows that the **UnSubscribe** method is much simpler. Because the subscription ID was sent back to SharePoint, and SharePoint recorded it, all that is needed is to send the UnSubscribe request with the correct subscription ID. - - - +**Figure 4 Code flow for UnSubscribe method** - - - ![External notifications unsubscribe process](../images/ExternalEventsAndAlerts_UnsubscribeFlow.jpg) - - - ### BDC model for Unsubscribe The following XML example shows how you can create a BDC model that unsubscribes from the external system event notifications. - - - - -```XML +```xml @@ -540,7 +342,7 @@ The following XML example shows how you can create a BDC model that unsubscribes
- @@ -554,8 +356,6 @@ The following XML example shows how you can create a BDC model that unsubscribes
- - @@ -567,12 +367,12 @@ The following XML example shows how you can create a BDC model that unsubscribes - - None @@ -588,77 +388,46 @@ The following XML example shows how you can create a BDC model that unsubscribes - ``` - ## Code example: Attach an event receiver to an external list - The following code provides an example of how to attach an event receiver to an external list. After it is attached, the event receiver listens for notifications from the external system about updates, additions, and deletions that are performed on the native data. - - - - -```XML +```csharp private static void AddEventReceiver(string siteUrl, string listTitle) -{ - string assembly = "SampleEventReceiver, Culture=neutral, Version=1.0.0.0, - PublicKeyToken=1bfafa687d2e46a7"; - string className = "SampleEventReceiver.EntryContentEventReceiver"; - - try - { - using (SPSite site = new SPSite(siteUrl)) - { - using (SPWeb web = site.OpenWeb()) - { - SPList list = web.Lists[listTitle]; - list.EventReceivers.Add(SPEventReceiverType.ItemAdded, - assembly, className); - } +{ + string assembly = "SampleEventReceiver, Culture=neutral, Version=1.0.0.0,PublicKeyToken=1bfafa687d2e46a7"; + string className = "SampleEventReceiver.EntryContentEventReceiver"; + try + { + using (SPSite site = new SPSite(siteUrl)) + { + using (SPWeb web = site.OpenWeb()) + { + SPList list = web.Lists[listTitle]; + list.EventReceivers.Add(SPEventReceiverType.ItemAdded, assembly, className); } - } - catch (Exception e) - { - Console.WriteLine(e); - } + } + } + catch (Exception e) + { + Console.WriteLine(e); + } } - ``` - ## Beyond the basics: Learn more about using external event receivers - For more information about external events and alerts, see the following. - - - **Table 2. Advanced concepts for working with external event receivers** +| **Article** | **Description** | +| :----------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [How to: Create an OData data service for use as a BCS external system](how-to-create-an-odata-data-service-for-use-as-a-bcs-external-system.md) | Learn how to create an Internet-addressable Windows Communication Foundation (WCF) service that uses OData to send notifications to SharePoint when the underlying data changes. These notifications are used to tigger events that are attached to external lists. | -|**Article**|**Description**| -|:-----|:-----| -| [How to: Create an OData data service for use as a BCS external system](how-to-create-an-odata-data-service-for-use-as-a-bcs-external-system.md)
|Learn how to create an Internet-addressable Windows Communication Foundation (WCF) service that uses OData to send notifications to SharePoint when the underlying data changes. These notifications are used to trigger events that are attached to external lists.
| - - -## See also - - - -- [What's new in Business Connectivity Services in SharePoint](what-s-new-in-business-connectivity-services-in-sharepoint.md) - - -- [Business Connectivity Services in SharePoint](business-connectivity-services-in-sharepoint.md) - - -- [Business Connectivity Services programmers reference for SharePoint](business-connectivity-services-programmers-reference-for-sharepoint.md) - - -- [How to: Create external event receivers](how-to-create-external-event-receivers.md) - - +## See Also +- [What's new in Business Connectivity Services in SharePoint](what-s-new-in-business-connectivity-services-in-sharepoint.md) +- [Business Connectivity Services in SharePoint](business-connectivity-services-in-sharepoint.md) diff --git a/docs/general-development/fast-query-language-fql-syntax-reference.md b/docs/general-development/fast-query-language-fql-syntax-reference.md index 48df9d176..3a85d77d4 100644 --- a/docs/general-development/fast-query-language-fql-syntax-reference.md +++ b/docs/general-development/fast-query-language-fql-syntax-reference.md @@ -1,10 +1,9 @@ --- title: FAST Query Language (FQL) syntax reference description: Learn about constructing complex search queries for Search in SharePoint using the FAST Query Language (FQL). This reference describes the elements of an FQL query and how to use property specifications, token expressions, and operators in your FQL queries. -ms.date: 12/22/2020 -ms.prod: sharepoint +ms.date: 06/09/2022 ms.assetid: bd98a41b-623c-41d4-a15d-26c0d4ba4311 -localization_priority: Priority +ms.localizationpriority: high --- # FAST Query Language (FQL) syntax reference @@ -656,7 +655,7 @@ Use the **RANGE** operator for numeric and date/time managed properties. The ope #### Parameters -| Parameter | Value | Description | | +| Parameter | Value | Value | Description | | :-------- | :------------------ | :------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | _start_ | _\\ | \_ | Start value for the range. To specify that the range has no lower bound, use the reserved word **min**. | | _stop_ | _\\ | \_ | End value for the range. To specify that the range has no upper bound, use the reserved word **max**. | diff --git a/docs/general-development/follow-content-in-sharepoint.md b/docs/general-development/follow-content-in-sharepoint.md index 5abf78f05..13944f2dd 100644 --- a/docs/general-development/follow-content-in-sharepoint.md +++ b/docs/general-development/follow-content-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Follow content in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes the APIs for programmatically following content in SharePoint and provides lists of SharePoint APIs. +ms.date: 06/09/2022 ms.assetid: 30e68cd6-6e55-4cf9-afd6-7139b0a97288 -localization_priority: Normal +ms.localizationpriority: medium --- @@ -65,7 +65,7 @@ Table 1 shows the manager and other key objects (or REST resources) in the APIs **Table 1. SharePoint APIs used for following content programmatically** -|**API**|**Key objects**| +|API|Key objects| |:-----|:-----| |.NET client object model
See: [How to: Follow documents and sites by using the .NET client object model in SharePoint](how-to-follow-documents-and-sites-by-using-the-net-client-object-model-in-sharep.md)|Manager object: [SocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialFollowingManager.aspx)
Primary namespace: [Microsoft.SharePoint.Client.Social](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.aspx)
Other key objects: [SocialActor](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActor.aspx) , [SocialActorInfo](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActorInfo.aspx) , [SocialActorType](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActorType.aspx) , [SocialActorTypes](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActorTypes.aspx)
Class library: Microsoft.SharePoint.Client.UserProfiles.dll | |JavaScript object model|Manager object: [SocialFollowingManager](https://msdn.microsoft.com/library/9ee1c0c0-b864-f0c3-f0cb-4dd4f1870dfa%28Office.15%29.aspx)
Primary namespace: [SP.Social](https://msdn.microsoft.com/library/43d47f01-c085-0e77-bd01-48bcb7d5bb35%28Office.15%29.aspx)
Other key objects: [SocialActor](https://msdn.microsoft.com/library/4e369fd5-b9b0-9804-957e-b3e39c559cd4%28Office.15%29.aspx), [SocialActorInfo](https://msdn.microsoft.com/library/d940db32-1561-c868-bb66-0612e2031f17%28Office.15%29.aspx), [SocialActorType](https://msdn.microsoft.com/library/fbde74da-f292-dc87-0b7e-81bc5b7a880c%28Office.15%29.aspx), [SocialActorTypes](https://msdn.microsoft.com/library/a460c3e6-ed88-117d-6755-4c5803a154a0%28Office.15%29.aspx)
Class library: SP.UserProfiles.js | @@ -88,7 +88,7 @@ Table 2 shows common programming tasks for following content and the members tha **Table 2. API for common tasks for following content in SharePoint** -|**Task**|**Members**| +|Task|Members| |:-----|:-----| |Create an instance of a manager object in the context of the current user|CSOM: [SocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialFollowingManager.aspx)
JSOM: [SocialFollowingManager](https://msdn.microsoft.com/library/9ee1c0c0-b864-f0c3-f0cb-4dd4f1870dfa%28Office.15%29.aspx)
REST: `/_api/social.following`
SSOM: [SPSocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.Office.Server.Social.SPSocialFollowingManager.aspx)| |Create an instance of a manager object in the context of a specified user|CSOM: not implemented
JSOM: not implemented
REST: not implemented
SSOM: [SPSocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.Office.Server.Social.SPSocialFollowingManager.aspx) (overloaded)| diff --git a/docs/general-development/follow-people-in-sharepoint.md b/docs/general-development/follow-people-in-sharepoint.md index 878920949..fb74dd3c7 100644 --- a/docs/general-development/follow-people-in-sharepoint.md +++ b/docs/general-development/follow-people-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Follow people in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes the common programming tasks for following people in SharePoint and provides a list of APIs for programmatically following people. +ms.date: 06/09/2022 ms.assetid: 0fa2e235-63d0-41b1-9eed-4aeb2f59a14d -localization_priority: Normal +ms.localizationpriority: medium --- @@ -65,7 +65,7 @@ Table 1 shows the manager and other key objects (or REST resources) in the APIs **Table 1. SharePoint APIs used for following people programmatically** -|**API**|**Key objects**| +|API|Key objects| |:-----|:-----| |.NET client object model
See: [How to: Follow people by using the .NET client object model in SharePoint](how-to-follow-people-by-using-the-net-client-object-model-in-sharepoint.md)|Manager object: [SocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialFollowingManager.aspx)
Primary namespace: [Microsoft.SharePoint.Client.Social](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.aspx)
Other key objects: [SocialActor](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActor.aspx) , [SocialActorInfo](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActorInfo.aspx) , [SocialActorType](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActorType.aspx) , [SocialActorTypes](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialActorTypes.aspx)
Class library: Microsoft.SharePoint.Client.UserProfiles.dll | |JavaScript object model
See: [How to: Follow people by using the JavaScript object model in SharePoint](how-to-follow-people-by-using-the-javascript-object-model-in-sharepoint.md)|Manager object: [SocialFollowingManager](https://msdn.microsoft.com/library/9ee1c0c0-b864-f0c3-f0cb-4dd4f1870dfa%28Office.15%29.aspx)
Primary namespace: **SP.Social**
Other key objects: [SocialActor](https://msdn.microsoft.com/library/4e369fd5-b9b0-9804-957e-b3e39c559cd4%28Office.15%29.aspx), [SocialActorInfo](https://msdn.microsoft.com/library/d940db32-1561-c868-bb66-0612e2031f17%28Office.15%29.aspx), [SocialActorType](https://msdn.microsoft.com/library/fbde74da-f292-dc87-0b7e-81bc5b7a880c%28Office.15%29.aspx), [SocialActorTypes](https://msdn.microsoft.com/library/a460c3e6-ed88-117d-6755-4c5803a154a0%28Office.15%29.aspx)
Class library: SP.UserProfiles.js | @@ -92,7 +92,7 @@ The **SocialFollowingManager** object consolidates the core Following People and **Table 2. API for common tasks for following people by using the SocialFollowingManager object** -|**Task**|**Members**| +|Task|Members| |:-----|:-----| |Create an instance of a manager object in the context of the current user |CSOM: [SocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialFollowingManager.aspx)
JSOM: **SocialFollowingManager**
REST: `/_api/social.following`
SSOM: [SPSocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.Office.Server.Social.SPSocialFollowingManager.aspx)| |Create an instance of a manager object in the context of a particular user |CSOM: not implemented
JSOM: not implemented
REST: not implemented
SSOM: [SPSocialFollowingManager](https://msdn.microsoft.com/library/Microsoft.Office.Server.Social.SPSocialFollowingManager.aspx) (overloaded)| @@ -111,7 +111,7 @@ Table 3 shows the **PeopleManager** members that you can use for additional Foll **Table 3. API for common tasks for following people by using the PeopleManager object** -|**Task**|**Members**| +|Task|Members| |:-----|:-----| |Find out whether the **People I'm Following** list for the current user is public|CSOM: [IsMyPeopleListPublic](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.UserProfiles.PeopleManager.IsMyPeopleListPublic.aspx)
JSOM: [isMyPeopleListPublic](https://msdn.microsoft.com/library/2ffc73a5-24ce-1ed4-d850-a6fea4c773bb%28Office.15%29.aspx)
REST: [IsMyPeopleListPublic](https://msdn.microsoft.com/library/10757ed1-6e86-474f-89e0-6dec6aa66a2b%28Office.15%29.aspx#bk_PeopleManagerProperties)
Example: **GET** `/_api/SP.UserProfiles.PeopleManager/IsMyPeopleListPublic`
SSOM: [IsMyPeopleListPublic](https://msdn.microsoft.com/library/Microsoft.Office.Server.UserProfiles.PeopleManager.IsMyPeopleListPublic.aspx)| |Find out whether someone is following the current user |CSOM: [AmIFollowedBy](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.UserProfiles.PeopleManager.AmIFollowedBy.aspx)
JSOM: [amIFollowedBy](https://msdn.microsoft.com/library/3641c469-0063-054d-355d-e56697cb08ae%28Office.15%29.aspx)
REST: [AmIFollowedBy](https://msdn.microsoft.com/library/10757ed1-6e86-474f-89e0-6dec6aa66a2b%28Office.15%29.aspx#bk_PeopleManagerAmIFollowedBy)
Example: **GET** `/_api/SP.UserProfiles.PeopleManager/AmIFollowedBy(accountName=@v)?@v='domain\\user'`
SSOM: [AmIFollowedBy](https://msdn.microsoft.com/library/Microsoft.Office.Server.UserProfiles.PeopleManager.AmIFollowedBy.aspx)| diff --git a/docs/general-development/following-people-and-content-rest-api-reference-for-sharepoint.md b/docs/general-development/following-people-and-content-rest-api-reference-for-sharepoint.md index 9a3cf0d0f..e917934f3 100644 --- a/docs/general-development/following-people-and-content-rest-api-reference-for-sharepoint.md +++ b/docs/general-development/following-people-and-content-rest-api-reference-for-sharepoint.md @@ -1,9 +1,9 @@ --- title: Following people and content REST API reference for SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes finding SharePoint REST endpoints for following people and content by using the SocialRestFollowingManager and the PeopleManager resources. +ms.date: 06/09/2022 ms.assetid: c05755df-846d-4a39-941d-950d066cc6d4 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/frequently-asked-questions-about-excel-services-udfs.md b/docs/general-development/frequently-asked-questions-about-excel-services-udfs.md deleted file mode 100644 index 3f534adef..000000000 --- a/docs/general-development/frequently-asked-questions-about-excel-services-udfs.md +++ /dev/null @@ -1,255 +0,0 @@ ---- -title: Frequently Asked Questions About Excel Services UDFs -ms.date: 09/25/2017 -keywords: faqs -f1_keywords: -- faqs -ms.prod: sharepoint -ms.assetid: 3d94d040-eecf-4f8e-a316-6d1cca95e7eb -localization_priority: Normal ---- - - -# Frequently Asked Questions About Excel Services UDFs - -Here are some frequently asked questions about Excel Services user-defined functions (UDFs). - - - - - -## Creating Managed-Code UDFs - - -### What is a supported UDF class? - -The UDF class in a UDF assembly must be public. It can be sealed. It cannot be abstract, internal, or private. It must have a parameterless, public constructor. For languages that automatically generate a parameterless, public constructor (for example, C#), you can have no constructor at all. - - - - -### What is a supported UDF method? - -The UDF method in a UDF assembly must be public. The UDF method must be thread-safe. - - - -A UDF method cannot have: - - - - -- **ref** or **out** parameters - - -- **retval** attributes - - -- **Optional** arguments - - -- unsupported data types - - -The UDF method must also have a supported return type. For a list of supported data types, see the "Data Types" section of this topic. - - - - -### Can I call a Web service from a UDF assembly? - -Yes. For an example, see the following UDF sample code. Also see [How to: Create a UDF That Calls a Web Service](how-to-create-a-udf-that-calls-a-web-service.md). - - - - -```cs - -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.Office.Excel.Server.Udf; -using UdfWS.dk.iter.webservices; - -namespace UdfWS -{ - [UdfClass] - public class MyUdfClass - { - // Instantiate the Web service. The Web service used is at - // http://webservices.iter.dk/calculator.asmx - Calculator calc = new Calculator(); - - [UdfMethod] - public int MyFunction() - { - int i; - i = (i + 88) * 2; - return i; - } - - [UdfMethod(IsVolatile = true)] - public double MyDouble(double d) - { - return d * 9; - } - - [UdfMethod] - public int AddMe(int a, int b) - { - int c; - // Call the Web service Add method - c = calc.Add(a, b); - return c; - } - } -} -``` - - -```VB.net - -Imports System -Imports System.Collections.Generic -Imports System.Text -Imports Microsoft.Office.Excel.Server.Udf -Imports UdfWS.dk.iter.webservices - -Namespace UdfWS - _ - Public Class MyUdfClass - ' Instantiate the Web service. The Web service used is at - ' http://webservices.iter.dk/calculator.asmx - Private calc As New Calculator() - - _ - Public Function MyFunction() As Integer - Dim i As Integer - i = (i + 88) * 2 - Return i - End Function - - _ - Public Function MyDouble(ByVal d As Double) As Double - Return d * 9 - End Function - - _ - Public Function AddMe(ByVal a As Integer, ByVal b As Integer) As Integer - Dim c As Integer - ' Call the Web service Add method - c = calc.Add(a, b) - Return c - End Function - End Class -End Namespace -``` - - -## Data Types - - -### What are the data types that can be used as UDF parameters? - -The supported data types are as follows: - - - - -- Numeric types: Double, Single, Int32, UInt32, Int16, UInt16, Byte, Sbyte - - -- String - - -- Boolean - - -- Object arrays: one- or two- dimensional arrays, that is, object [] and object [,] - - -- DateTime - - - -### What are the supported return value types? - -The supported return value types are as follows: - - - - -- Numeric types: Double, Single, Int32, UInt32, Int16, UInt16, Byte, Sbyte - - -- String - - -- Boolean - - -- Object arrays: one- or two-dimensional arrays, that is, object [], object [,], int[] and int[,]) - - -- DateTime - - -- Object - - - -## XLLs - - -### Are XLLs supported? - -Not directly. Excel Services will load and call only managed-code UDFs. However, you can write a managed-code wrapper to call the XLLs and deploy the XLLs to the server, together with the managed-code wrapper assembly. - - - - -## See also - - -#### Tasks - - - - - - [How to: Create a UDF That Calls a Web Service](how-to-create-a-udf-that-calls-a-web-service.md) - - - - [How to: Trust a Location](how-to-trust-a-location.md) - - - - [How to: Catch Exceptions](how-to-catch-exceptions.md) -#### Concepts - - - - - - [Understanding Excel Services UDFs](understanding-excel-services-udfs.md) - - - - [Walkthrough: Developing a Managed-Code UDF](walkthrough-developing-a-managed-code-udf.md) - - - - [Excel Services Architecture](excel-services-architecture.md) - - - - [Excel Services Alerts](excel-services-alerts.md) - - - - [Excel Services Known Issues and Tips](excel-services-known-issues-and-tips.md) - - - - [Excel Services Best Practices](excel-services-best-practices.md) diff --git a/docs/general-development/frequently-asked-questions-about-excel-services-udfs.yml b/docs/general-development/frequently-asked-questions-about-excel-services-udfs.yml new file mode 100644 index 000000000..761eaac4a --- /dev/null +++ b/docs/general-development/frequently-asked-questions-about-excel-services-udfs.yml @@ -0,0 +1,200 @@ +### YamlMime:FAQ +metadata: + title: Frequently Asked Questions About Excel Services UDFs + description: Here are some frequently asked questions about Excel Services user-defined functions (UDFs). + ms.date: 09/25/2017 + keywords: faqs + f1_keywords: + - faqs + ms.assetid: 3d94d040-eecf-4f8e-a316-6d1cca95e7eb + ms.localizationpriority: medium + +title: Frequently Asked Questions About Excel Services UDFs +summary: | + Here are some frequently asked questions about Excel Services user-defined functions (UDFs). + +sections: + - name: Creating Managed-Code UDFs + questions: + - question: | + What is a supported UDF class? + answer: | + The UDF class in a UDF assembly must be public. It can be sealed. It cannot be abstract, internal, or private. It must have a parameterless, public constructor. For languages that automatically generate a parameterless, public constructor (for example, C#), you can have no constructor at all. + + - question: | + What is a supported UDF method? + answer: | + The UDF method in a UDF assembly must be public. The UDF method must be thread-safe. + + A UDF method cannot have: + + - **ref** or **out** parameters + + - **retval** attributes + + - **Optional** arguments + + - unsupported data types + + The UDF method must also have a supported return type. For a list of supported data types, see the "Data Types" section of this topic. + + - question: | + Can I call a Web service from a UDF assembly? + answer: | + Yes. For an example, see the following UDF sample code. Also see [How to: Create a UDF That Calls a Web Service](how-to-create-a-udf-that-calls-a-web-service.md). + + ```csharp + using System; + using System.Collections.Generic; + using System.Text; + using Microsoft.Office.Excel.Server.Udf; + using UdfWS.dk.iter.webservices; + + namespace UdfWS + { + [UdfClass] + public class MyUdfClass + { + // Instantiate the Web service. The Web service used is at + // http://webservices.iter.dk/calculator.asmx + Calculator calc = new Calculator(); + + [UdfMethod] + public int MyFunction() + { + int i; + i = (i + 88) * 2; + return i; + } + + [UdfMethod(IsVolatile = true)] + public double MyDouble(double d) + { + return d * 9; + } + + [UdfMethod] + public int AddMe(int a, int b) + { + int c; + // Call the Web service Add method + c = calc.Add(a, b); + return c; + } + } + } + ``` + + + ```VB.net + + Imports System + Imports System.Collections.Generic + Imports System.Text + Imports Microsoft.Office.Excel.Server.Udf + Imports UdfWS.dk.iter.webservices + + Namespace UdfWS + _ + Public Class MyUdfClass + ' Instantiate the Web service. The Web service used is at + ' http://webservices.iter.dk/calculator.asmx + Private calc As New Calculator() + + _ + Public Function MyFunction() As Integer + Dim i As Integer + i = (i + 88) * 2 + Return i + End Function + + _ + Public Function MyDouble(ByVal d As Double) As Double + Return d * 9 + End Function + + _ + Public Function AddMe(ByVal a As Integer, ByVal b As Integer) As Integer + Dim c As Integer + ' Call the Web service Add method + c = calc.Add(a, b) + Return c + End Function + End Class + End Namespace + ``` + + - name: Data Types + questions: + - question: | + What are the data types that can be used as UDF parameters? + answer: | + The supported data types are as follows: + + - Numeric types: Double, Single, Int32, UInt32, Int16, UInt16, Byte, Sbyte + + + - String + + + - Boolean + + + - Object arrays: one- or two- dimensional arrays, that is, object [] and object [,] + + + - DateTime + + - question: | + What are the supported return value types? + answer: | + The supported return value types are as follows: + + - Numeric types: Double, Single, Int32, UInt32, Int16, UInt16, Byte, Sbyte + + - String + + - Boolean + + - Object arrays: one- or two-dimensional arrays, that is, object [], object [,], int[] and int[,]) + + - DateTime + + - Object + + + + - name: XLLs + questions: + - question: | + Are XLLs supported? + answer: | + Not directly. Excel Services will load and call only managed-code UDFs. However, you can write a managed-code wrapper to call the XLLs and deploy the XLLs to the server, together with the managed-code wrapper assembly. + + +additionalContent: | + + ## See also + + #### Tasks + + [How to: Create a UDF That Calls a Web Service](how-to-create-a-udf-that-calls-a-web-service.md) + + [How to: Trust a Location](how-to-trust-a-location.md) + + [How to: Catch Exceptions](how-to-catch-exceptions.md) + + #### Concepts + + + [Understanding Excel Services UDFs](understanding-excel-services-udfs.md) + + [Walkthrough: Developing a Managed-Code UDF](walkthrough-developing-a-managed-code-udf.md) + + [Excel Services Architecture](excel-services-architecture.md) + + [Excel Services Alerts](excel-services-alerts.md) + + [Excel Services Known Issues and Tips](excel-services-known-issues-and-tips.md) + + [Excel Services Best Practices](excel-services-best-practices.md) \ No newline at end of file diff --git a/docs/general-development/general-guidelines.md b/docs/general-development/general-guidelines.md index a96824143..c08754b48 100644 --- a/docs/general-development/general-guidelines.md +++ b/docs/general-development/general-guidelines.md @@ -1,9 +1,9 @@ --- title: General Guidelines -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Provides general information related to Excel Services and provides links to articles and tutorials about Excel Services. +ms.date: 06/09/2022 ms.assetid: 437541f8-5cd9-46f4-92b6-3bf9d7e62f69 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/get-started-developing-with-social-features-in-sharepoint.md b/docs/general-development/get-started-developing-with-social-features-in-sharepoint.md index c590fcd2b..9431f614a 100644 --- a/docs/general-development/get-started-developing-with-social-features-in-sharepoint.md +++ b/docs/general-development/get-started-developing-with-social-features-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Get started developing with social features in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to get started with developing SharePoint social features and provides links to articles and tutorials. +ms.date: 06/09/2022 ms.assetid: 8852ce36-8309-45a7-a141-2e10ac17a123 -localization_priority: Normal +ms.localizationpriority: medium --- @@ -113,7 +113,7 @@ After you set up your development environment and choose your scenario, you can **Table 1. How-to articles for developing with social features** -|**Feature area**|**Description**| +|Feature area|Description| |:-----|:-----| | [How to: Learn to read and write to the social feed by using the .NET client object model in SharePoint](how-to-learn-to-read-and-write-to-the-social-feed-by-using-the-net-client-object.md)|Walk through detailed steps for creating an application that reads and writes to the social feed by using the .NET client object model.| | [How to: Learn to read and write to the social feed by using the REST service in SharePoint](how-to-learn-to-read-and-write-to-the-social-feed-by-using-the-rest-service-in-s.md)|Walk through detailed steps for creating an application that reads and writes to the social feed by using the REST service.| @@ -141,7 +141,7 @@ Although apps and solutions access SharePoint differently, after you do access S **Table 2. APIs for programming with social features** -|**API name**|**Source and path**| +|API name|Source and path| |:-----|:-----| | [.NET client object model](https://msdn.microsoft.com/library/9cc3f70c-78ac-4d2d-b46e-77522ee5d937%28Office.15%29.aspx)|Microsoft.SharePoint.Client.UserProfiles.dll
in %ProgramFiles%\\Common Files\\Microsoft Shared\\web server extensions\\15\\ISAPI| |Silverlight client object model|Microsoft.SharePoint.Client.UserProfiles.Silverlight.dll
in %ProgramFiles%\\Common Files\\Microsoft Shared\\web server extensions\\15\\TEMPLATE\\LAYOUTS\\ClientBin| @@ -172,7 +172,7 @@ App permission requests are scoped to the SharePoint deployment landscape. Table **Table 3. App permission scopes and available rights for social features in SharePoint** -|**Scope name**|**Description**|**Available rights**| +|Scope name|Description|Available rights| |:-----|:-----|:-----| |User Profiles
`http://sharepoint/social/tenant`|The permission request scope used to access all user profiles. Only the profile picture can be changed; all other user profile properties are read-only for SharePoint Add-ins. Must be installed by a tenant administrator.|Read, Write, Manage, FullControl| |Core
`http://sharepoint/social/core`|The permission request scope used to access the user's followed content and shared metadata that is used by microblogging features. This scope applies only to personal sites that support following content. If the app installs on any other type of site, use the Tenant scope.|Read, Write, Manage, FullControl| diff --git a/docs/general-development/get-started-using-the-client-object-model-with-external-data-in-sharepoint.md b/docs/general-development/get-started-using-the-client-object-model-with-external-data-in-sharepoint.md index e2584c33c..b6fe3360a 100644 --- a/docs/general-development/get-started-using-the-client-object-model-with-external-data-in-sharepoint.md +++ b/docs/general-development/get-started-using-the-client-object-model-with-external-data-in-sharepoint.md @@ -1,15 +1,14 @@ --- title: Get started using the client object model with external data in SharePoint +description: Learn how to use the SharePoint client object model to work with Business Connectivity Services (BCS) in SharePoint. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: 8ed91929-fdb6-4fde-ba2a-7942870575f3 -localization_priority: Normal +ms.localizationpriority: medium --- - - - # Get started using the client object model with external data in SharePoint + Learn how to use the SharePoint client object model to work with Business Connectivity Services (BCS) in SharePoint. + ## What is the SharePoint client object model? The client object model for SharePoint is a set of client-based libraries that represent the server object model. They are packaged in three different DLLs to accommodate a variety of development types. The client object model includes most of the major functions of the server API. This allows access to the same types of functionality from browser scripting and also .NET web applications and Silverlight applications.
To enhance and expand the capabilities for working with external data, Business Connectivity Services (BCS) has expanded the client object model to include additional functionality.
@@ -100,7 +99,7 @@ This example shows how to get context from SharePoint, and then retrieve a speci -```cs +```csharp ClientContext ctx = new ClientContext("http://sharepointservername"); Web web = ctx.Web; @@ -118,7 +117,7 @@ This example shows how to write a generic invoker so that you can create an enti -```cs +```csharp LobSystem lobSystem = entity.GetLobSystem(); ctx.Load(lobSystem); @@ -152,7 +151,7 @@ The following example shows how to retrieve a filtered, paged dataset. In this c -```cs +```csharp // Find filters for given Method Name. FilterCollection fCollection = entity.GetFilters("methodName"); @@ -177,7 +176,7 @@ The following example demonstrates how to return a filtered result set. In this -```cs +```csharp // Find filters for given Method Name. FilterCollection fCollection = entity.GetFilters("methodName"); diff --git a/docs/general-development/get-started-with-business-connectivity-services-in-sharepoint.md b/docs/general-development/get-started-with-business-connectivity-services-in-sharepoint.md index e1c4247ac..724782b63 100644 --- a/docs/general-development/get-started-with-business-connectivity-services-in-sharepoint.md +++ b/docs/general-development/get-started-with-business-connectivity-services-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Get started with Business Connectivity Services in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to get started with Business Connectivity Services in SharePoint and provides lists of core concepts and basic tasks. +ms.date: 06/09/2022 ms.assetid: c6bf3db0-db79-4b13-9834-891d24b2c9e5 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/get-started-with-workflows-in-sharepoint.md b/docs/general-development/get-started-with-workflows-in-sharepoint.md index ca1feac65..9a55786ce 100644 --- a/docs/general-development/get-started-with-workflows-in-sharepoint.md +++ b/docs/general-development/get-started-with-workflows-in-sharepoint.md @@ -1,12 +1,12 @@ --- title: Get started with workflows in SharePoint -ms.date: 09/25/2017 +description: Describes how to get started with workflows in SharePoint and provides steps for creating a workflow using Visual Studio. +ms.date: 06/09/2022 keywords: vs.sharepointtools.workflow4.workflowlist,VS.SharePointTools.Workflow4.WorkflowName f1_keywords: - vs.sharepointtools.workflow4.workflowlist,VS.SharePointTools.Workflow4.WorkflowName -ms.prod: sharepoint ms.assetid: a2643cd7-474d-4e4c-85bb-00f0b6685a1d -localization_priority: Priority +ms.localizationpriority: high --- @@ -16,6 +16,7 @@ Learn about the newly engineered Workflow Manager Client 1.0, which provides the > For instructions on setting up and configuring SharePoint and Microsoft Azure, see [Set up and configure SharePoint Workflow Manager](set-up-and-configure-sharepoint-workflow-manager.md). > [!NOTE] +> SharePoint 2013 workflow has been deprecated since April 2023 and will be turned off for new tenants as of April 2, 2024. It will be removed from existing tenants and will be fully retired as of April 2, 2026. If you’re using SharePoint 2013 workflow, we recommend migrating to Power Automate or other supported solutions. For more info, see [SharePoint 2013 workflow retirement in Microsoft 365](https://support.microsoft.com/office/4613d9cf-69aa-40f7-b6bf-6e7831c9691e). > SharePoint 2010 workflows have been retired since August 1, 2020 for new tenants and removed from existing tenants on November 1, 2020. If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions. For more info, see [SharePoint 2010 workflow retirement](https://support.microsoft.com/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f). diff --git a/docs/general-development/getting-familiar-with-visual-designer-for-workflow-in-sharepoint-designer.md b/docs/general-development/getting-familiar-with-visual-designer-for-workflow-in-sharepoint-designer.md index 757f85bc9..eb5bd2f49 100644 --- a/docs/general-development/getting-familiar-with-visual-designer-for-workflow-in-sharepoint-designer.md +++ b/docs/general-development/getting-familiar-with-visual-designer-for-workflow-in-sharepoint-designer.md @@ -1,9 +1,9 @@ --- title: Getting familiar with Visual Designer for workflow in SharePoint Designer 2013 -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes the basic features of the Visual Designer in SharePoint Designer 2013 and provides guidance for using the Visual Designer in SharePoint. +ms.date: 06/09/2022 ms.assetid: ff9b0314-eea1-47e4-87c7-53ed4de98c30 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/getting-ranges-using-atom-feed-and-html-fragment.md b/docs/general-development/getting-ranges-using-atom-feed-and-html-fragment.md index e1e168419..138b17b3f 100644 --- a/docs/general-development/getting-ranges-using-atom-feed-and-html-fragment.md +++ b/docs/general-development/getting-ranges-using-atom-feed-and-html-fragment.md @@ -1,9 +1,9 @@ --- title: Getting Ranges Using Atom Feed and HTML Fragment -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes the Atom feed method and the HTML fragment method to access ranges by using the REST API in Excel Services. +ms.date: 06/09/2022 ms.assetid: 45d4ef08-02d6-48dd-b0ef-a748db1a0c6a -localization_priority: Normal +ms.localizationpriority: medium --- @@ -48,7 +48,7 @@ Therefore, for a workbook with the file name **sampleWorkbook.xlsx** that is sav http:///_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model ``` -Using the discovery mechanism described in [Discovery in Excel Services REST API](discovery-in-excel-services-rest-api.md), if you click on the **Ranges** Atom feed on the model page on the server, ( `http://` __ `/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model`), it displays a page that shows all the named ranges in the workbook. The sampleWorkbook.xlsx contains one named range, **SampleNamedRange**, as shown in the following screen shot: +Using the discovery mechanism described in [Discovery in Excel Services REST API](discovery-in-excel-services-rest-api.md), if you click on the **Ranges** Atom feed on the model page on the server, ( `http://` _\_ `/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model`), it displays a page that shows all the named ranges in the workbook. The sampleWorkbook.xlsx contains one named range, **SampleNamedRange**, as shown in the following screen shot: @@ -184,19 +184,19 @@ The feed item contains XML that represents the data inside the range. Following -- **** The range element. Represents the container of the returned range. +- **\** The range element. Represents the container of the returned range. -- **** The row element. Represents each row in the range. +- **\** The row element. Represents each row in the range. -- **** The cell element. Represents each cell in a row. +- **\** The cell element. Represents each cell in a row. -- **** The formatted value element. Represents the value as it is formatted by Excel. If the value is of type string in the workbook, the formatted value element is the only element under ****. +- **\** The formatted value element. Represents the value as it is formatted by Excel. If the value is of type string in the workbook, the formatted value element is the only element under **\**. -- **** The value element. Represents a number value. If the value in the cell is a number instead of a string, the value element contains that information. +- **\** The value element. Represents a number value. If the value in the cell is a number instead of a string, the value element contains that information. Using XML gives you an easier way to get data out of an Excel range so that you can use it in your application. diff --git a/docs/general-development/getting-started-with-excel-services.md b/docs/general-development/getting-started-with-excel-services.md index 6ae8ae47a..cc622475f 100644 --- a/docs/general-development/getting-started-with-excel-services.md +++ b/docs/general-development/getting-started-with-excel-services.md @@ -1,9 +1,9 @@ --- title: Getting Started with Excel Services -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Provides an overview of Excel Services and its architecture, and provides links to Excel Service articles and reference topics. +ms.date: 06/09/2022 ms.assetid: 392e4734-5ca0-4647-8f6d-e671daa45a4d -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/how-to-access-an-external-data-source-from-a-udf.md b/docs/general-development/how-to-access-an-external-data-source-from-a-udf.md index a6d3067b0..93dfbf263 100644 --- a/docs/general-development/how-to-access-an-external-data-source-from-a-udf.md +++ b/docs/general-development/how-to-access-an-external-data-source-from-a-udf.md @@ -1,12 +1,12 @@ --- title: Access an external data source from a UDF +description: This example shows how to access an external database from a user-defined function (UDF). ms.date: 09/25/2017 keywords: how to,howdoi,howto,UDF f1_keywords: - how to,howdoi,howto,UDF -ms.prod: sharepoint ms.assetid: 7a1876da-aeb5-4017-8eb6-3fed47912f70 -localization_priority: Normal +ms.localizationpriority: medium --- @@ -21,7 +21,7 @@ This example shows how to access an external database from a user-defined functi ## Example -```cs +```csharp using System; using System.Collections.Generic; @@ -185,7 +185,7 @@ End Namespace - [Frequently Asked Questions About Excel Services UDFs](frequently-asked-questions-about-excel-services-udfs.md) + [Frequently Asked Questions About Excel Services UDFs](frequently-asked-questions-about-excel-services-udfs.yml) diff --git a/docs/general-development/how-to-access-external-data-with-rest-in-sharepoint.md b/docs/general-development/how-to-access-external-data-with-rest-in-sharepoint.md index dda4d9fbd..5d9087c9d 100644 --- a/docs/general-development/how-to-access-external-data-with-rest-in-sharepoint.md +++ b/docs/general-development/how-to-access-external-data-with-rest-in-sharepoint.md @@ -1,193 +1,130 @@ --- title: Access external data by using REST in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to access external data from SharePoint by using REST URLs for BCS and provides an example that sets up an external list. +ms.date: 05/18/2023 ms.assetid: 0663cc8c-a736-434d-9858-6ce12ce7f748 -localization_priority: Priority +ms.localizationpriority: high --- - - # Access external data by using REST in SharePoint Learn how to access external data from SharePoint by using Representational State Transfer (REST) URLs for Business Connectivity Services (BCS). This article shows how to set up an external list that retrieves data from an Open Data protocol (OData) source. - - - - ## Prerequisites for accessing external data using REST - To access external data from SharePoint by using REST, you need the following: - - - - SharePoint - - - Visual Studio 2012 - - - Office Developer Tools for Visual Studio 2012 - - - A functioning SharePoint Add-ins development environment: Follow the instructions in [Set up a general development environment for SharePoint](set-up-a-general-development-environment-for-sharepoint.md). - - - Access to the public OData.org producers - - ### Core concepts to know when accessing external data with REST The SharePoint REST service provides a way to access external data using a specially constructed URL. To understand how it works and how to use it, see the following articles. - - - **Table 1. Core concepts for REST in SharePoint** - -|**Article title**|**Description**| -|:-----|:-----| -| [Use OData query operations in SharePoint REST requests](https://msdn.microsoft.com/library/d4b5c277-ed50-420c-8a9b-860342284b72%28Office.15%29.aspx)
|Learn how to use the SharePoint REST service, which provides a REST programming interface comparable to the existing client object model.
| -| [Get to know the SharePoint REST service](https://msdn.microsoft.com/library/2de035a0-ac75-43bd-9665-5c5a59c4c590%28Office.15%29.aspx)
|Get the basics of using the SharePoint REST service to access and update SharePoint data, using the REST and OData web protocol standards.
| -| [Complete basic operations using SharePoint REST endpoints](https://docs.microsoft.com/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints)
|Learn how to navigate the SharePoint data structure as it is represented in the REST service, perform common CRUD (create, read, update, and delete) operations on SharePoint items via the REST service, synchronize SharePoint items across applications, and control item concurrency.
| - +| **Article title** | **Description** | +| :---------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Use OData query operations in SharePoint REST requests](https://msdn.microsoft.com/library/d4b5c277-ed50-420c-8a9b-860342284b72%28Office.15%29.aspx) | Learn how to use the SharePoint REST service, which provides a REST programming interface comparable to the existing client object model. | +| [Get to know the SharePoint REST service](https://msdn.microsoft.com/library/2de035a0-ac75-43bd-9665-5c5a59c4c590%28Office.15%29.aspx) | Get the basics of using the SharePoint REST service to access and update SharePoint data, using the REST and OData web protocol standards. | +| [Complete basic operations using SharePoint REST endpoints](/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints) | Learn how to navigate the SharePoint data structure as it is represented in the REST service, perform common CRUD (create, read, update, and delete) operations on SharePoint items via the REST service, synchronize SharePoint items across applications, and control item concurrency. | ## Create an SharePoint Add-in to access external data using REST - The following procedures guide you through setting up an SharePoint Add-in and configuring a webpage to make requests using REST functions to retrieve data from an external data source. - - - ### To create an SharePoint Add-in - 1. Open Visual Studio 2012 or later. - - -2. Create an **App for SharePoint** project. - - -3. Specify the app settings, including app name, the site URL for debugging the app, and how you want to host the app (Autohosted, Provider-hosted, SharePoint-hosted). For more information about hosting options, see [Choose patterns for developing and hosting your SharePoint Add-in](https://msdn.microsoft.com/library/05ce5435-0a03-4ddc-976b-c33b08d03457%28Office.15%29.aspx). - - -4. Choose **Finish** to create the app. - - +1. Create an **App for SharePoint** project. +1. Specify the app settings, including app name, the site URL for debugging the app, and how you want to host the app (Autohosted, Provider-hosted, SharePoint-hosted). For more information about hosting options, see [Choose patterns for developing and hosting your SharePoint Add-in](https://msdn.microsoft.com/library/05ce5435-0a03-4ddc-976b-c33b08d03457%28Office.15%29.aspx). +1. Choose **Finish** to create the app. ### To generate the external content type - 1. In **Solution Explorer**, open the shortcut menu for the project, and choose **Add**, **Content Types for External Data Source**. - - -2. In the **Specify OData Source** page, enter the URL of the OData service you want to connect to. In this case, use the Northwind OData source published at [http://www.odata.org/ecosystem](http://www.odata.org/ecosystem). Set the URL for the OData service to `http://services.odata.org/Northwind/Northwind.svc/`, and provide a name for the data source. - +1. In the **Specify OData Source** page, enter the URL of the OData service you want to connect to. In this case, use the Northwind OData source published at [https://www.odata.org/ecosystem](https://www.odata.org/ecosystem). Set the URL for the OData service to `http://services.odata.org/Northwind/Northwind.svc/`, and provide a name for the data source. + Choose **Next**. - - -3. This displays a list of data entities that are being exposed by the OData Service. Select the **Customers** entity. Ensure that the **Create list instances for the selected data entities (except Service Operations)** check box is selected. - - -4. Choose **Finish**. - - + +1. This displays a list of data entities that are being exposed by the OData Service. Select the **Customers** entity. Ensure that the **Create list instances for the selected data entities (except Service Operations)** check box is selected. +1. Choose **Finish**. ## Code example: Add scripts and HTML to the Home.aspx page - -At this point, you have an external content type and an external list that will display the data from the Northwind OData source. - - - +At this point, you have an external content type and an external list that will display the data from the Northwind OData source. + The next objective is to modify the default.aspx page that was created when you created your app. You will add a container to hold the results of the query that is executed with the page loads. By executing the scripts on the page load event, you ensure that the script is executed every time the page is browsed, and the resulting REST calls are made to the Northwind OData source to add records to the page. - - - ### To add the container to the Default.aspx page - 1. In **Solution Explorer**, open the Default.aspx page in the **Pages** module. - - -2. Add the following **div** element to the page. - -```HTML - -
-``` +1. Add the following **div** element to the page. + + ```html +
+ ``` + +1. Save the page. -3. Save the page. - - Finally, you add code to the App.js file that executes when the page loads. - - - ### To modify the App.js file to make REST calls +1. Open the **App.js** file in the Scripts module of your SharePoint project. +1. Paste the following code at the end of the file. -1. Open the App.js file in the Scripts module of your SharePoint project. - - -2. Paste the following code at the end of the file. - -``` - $(document).ready(function () { +```javascript +$(document).ready(function () { - // Namespace - window.AppLevelECT = window.AppLevelECT || {}; + // Namespace + window.AppLevelECT = window.AppLevelECT || {}; - // Constructor - AppLevelECT.Grid = function (hostElement, surlWeb) { - this.hostElement = hostElement; - if (surlWeb.length > 0 && surlWeb.substring(surlWeb.length - 1, surlWeb.length) != "/") - surlWeb += "/"; - this.surlWeb = surlWeb; - } + // Constructor + AppLevelECT.Grid = function (hostElement, surlWeb) { + this.hostElement = hostElement; + if (surlWeb.length > 0 && surlWeb.substring(surlWeb.length - 1, surlWeb.length) != "/") + surlWeb += "/"; + this.surlWeb = surlWeb; + } - // Prototype - AppLevelECT.Grid.prototype = { + // Prototype + AppLevelECT.Grid.prototype = { - init: function () { + init: function () { - $.ajax({ - url: this.surlWeb + "_api/lists/getbytitle('Customer')/items?$select=BdcIdentity,CustomerID,ContactName", - headers: { - "accept": "application/json", - "X-RequestDigest": $("#__REQUESTDIGEST").val() - }, - success: this.showItems - }); - }, + $.ajax({ + url: this.surlWeb + "_api/lists/getbytitle('Customer')/items?$select=BdcIdentity,CustomerID,ContactName", + headers: { + "accept": "application/json", + "X-RequestDigest": $("#__REQUESTDIGEST").val() + }, + success: this.showItems + }); + }, - showItems: function (data) { - var items = []; + showItems: function (data) { + var items = []; - items.push(""); - items.push(''); + items.push("
Customer IDCustomer Name
"); + items.push(''); - $.each(data.d.results, function (key, val) { - items.push(''); - }); + $.each(data.d.results, function (key, val) { + items.push(''); + }); - items.push("
Customer IDCustomer Name
' + - val.CustomerID + '' + - val.ContactName + '
' + + val.CustomerID + '' + + val.ContactName + '
"); + items.push(""); - $("#displayDiv").html(items.join('')); - } - } + $("#displayDiv").html(items.join('')); + } + } - ExecuteOrDelayUntilScriptLoaded(getCustomers, "sp.js"); + ExecuteOrDelayUntilScriptLoaded(getCustomers, "sp.js"); }); function getCustomers() { @@ -197,28 +134,11 @@ function getCustomers() { ``` Press F5 to deploy the app to SharePoint. Browse to the Default.aspx page in the app, and a list of customers appears on the page. - - - ## See also - - - -- [Business Connectivity Services in SharePoint](business-connectivity-services-in-sharepoint.md) - - -- [Get to know the SharePoint REST service](https://msdn.microsoft.com/library/2de035a0-ac75-43bd-9665-5c5a59c4c590%28Office.15%29.aspx) - - -- [Complete basic operations using SharePoint REST endpoints](https://docs.microsoft.com/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints) - - -- [Add-in-scoped external content types in SharePoint](add-in-scoped-external-content-types-in-sharepoint.md) - - -- [What's new in Business Connectivity Services in SharePoint](what-s-new-in-business-connectivity-services-in-sharepoint.md) - - - +- [Business Connectivity Services in SharePoint](business-connectivity-services-in-sharepoint.md) +- [Get to know the SharePoint REST service](https://msdn.microsoft.com/library/2de035a0-ac75-43bd-9665-5c5a59c4c590%28Office.15%29.aspx) +- [Complete basic operations using SharePoint REST endpoints](/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints) +- [Add-in-scoped external content types in SharePoint](add-in-scoped-external-content-types-in-sharepoint.md) +- [What's new in Business Connectivity Services in SharePoint](what-s-new-in-business-connectivity-services-in-sharepoint.md) diff --git a/docs/general-development/how-to-add-a-device-channel-panel-snippet-in-sharepoint.md b/docs/general-development/how-to-add-a-device-channel-panel-snippet-in-sharepoint.md index 164b254e0..6d119f6d0 100644 --- a/docs/general-development/how-to-add-a-device-channel-panel-snippet-in-sharepoint.md +++ b/docs/general-development/how-to-add-a-device-channel-panel-snippet-in-sharepoint.md @@ -1,156 +1,92 @@ --- title: Add a Device Channel Panel snippet in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to add a Device Channel Panel that can be added to a master page or page layout to control how content is rendered in created channels. +ms.date: 05/18/2023 ms.assetid: 612780a8-6267-49f6-a32d-33600bb5f6b4 -localization_priority: Normal +ms.localizationpriority: medium --- - # Add a Device Channel Panel snippet in SharePoint A Device Channel Panel is a snippet that you can add to a master page or page layout to control what content is rendered for each channel that you create. The primary purpose of a Device Channel Panel is to selectively display different page fields on different channels from a single page layout. ## Introduction to the Device Channel Panel snippet - A Device Channel Panel is a control that you can add to a master page or page layout to control what content is rendered in each channel that you create. A Device Channel Panel is a container that specifies one or more channels; if one or more of those channels are active when the page is rendered, all of the contents of the Device Channel Panel are also rendered. A Device Channel Panel can include almost any type of content, including a link to a CSS file or a .js file. It is an easy way to include specific content for specific channels. - - - + Perhaps the most common scenario for using Device Channel Panels is to selectively include parts of a page layout for specific channels. For example, you may have a page layout with separate text fields for a long greeting and a short greeting. By placing the page fields inside Device Channel Panels, you can display the short greeting only to phones and the long greeting only to the desktop. The content of a Device Channel Panel is not displayed on non-included channels—in fact, the content is not rendered at all, which prevents bytes from going across the wire. For this reason, using Device Channel Panels is a better way to display content on specific channels than using a CSS class with `Display:None` because Device Channel Panels help to reduce the page weight for a specific channel. - - - + You can also use Device Channel Panels on master pages. For example, if you have a master page that can accommodate two different devices (or two different browsers) with only minimal changes, you can use Device Channel Panels to hold the content on the master page that is specific to either of those devices. - - - + There are two limitations to using a Device Channel Panel: - - - - **Display templates** Because display templates are rendered on the client side and Device Channel Panels run on the server side, you cannot use a Device Channel Panel within a display template. Instead, you should use two different Content Search web parts within Device Channel Panels on your page layout, or use the JavaScript variable to trigger the behavior you want within the display template itself. - - - **Web part zones** You cannot insert a web part zone inside a Device Channel Panel. If you want to allow authors to add web parts to a page, and if you are not concerned about the page weight for mobile devices, you can add a Rich Text Editor page field to a Device Channel Panel, and then instruct authors to add web parts there. You can add web parts directly to a Device Channel Panel (without a web part zone). - - ## Inserting a Device Channel Panel snippet - Like all snippets, you add a Device Channel Panel snippet from the Snippet Gallery. To navigate to the Snippet Gallery, you must first select a master page or page layout to edit. - - - - ### To insert a Device Channel Panel snippet - 1. Browse to your publishing site. - - -2. In the upper-right corner of the page, choose the Settings gear, and then choose **Design Manager**. - - -3. In Design Manager, in the left navigation pane, choose **Edit Master Pages** or **Edit Page Layouts**, depending on what type of file you're editing. - - -4. Select the name of the master page or page layout that you want to add the snippet to. - - -5. To open the Snippet Gallery, choose **Snippets** in the upper-right corner of the server-side preview. - - -6. On the ribbon, on the **Design** tab, choose **Device Channel Panel**. - - -7. On the right side of the Snippet Gallery, under **About this Component**, click or select section headers to expand or collapse groups of properties, and then configure any custom settings that you want. - +1. In the upper-right corner of the page, choose the Settings gear, and then choose **Design Manager**. +1. In Design Manager, in the left navigation pane, choose **Edit Master Pages** or **Edit Page Layouts**, depending on what type of file you're editing. +1. Select the name of the master page or page layout that you want to add the snippet to. +1. To open the Snippet Gallery, choose **Snippets** in the upper-right corner of the server-side preview. +1. On the ribbon, on the **Design** tab, choose **Device Channel Panel**. +1. On the right side of the Snippet Gallery, under **About this Component**, click or select section headers to expand or collapse groups of properties, and then configure any custom settings that you want. + The section named **Important** contains the properties that are key to how this particular snippet works. For a Device Channel Panel, the **IncludedChannels** property is the most important. For this property, enter the alias of each Device Channel that you want to display the content contained in this Device Channel Panel. If you enter more than one alias, separate each with a comma. - + > [!NOTE] > If you edit the alias of a channel in the Device Channels list, you must manually find and update that alias wherever it appears in your design files, including updating the **IncludedChannels** property for every Device Channel Panel that uses that alias. -8. After you configure any other properties, choose **Update**. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always choose **Reset** to return all properties to their default settings. - - -9. On the left side of the Snippet Gallery, under **HTML Snippet**, choose **Copy to Clipboard**. - - -10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to. - +1. After you configure any other properties, choose **Update**. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always choose **Reset** to return all properties to their default settings. +1. On the left side of the Snippet Gallery, under **HTML Snippet**, choose **Copy to Clipboard**. +1. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to. + For more information, see [How to: Map a network drive to the SharePoint Master Page Gallery](how-to-map-a-network-drive-to-the-sharepoint-master-page-gallery.md). - - -11. In the HTML file, paste the snippet where you want the markup to appear. - + +1. In the HTML file, paste the snippet where you want the markup to appear. + If you are adding the snippet to a page layout, make sure to paste the snippet inside **PlaceHolderMain**. - - -12. Replace the **
** where `class="DefaultContentBlock"` with your own specific content. - - Typically, if you're adding a Device Channel Panel to a page layout, you replace the **
** by copying page fields inside the panel. - - -13. Save the page, and then refresh the server-side preview in Design Manager to make sure the Device Channel Panel appears as expected. - + +1. Replace the `
` where `class="DefaultContentBlock"` with your own specific content. + + Typically, if you're adding a Device Channel Panel to a page layout, you replace the `
` by copying page fields inside the panel. + +1. Save the page, and then refresh the server-side preview in Design Manager to make sure the Device Channel Panel appears as expected. + To preview the panel on different channels, you can add query string parameters to the URL. For example, you can append the query string variable `"DeviceChannel=YourChannelAlias"` to the URL of any page in the server-side preview. - - ## Understanding the snippet markup - -The two most important parts of a Device Channel Panel snippet are the **IncludedChannels** property and the **
** where `class="DefaultContentBlock"`. By default, the **IncludedChannels** property is empty. In the **Important** section of the property grid, you should enter the aliases, separated by commas, of the device channels that you want to display the content in this panel. - +The two most important parts of a Device Channel Panel snippet are the **IncludedChannels** property and the `
` where `class="DefaultContentBlock"`. By default, the **IncludedChannels** property is empty. In the **Important** section of the property grid, you should enter the aliases, separated by commas, of the device channels that you want to display the content in this panel. + > [!NOTE] > If you change an alias in the Device Channels list, you must also change that alias wherever it appears in your markup, including in the **IncludedChannels** property for every Device Channel Panel that uses that alias. - - - - -The **
** where `class="DefaultContentBlock"` should be replaced with whatever specific content you want to display for the included channels. A Device Channel Panel can include almost any type of content, including a link to a CSS file or a .js file. The most common scenario for using Device Channel Panels is to include specific page fields from a page layout for specific channels. In this case, you copy the page field markup where the **
** is positioned inside the Device Channel Panel. - - - +The `
` where `class="DefaultContentBlock"` should be replaced with whatever specific content you want to display for the included channels. A Device Channel Panel can include almost any type of content, including a link to a CSS file or a .js file. The most common scenario for using Device Channel Panels is to include specific page fields from a page layout for specific channels. In this case, you copy the page field markup where the `
` is positioned inside the Device Channel Panel. ```HTML -
- You should replace this div with content that renders based on your Device Channel Panel Properties. + You should replace this div with content that renders based on your Device Channel Panel Properties.
- ``` - ## See also - - - -- [SharePoint Design Manager snippets](sharepoint-design-manager-snippets.md) - - -- [SharePoint Design Manager device channels](sharepoint-design-manager-device-channels.md) - - -- [Build sites for SharePoint](build-sites-for-sharepoint.md) - - -- [Develop the site design in SharePoint](develop-the-site-design-in-sharepoint.md) - - +- [SharePoint Design Manager snippets](sharepoint-design-manager-snippets.md) +- [SharePoint Design Manager device channels](sharepoint-design-manager-device-channels.md) +- [Build sites for SharePoint](build-sites-for-sharepoint.md) +- [Develop the site design in SharePoint](develop-the-site-design-in-sharepoint.md) diff --git a/docs/general-development/how-to-add-a-geolocation-column-to-a-list-programmatically-in-sharepoint.md b/docs/general-development/how-to-add-a-geolocation-column-to-a-list-programmatically-in-sharepoint.md index 2d1fec003..29d293584 100644 --- a/docs/general-development/how-to-add-a-geolocation-column-to-a-list-programmatically-in-sharepoint.md +++ b/docs/general-development/how-to-add-a-geolocation-column-to-a-list-programmatically-in-sharepoint.md @@ -1,218 +1,160 @@ --- title: Add a Geolocation column to a list programmatically in SharePoint description: Learn how to programmatically add a Geolocation column to a list in SharePoint. Integrate location information and maps in SharePoint lists and location-based websites by using the new Geolocation field creating your own Geolocation-based field type. -ms.date: 02/17/2021 -ms.prod: sharepoint +ms.date: 01/06/2023 ms.assetid: f31a3594-c328-4731-b8eb-5da6b85103ad -localization_priority: Priority +ms.localizationpriority: high --- # Add a Geolocation column to a list programmatically in SharePoint Learn how to programmatically add a Geolocation column to a list in SharePoint. Integrate location information and maps in SharePoint lists and location-based websites by using the new Geolocation field creating your own Geolocation-based field type. -SharePoint introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location information. In columns of type Geolocation, you can enter location information as a pair of latitude and longitude coordinates in decimal degrees or retrieve the coordinates of the user's current location from the browser if it implements the W3C Geolocation API. For more information about the Geolocation column, see [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md). The Geolocation column is not available by default in SharePoint lists. To add the column to a SharePoint list, you have to write code. In this article, learn how to add the Geolocation field to a list programmatically by using the SharePoint client object model. - - - +SharePoint introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location information. In columns of type Geolocation, you can enter location information as a pair of latitude and longitude coordinates in decimal degrees or retrieve the coordinates of the user's current location from the browser if it implements the W3C Geolocation API. For more information about the Geolocation column, see [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md). The Geolocation column isn't available by default in SharePoint lists. To add the column to a SharePoint list, you have to write code. In this article, learn how to add the Geolocation field to a list programmatically by using the SharePoint client object model. + +An MSI package named SQLSysClrTypes.msi must be installed on every SharePoint front-end web server to view the geolocation field value or data in a list. This package installs components that implement the new geometry, geography, and hierarchy ID types in SQL Server 2008. By default, this file is installed for SharePoint Online. However, it isn't for an on-premises deployment of SharePoint. You must be a member of the Farm Administrators group to perform this operation. To download SQLSysClrTypes.msi, see [Microsoft SQL Server 2008 R2 SP1 Feature Pack](https://www.microsoft.com/download/details.aspx?id=30437) for SQL Server 2008, or [Microsoft SQL Server 2012 Feature Pack](https://www.microsoft.com/download/details.aspx?id=29065)for SQL Server 2012 in the Microsoft Download Center. -An MSI package named SQLSysClrTypes.msi must be installed on every SharePoint front-end web server to view the geolocation field value or data in a list. This package installs components that implement the new geometry, geography, and hierarchy ID types in SQL Server 2008. By default, this file is installed for SharePoint Online. However, it is not for an on-premises deployment of SharePoint. You must be a member of the Farm Administrators group to perform this operation. To download SQLSysClrTypes.msi, see [Microsoft SQL Server 2008 R2 SP1 Feature Pack](https://www.microsoft.com/download/details.aspx?id=26728) for SQL Server 2008, or [Microsoft SQL Server 2012 Feature Pack](https://www.microsoft.com/download/details.aspx?id=29065)for SQL Server 2012 in the Microsoft Download Center. ## Prerequisites for adding a Geolocation column - +- Access to a SharePoint list, with sufficient privileges to add a column. +- A valid Bing Maps key set at the farm or web level, which can be obtained from the [Bing Maps Account Center](https://www.bingmapsportal.com/). + + > [!IMPORTANT] + > Please note that you are responsible for compliance with terms and conditions applicable to your use of the Bing Maps key, and any necessary disclosures to users of your application regarding data passed to the Bing Maps service. - - - +- Visual Studio 2010 +- SharePoint Online Management Shell: https://www.microsoft.com/download/details.aspx?id=35588 +- SharePoint PnP-PowerShell (legacy): https://github.com/SharePoint/PnP-PowerShell/ +- SharePoint PnP.PowerShell (latest): https://github.com/pnp/powershell -- Access to a SharePoint list, with sufficient privileges to add a column. - - -- A valid Bing Maps key set at the farm or web level, which can be obtained from the [Bing Maps Account Center](https://www.bingmapsportal.com/). - - > **Important:** - > Please note that you are responsible for compliance with terms and conditions applicable to your use of the Bing Maps key, and any necessary disclosures to users of your application regarding data passed to the Bing Maps service. -- Visual Studio 2010. -- SharePoint Online Management Shell - https://www.microsoft.com/download/details.aspx?id=35588 -- SharePoint PnP-PowerShell (legacy) - https://github.com/SharePoint/PnP-PowerShell/ -- SharePoint PnP.PowerShell (latest) - https://github.com/pnp/powershell - [!INCLUDE [pnp-powershell](../../includes/snippets/open-source/pnp-powershell.md)] ## Code example: Add a Geolocation column to an existing list programmatically - Follow these steps to add the Geolocation column to a list. This must be done programmatically with CSOM or PowerShell - + ### To add the Geolocation column to a list using PnP PowerShell -1. Open the SharePoint Online Management Shell -2. Connect to the site you wish to add the column to -```cs -Connect-PnPOnline -url "https://TENANT.sharepoint.com/sites/SITEURL" -``` -3. Open the list you wish to add the column to -```cs -$list = Get-PnPList -Identity "LISTNAME" -``` -4. #Add the Geolocation field - Change parameters as necessary -```cs -Add-PnPField -List $list -Type GeoLocation -DisplayName "GeoLocationField" -InternalName "GeoLocationField" -AddToDefaultView -Required -``` - - - -### To add the Geolocation column to a list using the client object model in Visual Studio +1. Open PowerShell +1. Connect to the site you wish to add the column to + + ```powershell + Connect-PnPOnline -url "https://TENANT.sharepoint.com/sites/SITEURL" + ``` +1. Open the list you wish to add the column to + + ```powershell + $list = Get-PnPList -Identity "LISTNAME" + ``` + +1. #Add the Geolocation field - Change parameters as necessary + + ```powershell + Add-PnPField -List $list -Type GeoLocation -DisplayName "GeoLocationField" -InternalName "GeoLocationField" -AddToDefaultView -Required + ``` + +### To add the Geolocation column to a list using the client object model in Visual Studio 1. Start Visual Studio. - - -2. On the menu bar, choose **File, New Project**. The **New Project** dialog box opens. - - -3. In the **New Project** dialog box, choose **C#** in the **Installed Templates** box, and then choose the **Console Application** template. - - -4. Give the project a name, and then choose the **OK** button. - - -5. Visual Studio creates the project. Add a reference to the following assemblies, and choose **OK**. - - Microsoft.SharePoint.Client.dll - - Microsoft.SharePoint.Client.Runtime.dll - - -6. In the default .cs file, add a **using** directive as follows. - - `using Microsoft.SharePoint.Client;` - - -7. Add the following code to the **Main** method in the .cs file. - -```cs - -class Program +1. On the menu bar, choose **File, New Project**. The **New Project** dialog box opens. +1. In the **New Project** dialog box, choose **C#** in the **Installed Templates** box, and then choose the **Console Application** template. +1. Give the project a name, and then choose the **OK** button. +1. Visual Studio creates the project. Add a reference to the following assemblies, and choose **OK**. + + - Microsoft.SharePoint.Client.dll + - Microsoft.SharePoint.Client.Runtime.dll + +1. In the default .cs file, add a **using** directive as follows. + + ```csharp + using Microsoft.SharePoint.Client; + ``` + +1. Add the following code to the **Main** method in the .cs file. + + ```csharp + class Program { - static void Main(string[] args) - { - AddGeolocationField(); - Console.WriteLine("Location field added successfully"); - } - private static void AddGeolocationField() - { - // Replace site URL and List Title with Valid values. - ClientContext context = new ClientContext(""); - List oList = context.Web.Lists.GetByTitle(""); - oList.Fields.AddFieldAsXml("",true, AddFieldOptions.AddToAllContentTypes); - oList.Update(); - context.ExecuteQuery(); - } + static void Main(string[] args) + { + AddGeolocationField(); + Console.WriteLine("Location field added successfully"); + } + private static void AddGeolocationField() + { + // Replace site URL and List Title with Valid values. + ClientContext context = new ClientContext(""); + List oList = context.Web.Lists.GetByTitle(""); + oList.Fields.AddFieldAsXml("",true, AddFieldOptions.AddToAllContentTypes); + oList.Update(); + context.ExecuteQuery(); + } } -``` - -8. Replace \ and \ with valid values. - - -9. Set the target framework in Project Properties as .NET Framework 4.0 or 3.5, and run the example. - - -10. Navigate to the list. You should be able to see a column named **Location** of type Geolocation in the list. You can now enter some values and see it in action. Figure 1 shows the default location and map features that you can expect to see in your list. - - **Figure 1. Summarized view of the default location and map features** + ``` - +1. Replace `` and `` with valid values. +1. Set the target framework in Project Properties as .NET Framework 4.0 or 3.5, and run the example. +1. Navigate to the list. You should be able to see a column named **Location** of type Geolocation in the list. You can now enter some values and see it in action. Figure 1 shows the default location and map features that you can expect to see in your list. + **Figure 1. Summarized view of the default location and map features** ![Default Geolocation and Map feature](../images/SP15Con_HowToAddGeolocationColumnUpdated_Fig1.png) - - - - - ## Add a list item with the Geolocation field value to a SharePoint list programmatically - After the Geolocation field is added to a SharePoint list, the developer can add the list item to the list programmatically. There are two ways to add the list item programmatically: by passing the **FieldGeolocationValue** object to the Geolocation field, and by passing **Raw Value** to the Geolocation field. - - - ### Method A: Pass the FieldGeolocationValue object to the Geolocation field - - The following method adds a list item by passing the Geolocation value as an object. - -```cs - -private void AddListItem() - { // Replace site URL and List Title with Valid values. - ClientContext context = new ClientContext(""); - List oList = context.Web.Lists.GetByTitle(""); - - ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation(); - ListItem oListItem = oList.AddItem(itemCreationInfo); - oListItem["Title"] = "New Title"; + ```csharp + private void AddListItem() { + // Replace site URL and List Title with Valid values. + ClientContext context = new ClientContext(""); + List oList = context.Web.Lists.GetByTitle(""); - FieldGeolocationValue oGeolocationValue = new FieldGeolocationValue(); - oGeolocationValue.Latitude = (double)17.4; - oGeolocationValue.Longitude = (double)78.4; - oListItem["location"] = oGeolocationValue; + ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation(); + ListItem oListItem = oList.AddItem(itemCreationInfo); - oListItem.Update(); - context.ExecuteQuery(); - } + oListItem["Title"] = "New Title"; -``` + FieldGeolocationValue oGeolocationValue = new FieldGeolocationValue(); + oGeolocationValue.Latitude = (double)17.4; + oGeolocationValue.Longitude = (double)78.4; + oListItem["location"] = oGeolocationValue; + oListItem.Update(); + context.ExecuteQuery(); + } + ``` ### Method B: Pass a raw value to the Geolocation field - - The following method adds a list item to the SharePoint list by passing raw values to the Geolocation field. - -```cs - -private void AddListItem() - { // Replace site URL and List Title with Valid values. - ClientContext context = new ClientContext(""); - List oList = context.Web.Lists.GetByTitle(""); - - ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation(); - ListItem oListItem = oList.AddItem(itemCreationInfo); - oListItem["Title"] = "New Title"; - // Data in WKT (World Known Text) format. - oListItem["location"] = "POINT (78.4 17.4)" ; + ```csharp + private void AddListItem() { + // Replace site URL and List Title with Valid values. + ClientContext context = new ClientContext(""); + List oList = context.Web.Lists.GetByTitle(""); - oListItem.Update(); - context.ExecuteQuery(); - } + ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation(); + ListItem oListItem = oList.AddItem(itemCreationInfo); -``` + oListItem["Title"] = "New Title"; + // Data in WKT (World Known Text) format. + oListItem["location"] = "POINT (78.4 17.4)" ; + oListItem.Update(); + context.ExecuteQuery(); + } + ``` ## See also - - - -- [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md) - - -- [How to: Set the Bing Maps key at the web and farm level in SharePoint](how-to-set-the-bing-maps-key-at-the-web-and-farm-level-in-sharepoint.md) - - -- [How to: Extend the Geolocation field type using client-side rendering](how-to-extend-the-geolocation-field-type-using-client-side-rendering.md) - - -- [Create a map view for the Geolocation field in SharePoint](create-a-map-view-for-the-geolocation-field-in-sharepoint.md) - - -- [How to: Integrate maps with Windows Phone apps and SharePoint lists](how-to-integrate-maps-with-windows-phone-apps-and-sharepoint-lists.md) - - -- [Use the SharePoint location field type in mobile applications](https://technet.microsoft.com/library/fp161355%28v=office.15%29.aspx) - - +- [Integrating location and map functionality in SharePoint](integrating-location-and-map-functionality-in-sharepoint.md) +- [How to: Set the Bing Maps key at the web and farm level in SharePoint](how-to-set-the-bing-maps-key-at-the-web-and-farm-level-in-sharepoint.md) +- [How to: Extend the Geolocation field type using client-side rendering](how-to-extend-the-geolocation-field-type-using-client-side-rendering.md) +- [Create a map view for the Geolocation field in SharePoint](create-a-map-view-for-the-geolocation-field-in-sharepoint.md) +- [How to: Integrate maps with Windows Phone apps and SharePoint lists](how-to-integrate-maps-with-windows-phone-apps-and-sharepoint-lists.md) +- [Use the SharePoint location field type in mobile applications](https://technet.microsoft.com/library/fp161355%28v=office.15%29.aspx) diff --git a/docs/general-development/how-to-add-a-security-trim-snippet-in-sharepoint.md b/docs/general-development/how-to-add-a-security-trim-snippet-in-sharepoint.md index 175bc66fe..6fde84dc3 100644 --- a/docs/general-development/how-to-add-a-security-trim-snippet-in-sharepoint.md +++ b/docs/general-development/how-to-add-a-security-trim-snippet-in-sharepoint.md @@ -1,152 +1,87 @@ --- title: Add a Security Trim snippet in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to add a Security Trim snippet in SharePoint to display content only to specific and authenticated users. +ms.date: 05/18/2023 ms.assetid: 4beaab08-760b-408a-b768-906312779379 -localization_priority: Priority +ms.localizationpriority: high --- - # Add a Security Trim snippet in SharePoint You can use a Security Trim snippet to display content only to specific users, based on a specific permission that those users must have and whether the users are authenticated or anonymous. ## Introduction to the Security Trim snippet - You can use a Security Trim snippet to display content only to specific users, based on a specific permission that those users must have, and whether those users are authenticated or anonymous. You can add a Security Trim panel to a master page or page layout. A Security Trim panel is a container that can include other components or snippets, such as web parts, in addition to static content. - - - + For example, you can use a Security Trim panel to display the following content to specific users: - - - - A Content by Search web part that displays which documents an authenticated user is currently working on. - - - A list view of recently modified documents so that authenticated users can see what's new on the site. - - - A Content by Search web part that displays to non-authenticated visitors a list of recommended links based on the current article. Such a list of recommendations might be noise to authenticated content authors working in the site, but it's important for non-authenticated visitors. - - - A sign-in link separate from the ribbon, for non-authenticated users or users who have yet to be authenticated. - + > [!NOTE] - > This sign-in link is inserted automatically into a master page that is created by using Design Manager, but you can delete it if it's not needed. + > This sign-in link is inserted automatically into a master page that is created by using Design Manager, but you can delete it if it's not needed. A Security Trim panel has two important property settings, one for authentication and one for permissions (or authorization). For example, you can use a Security Trim panel to display the following content to specific users: - - - - **AuthenticationRestrictions** With this property, you can restrict the panel to either authenticated or anonymous users, or choose all users (all users is the default setting). - - - **Permissions** With this property, you can select a specific permission that users must have to view the content in the panel. - + > [!NOTE] - > You are selecting an individual permission, not a permission level. (A permission level is a set of granted permissions.) + > You are selecting an individual permission, not a permission level. (A permission level is a set of granted permissions.) + Of course, if you restrict the authentication to only anonymous users, it's typically not necessary to specify a specific permission because anonymous users have usually not been given any SharePoint permissions. It makes sense to use permissions only with all users or with all authenticated users. - - - -The Security Trim panel has three options on the ribbon, listed in the left column of Table 1. Table 1 shows how these settings determine the specific permission that users are required to have, the lowest default permission level that includes that specific permission, and the group that is linked to that permission level by default.) - + +The Security Trim panel has three options on the ribbon, listed in the left column of Table 1. Table 1 shows how these settings determine the specific permission that users are required to have, the lowest default permission level that includes that specific permission, and the group that is linked to that permission level by default. + > [!NOTE] -> These are the default settings, which can be changed for any given scope, such as a site collection, site, list, or item. - - - +> These are the default settings, which can be changed for any given scope, such as a site collection, site, list, or item. For example, if you set a Security Trim panel to **Show to authors**, by default content inside that panel is visible to users in the Members group and the Owners group. - - - **Table 1. Mapping of panel options to default permission levels and groups** - |**Security Trim panel option**|**Permissions property**|**Permission**|**Permission level**|**Group**| |:-----|:-----|:-----|:-----|:-----| -|Show to authors
|**AddAndCustomizePages**
|Add and Customize Pages
|Contribute (or higher)
|Members
| -|Show to Authenticated Users
|**ViewPages**
|View Pages
|Read (or higher)
|Visitors
| -|Show to Administrators
|**FullMask**
|Select All
|Full Control
|Owners
| - +|Show to authors |**AddAndCustomizePages** |Add and Customize Pages |Contribute (or higher) |Members | +|Show to Authenticated Users |**ViewPages** |View Pages |Read (or higher) |Visitors | +|Show to Administrators |**FullMask** |Select All |Full Control |Owners | ### Inserting a Security Trim panel - Like all snippets, you add the Security Trim snippet from the Snippet Gallery. To navigate to the Snippet Gallery, you must first select a master page or page layout to edit. - - - ### To insert a Security Trim panel - 1. Browse to your publishing site. - - -2. In the upper-right corner of the page, choose the Settings gear, and then choose **Design Manager**. - - -3. In Design Manager, in the left navigation pane, choose **Edit Master Pages** or **Edit Page Layouts**, depending on what type of file you're editing. - - -4. Select the name of the master page or page layout that you want to add the snippet to. - - -5. To open the Snippet Gallery, choose **Snippets** in the upper-right corner of the server-side preview. - - -6. On the ribbon, on the **Design** tab, choose **Security Trim**. - +1. In the upper-right corner of the page, choose the Settings gear, and then choose **Design Manager**. +1. In Design Manager, in the left navigation pane, choose **Edit Master Pages** or **Edit Page Layouts**, depending on what type of file you're editing. +1. Select the name of the master page or page layout that you want to add the snippet to. +1. To open the Snippet Gallery, choose **Snippets** in the upper-right corner of the server-side preview. +1. On the ribbon, on the **Design** tab, choose **Security Trim**. + Optionally, in the drop-down list on the **Security Trim** button, you can select the users to whom the panel content will be visible, or you can see more options by configuring the important property values for the panel. - - -7. On the right side of the Snippet Gallery, under **About this Component**, click or select section headers to expand or collapse groups of properties, and then configure any custom settings that you want. - - -8. After you configure any properties, choose **Update**. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always choose **Reset** to return all properties to their default settings. - - -9. On the left side of the Snippet Gallery, under **HTML Snippet**, choose **Copy to Clipboard**. - - -10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to. - - -11. In the HTML file, paste the snippet where you want the markup to appear. - + +1. On the right side of the Snippet Gallery, under **About this Component**, click or select section headers to expand or collapse groups of properties, and then configure any custom settings that you want. +1. After you configure any properties, choose **Update**. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always choose **Reset** to return all properties to their default settings. +1. On the left side of the Snippet Gallery, under **HTML Snippet**, choose **Copy to Clipboard**. +1. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to. +1. In the HTML file, paste the snippet where you want the markup to appear. + If you are adding the snippet to a page layout, make sure to paste the snippet inside **PlaceHolderMain**. - - -12. Replace the **
** where `class="DefaultContentBlock"` with your own specific content. - - -13. Save the page, and then refresh the server-side preview in Design Manager to make sure the Security Trim panel appears as expected. - - -## Understanding the snippet markup - +1. Replace the `
` where `class="DefaultContentBlock"` with your own specific content. +1. Save the page, and then refresh the server-side preview in Design Manager to make sure the Security Trim panel appears as expected. -The most important parts of a Security Trim snippet are the **AuthenticationRestrictions** property and the **Permissions** property, and the **
** in bold below. **AuthenticationRestrictions** appears in the markup only when changed from **AllUsers**, which is the default. If you choose **Reset** for the snippet in the Snippet Gallery, **AuthenticationRestrictions** is removed from the markup, which means the snippet uses the default value, **AllUsers**. - - - -The **
** where `class="DefaultContentBlock"` is what you replace with your own content, which can include other snippets and controls. - - - +## Understanding the snippet markup +The most important parts of a Security Trim snippet are the **AuthenticationRestrictions** property and the **Permissions** property, and the `
` in bold below. **AuthenticationRestrictions** appears in the markup only when changed from **AllUsers**, which is the default. If you choose **Reset** for the snippet in the Snippet Gallery, **AuthenticationRestrictions** is removed from the markup, which means the snippet uses the default value, **AllUsers**. +The `
` where `class="DefaultContentBlock"` is what you replace with your own content, which can include other snippets and controls. ```HTML -
@@ -161,21 +96,9 @@ The **
** where `class="DefaultContentBlock"` is what you replace with your
``` - ## See also - - - -- [Understanding permission levels](https://support.office.com/article/understanding-permission-levels-in-sharepoint-87ecbb0e-6550-491a-8826-c075e4859848) - - -- [SharePoint Design Manager snippets](sharepoint-design-manager-snippets.md) - - -- [Build sites for SharePoint](build-sites-for-sharepoint.md) - - -- [Develop the site design in SharePoint](develop-the-site-design-in-sharepoint.md) - - +- [Understanding permission levels](https://support.office.com/article/understanding-permission-levels-in-sharepoint-87ecbb0e-6550-491a-8826-c075e4859848) +- [SharePoint Design Manager snippets](sharepoint-design-manager-snippets.md) +- [Build sites for SharePoint](build-sites-for-sharepoint.md) +- [Develop the site design in SharePoint](develop-the-site-design-in-sharepoint.md) diff --git a/docs/general-development/how-to-add-a-web-part-zone-snippet-in-sharepoint.md b/docs/general-development/how-to-add-a-web-part-zone-snippet-in-sharepoint.md index a31e53041..5390f1ed0 100644 --- a/docs/general-development/how-to-add-a-web-part-zone-snippet-in-sharepoint.md +++ b/docs/general-development/how-to-add-a-web-part-zone-snippet-in-sharepoint.md @@ -1,209 +1,116 @@ --- title: Add a web part zone snippet in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to add a web part zone snippet in SharePoint and provides a list of Web part zone properties used to restrict content authors. +ms.date: 05/18/2023 ms.assetid: 7583b217-200c-4569-8f88-fe975c8ebd72 -localization_priority: Priority +ms.localizationpriority: high --- - # Add a web part zone snippet in SharePoint -> [!IMPORTANT] +> [!IMPORTANT] > This extensibility option is **only** available for classic SharePoint experiences. You cannot use this option with modern experiences in SharePoint Online, like with communication sites. We do not recommend using classic experience or these branding techniques anymore. A web part zone is a snippet that you can add to a page layout so that content authors can add, edit, or delete web parts in that zone. ## Introduction to the web part zone snippet - A web part is a server control that provides a specific piece of SharePoint functionality, and a web part zone is a container that determines the layout, behavior, and other properties of the web parts contained in that zone. For example, a web part zone can specify whether the web parts in the zone: - - - -- Are arranged in a horizontal or vertical layout. - - +- Are arranged in a horizontal or vertical layout. - Display common user interface (UI) elements such as a title bar or border. - - - Can be customized by content authors when they edit a page in the browser. - - - Can be personalized by site visitors who create a personal view of a web part when they view a page in the browser. - - + In a publishing site, content authors with the necessary permissions can create or edit pages that reside in the Pages library. As a designer, you can add a web part zone to a page layout. When a content author creates or edits a page based on that page layout, the author can add, edit, or delete web parts in that zone. For example, you may want to add a web part zone to a page layout so that content authors can: - - - - Display the results of a search query by using a Content Search web part. Authors can update or modify the search query when a search-driven web part resides inside a web part zone. - - - Embed video or audio clips in a webpage by using a Media web part. - - - Create lists of hyperlinks that are easily edited, grouped, or reordered by using a Summary Link web part. - - - Create a site map that lists all pages in a site and that is automatically updated whenever a page is added, deleted, renamed, or moved by using a Table of Contents web part. - - ### When to use web part zones When a page layout includes one or more web part zones, the web part zones are available on all pages that use that layout, which enables authors to insert web parts onto those pages. If you enable authors to insert web parts on pages, you reduce your control over the users' experience of the site. For example, an author could insert a Table of Contents web part onto a page that exposes parts of your site that you don't want visitors to navigate to from the current page. - - - + If you want complete control over how a web part appears on your site, and if you want that web part to appear on all pages of a certain type, add the web part directly to a page layout. If you want a web part to appear on all pages in a site, you can also add a web part directly to a master page. - + > [!NOTE] -> Web part zones are available on page layouts but not on master pages—the purpose of zones is to allow authors to modify web parts, and authors typically don't edit a master page. - - - +> Web part zones are available on page layouts but not on master pages—the purpose of zones is to allow authors to modify web parts, and authors typically don't edit a master page. You can also add web part zones to a page layout but restrict their use. For example, you can add web parts to a zone, and then set a property of that zone so that content authors can edit the properties of existing web parts but not add or remove web parts from the zone. web part zones have a set of properties that serve a dual purpose. You can use one subset of properties to organize the layout and format of web parts on the page. You can use another subset of properties to provide an additional level of protection from modification (or "lock down") of the web parts within the zone. - - - + For varying levels of control over how web parts are presented on your site, you can: - - - - Add web parts directly to a master page or page layout. This means content authors cannot modify the web parts. - - - Add web parts to zones on page layouts, but restrict those zones to only the default web parts that you add. - - - Add web part zones to page layouts, and give content authors complete control over what web parts appear in those zones and how they are configured. - - + The properties of a web part zone can specify whether content authors are allowed to change: - - - - The layout of web parts in the zone by adding, deleting, resizing, or moving the web parts. - - - The web part settings for all users (the shared view of a web part). - - - Their personal web part settings (the personal view of a web part). - - + Table 1 shows important properties to consider when you want to restrict a web part zone. - - - **Table 1. Web part zone properties used to restrict content authors** - |**Property Name**|**Description**| |:-----|:-----| -|**AllowLayoutChange**
|Specifies whether web parts within the zone can be closed, minimized, deleted, or restored.
If set to **False**, users cannot close, minimize, delete, or restore web parts in the zone, drag web parts to a different zone, or rearrange or move web parts within the zone. Users also cannot add web parts from the web part catalog, and several properties that affect the UI of web parts in the zone are disabled. This property does not affect the ability to change the layout programmatically.
If set to **True**, users with appropriate permissions can perform these actions.
| -|**LockLayout**
|Specifies whether web parts within the zone can be added, deleted, resized, or moved. This property works the same whether the web part page is in personal view or shared view.
If set to **True**, the specific web part properties for each web part in the zone that are affected are: **Zone (ZoneID)**, **Part Order (PartOrder)**, **Visible on Page (IsVisible)**, **Height (Height)**, **Width (Width)**, **Allow Close (AllowRemove)**, and **IsIncluded** (the **Close** command on the **web part** menu). Other web part properties are not affected.
If set to **False**, the web part properties determine whether modifications can be made (together with the appropriate site permissions).
| -|**AllowCustomization**
|Specifies whether shared property values of web parts within the zone can be modified.
If set to **True**, users with appropriate permissions can make changes to the web parts in the zone for all users.
If set to **False**, users cannot make changes to the web parts in the zone in the UI in shared view. But, changes can still be made programmatically and by using the web part Maintenance page.
| -|**AllowPersonalization**
|Specifies whether personal property values of web parts within the zone can be modified.
If set to **True**, users with appropriate permissions can make personal changes to the web parts in the zone.
If set to **False**, users cannot make personal changes to the web parts through the UI, unless the web part is a private web part and they have appropriate permissions.
| - -> [!NOTE] -> You cannot insert a web part zone inside a Device Channel Panel. If you want to allow authors to add web parts to a page, and if you are not concerned about the page weight for mobile devices, you can add a Rich Text Editor page field to a Device Channel Panel, and then instruct authors to add web parts there. You can add web parts directly to a Device Channel Panel (without a web part zone). For more information, see [How to: Add a Device Channel Panel snippet in SharePoint](how-to-add-a-device-channel-panel-snippet-in-sharepoint.md). - - - +|**AllowLayoutChange** |Specifies whether web parts within the zone can be closed, minimized, deleted, or restored. If set to **False**, users cannot close, minimize, delete, or restore web parts in the zone, drag web parts to a different zone, or rearrange or move web parts within the zone. Users also cannot add web parts from the web part catalog, and several properties that affect the UI of web parts in the zone are disabled. This property does not affect the ability to change the layout programmatically. If set to **True**, users with appropriate permissions can perform these actions. | +|**LockLayout** |Specifies whether web parts within the zone can be added, deleted, resized, or moved. This property works the same whether the web part page is in personal view or shared view. If set to **True**, the specific web part properties for each web part in the zone that are affected are: **Zone (ZoneID)**, **Part Order (PartOrder)**, **Visible on Page (IsVisible)**, **Height (Height)**, **Width (Width)**, **Allow Close (AllowRemove)**, and **IsIncluded** (the **Close** command on the **web part** menu). Other web part properties are not affected. If set to **False**, the web part properties determine whether modifications can be made (together with the appropriate site permissions). | +|**AllowCustomization** |Specifies whether shared property values of web parts within the zone can be modified. If set to **True**, users with appropriate permissions can make changes to the web parts in the zone for all users. If set to **False**, users cannot make changes to the web parts in the zone in the UI in shared view. But, changes can still be made programmatically and by using the web part Maintenance page. | +|**AllowPersonalization** |Specifies whether personal property values of web parts within the zone can be modified. If set to **True**, users with appropriate permissions can make personal changes to the web parts in the zone. If set to **False**, users cannot make personal changes to the web parts through the UI, unless the web part is a private web part and they have appropriate permissions. | +> [!NOTE] +> You cannot insert a web part zone inside a Device Channel Panel. If you want to allow authors to add web parts to a page, and if you are not concerned about the page weight for mobile devices, you can add a Rich Text Editor page field to a Device Channel Panel, and then instruct authors to add web parts there. You can add web parts directly to a Device Channel Panel (without a web part zone). For more information, see [How to: Add a Device Channel Panel snippet in SharePoint](how-to-add-a-device-channel-panel-snippet-in-sharepoint.md). ## Inserting a web part zone snippet - Like all snippets, you add this snippet from the Snippet Gallery. To navigate to the Snippet Gallery, you must first select a page layout to edit. Web part zones can be added to page layouts but cannot be added to master pages. - - - ### To insert a web part zone snippet - 1. Browse to your publishing site. - - -2. In the upper-right corner of the page, choose the Settings gear, and then choose **Design Manager**. - - -3. In Design Manager, in the left navigation pane, choose **Edit Page Layouts**. - - -4. Select the name of the page layout that you want to add the snippet to. - - -5. To open the Snippet Gallery, choose **Snippets** in the upper-right corner of the server-side preview. - - -6. On the ribbon, on the **Design** tab, choose **web part zone**. - - -7. On the right side of the Snippet Gallery, under **About this Component**, click or select section headers to expand or collapse groups of properties, and then configure any custom settings that you want. - +1. In the upper-right corner of the page, choose the Settings gear, and then choose **Design Manager**. +1. In Design Manager, in the left navigation pane, choose **Edit Page Layouts**. +1. Select the name of the page layout that you want to add the snippet to. +1. To open the Snippet Gallery, choose **Snippets** in the upper-right corner of the server-side preview. +1. On the ribbon, on the **Design** tab, choose **web part zone**. +1. On the right side of the Snippet Gallery, under **About this Component**, click or select section headers to expand or collapse groups of properties, and then configure any custom settings that you want. + The section named **Important** contains the properties that are key to how this particular snippet works. For a web part zone, the snippet has a unique ID. After you copy the snippet into your page layout, you should not reuse this ID. If you want to add another web part zone snippet, choose **Refresh** to generate a new ID for the next snippet. - + For descriptions of properties that are necessary for restricting a web part zone ( **LockLayout**, **AllowCustomization**, and **AllowPersonalization**), see Table 1. - + > [!NOTE] - > You may notice that some property names are bold in the property grid of the Snippet Gallery. These properties have values that have been changed from the default setting for this component, but these properties are not necessarily relevant to a designer scenario. In other words, a property may be bold but not necessarily important for your scenario. - -8. After you configure any properties, choose **Update**. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always choose **Reset** to return all properties to their default settings. - - -9. On the left side of the Snippet Gallery, under **HTML Snippet**, choose **Copy to Clipboard**. - - -10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to. - + > You may notice that some property names are bold in the property grid of the Snippet Gallery. These properties have values that have been changed from the default setting for this component, but these properties are not necessarily relevant to a designer scenario. In other words, a property may be bold but not necessarily important for your scenario. + +1. After you configure any properties, choose **Update**. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always choose **Reset** to return all properties to their default settings. +1. On the left side of the Snippet Gallery, under **HTML Snippet**, choose **Copy to Clipboard**. +1. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to. + For more information, see [How to: Map a network drive to the SharePoint Master Page Gallery](how-to-map-a-network-drive-to-the-sharepoint-master-page-gallery.md). - - -11. In the HTML file, paste the snippet where you want the markup to appear. - + +1. In the HTML file, paste the snippet where you want the markup to appear. + When you are adding the snippet to a page layout, make sure to paste the snippet inside **PlaceHolderMain**. - - -12. Replace the **
** where `class="DefaultContentBlock"` with your own specific content. - - -13. If you want to prepopulate the zone with web parts—for example, if the zone will restrict content authors to modifying only existing web parts and not adding new ones—insert web part snippets where the **** tag appears. - - -14. Save the page, and then refresh the server-side preview in Design Manager to make sure the page appears as expected. - - + +1. Replace the `
` where `class="DefaultContentBlock"` with your own specific content. +1. If you want to prepopulate the zone with web parts—for example, if the zone will restrict content authors to modifying only existing web parts and not adding new ones—insert web part snippets where the **** tag appears. +1. Save the page, and then refresh the server-side preview in Design Manager to make sure the page appears as expected. ## Understanding the snippet markup - The two most important parts of a web part zone snippet are the **ID** property and the **** comment. Each zone should have a unique ID. If you want to add more than one web part zone to your page layout, make sure to choose **Refresh** in the Snippet Gallery before copying each snippet so that a new ID is generated. The **** comment should be replaced with any web parts that you want to appear in the zone by default. - - - + Additional properties that can be used to restrict how content authors can use zones ( **AllowCustomization**, **AllowPersonalization**, and **LockLayout**) are shown in the following code. - + > [!NOTE] > The **AllowCustomization**, **AllowPersonalization**, and **LockLayout** properties appear in the markup only if you change their default values in the property grid. - - - - - - - -```HTML +```html
@@ -219,24 +126,10 @@ Additional properties that can be used to restrict how content authors can use z ``` - ## See also - - - -- [SharePoint Design Manager snippets](sharepoint-design-manager-snippets.md) - - -- [WebPartZone class](https://msdn.microsoft.com/library/system.web.ui.webcontrols.webparts.webpartzone.aspx) - - -- [WebPartZoneBase properties](https://msdn.microsoft.com/library/335sw9k3.aspx) - - -- [Build sites for SharePoint](build-sites-for-sharepoint.md) - - -- [Develop the site design in SharePoint](develop-the-site-design-in-sharepoint.md) - - +- [SharePoint Design Manager snippets](sharepoint-design-manager-snippets.md) +- [WebPartZone class](https://msdn.microsoft.com/library/system.web.ui.webcontrols.webparts.webpartzone.aspx) +- [WebPartZoneBase properties](https://msdn.microsoft.com/library/335sw9k3.aspx) +- [Build sites for SharePoint](build-sites-for-sharepoint.md) +- [Develop the site design in SharePoint](develop-the-site-design-in-sharepoint.md) diff --git a/docs/general-development/how-to-add-an-edit-mode-panel-snippet-in-sharepoint.md b/docs/general-development/how-to-add-an-edit-mode-panel-snippet-in-sharepoint.md index 0291727dc..c5ebadd63 100644 --- a/docs/general-development/how-to-add-an-edit-mode-panel-snippet-in-sharepoint.md +++ b/docs/general-development/how-to-add-an-edit-mode-panel-snippet-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Add an Edit Mode Panel snippet in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to add an Edit Mode Panel snippet in SharePoint to display instructions or other content to content authors. +ms.date: 06/09/2022 ms.assetid: 39fa1e32-9129-407d-914f-96f4c6e66dc8 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/how-to-apply-a-master-page-to-a-site-in-sharepoint.md b/docs/general-development/how-to-apply-a-master-page-to-a-site-in-sharepoint.md index 49e096bf6..ca1720117 100644 --- a/docs/general-development/how-to-apply-a-master-page-to-a-site-in-sharepoint.md +++ b/docs/general-development/how-to-apply-a-master-page-to-a-site-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Apply a master page to a site in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to apply a master page to a site in SharePoint and how to map a master page to a SharePoint site. +ms.date: 06/09/2022 ms.assetid: 04861390-84d5-40ea-b0db-6c0748eff196 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/how-to-apply-styles-to-page-fields-in-sharepoint.md b/docs/general-development/how-to-apply-styles-to-page-fields-in-sharepoint.md index 12ca69a73..084691223 100644 --- a/docs/general-development/how-to-apply-styles-to-page-fields-in-sharepoint.md +++ b/docs/general-development/how-to-apply-styles-to-page-fields-in-sharepoint.md @@ -2,9 +2,8 @@ title: Apply styles to page fields in SharePoint description: In a page layout, you can apply styles to a page field, and those styles are applied to any content added by content authors when they create a page from that page layout. Also, you have further options to control how content in a RichHtmlField page field is styled. ms.date: 12/22/2020 -ms.prod: sharepoint ms.assetid: e227613d-0e4d-4312-924d-bb55e1fe4293 -localization_priority: Priority +ms.localizationpriority: high --- # Apply styles to page fields in SharePoint diff --git a/docs/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md b/docs/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md index 87fa338ba..f239f0fb8 100644 --- a/docs/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md +++ b/docs/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md @@ -1,278 +1,325 @@ --- title: Avoid getting throttled or blocked in SharePoint Online -description: Find out about throttling in SharePoint Online, and learn how to avoid being throttled or blocked. Includes sample client-side object model (CSOM) and REST code you can use to make your task easier. -ms.date: 03/17/2021 -ms.prod: sharepoint +description: Learn about throttling in SharePoint Online and learn how to avoid being throttled or blocked. +ms.date: 06/12/2025 ms.assetid: 33ed8106-d850-42b1-8d7f-5ba83901149c -localization_priority: Priority +ms.localizationpriority: high --- # Avoid getting throttled or blocked in SharePoint Online -Find out about throttling in SharePoint Online, and learn how to avoid being throttled or blocked. Includes sample client-side object model (CSOM) and REST code you can use to make your task easier. +Find out about throttling in SharePoint Online and learn how to avoid being throttled or blocked. - [What is throttling?](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#what-is-throttling) +- [How to handle throttling?](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#how-to-handle-throttling) - [Common throttling scenarios in SharePoint Online](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#common-throttling-scenarios-in-sharepoint-online) -- [Why can't you just tell me the exact throttling limits?](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#why-cant-you-just-tell-me-the-exact-throttling-limits) -- [Search query volume limits when using app-only authentication with Sites.Read.All permission](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#search-query-volume-limits-when-using-app-only-authentication-with-sitesreadall-permission) -- [Best practices to handle throttling](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#best-practices-to-handle-throttling) -- [How to decorate your traffic to avoid getting throttled?](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#how-to-decorate-your-http-traffic-to-avoid-throttling) -- [GitHub CSOM code samples: SharePoint Online Throttling](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md) +- [Scenario specific limits](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#scenario-specific-limits) - [What should you do if you get blocked in SharePoint Online?](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#what-should-you-do-if-you-get-blocked-in-sharepoint-online) - [Additional resources](how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online.md#see-also) -Does this sound familiar? You're running a CSOM process - for example, to migrate files in SharePoint Online - but you keep getting throttled. Or even worse, you get blocked. What's going on and what can you do to make it stop? +Does this sound familiar? You're running an application - for example, to scan files in SharePoint Online - but you get throttled. Or even worse, you get blocked. What's going on and what can you do to make it stop? ## What is throttling? -SharePoint Online uses throttling to maintain optimal performance and reliability of the SharePoint Online service. Throttling limits the number of user actions or concurrent calls (by script or code) to prevent overuse of resources. +SharePoint Online uses throttling to maintain the optimal performance and reliability of the SharePoint Online service. Throttling limits the number of API calls or operations within a time window to prevent the overuse of resources. -That said, it is rare for a user to get throttled in SharePoint Online. The service is robust, and it is designed to handle high volume. If you do get throttled, 99% of the time it is because of custom code. That doesn't mean that there aren't other ways to get throttled, just that they're less common. For example, you spin up 10 machines and have a sync client going on all 10. On each sync 1 TB of content. This would likely get you throttled. - -![How throttling happens](../images/3b9184db-99a4-416e-ba1e-7f8653484cee.png) +> [!NOTE] +> Recent updates to this article enhance transparency to already existing throttling rules in the system ### What happens when you get throttled in SharePoint Online? -When a user exceeds usage limits, SharePoint Online throttles any further requests from that user account for a short period. All user actions are throttled while the throttle is in effect. +When usage limits are exceeded, SharePoint Online throttles any further requests from that client for a short period. + +For requests that a user performs directly in the browser, SharePoint Online redirects you to the throttling information page, and the requests fail. + +For requests that an application makes, including [Microsoft Graph](/graph), CSOM, or REST calls, SharePoint Online returns HTTP status code 429 ("Too many requests") or 503 ("Server Too Busy"), and the requests will fail. + +- HTTP 429 indicates the calling application sent too many requests in a time window and exceeded a predetermined limit. +- HTTP 503 indicates the service isn't ready to handle the request. The common cause is that the service is experiencing more temporary load spikes. + +In both cases, a `Retry-After` header is included in the response, indicating how long the calling application should wait before retrying or making a new request. Throttled requests count towards usage limits, so failure to honor `Retry-After` may result in more throttling. + +If the offending application continues to exceed usage limits, SharePoint Online may completely block the application or specific request patterns from the application; in this case, the application will keep getting HTTP status code 503, and Microsoft will notify the tenant of the block in the Office 365 Message Center. + +### Resource units + +Some limits are measured in terms of API costs. [Microsoft Graph APIs](/graph) have a predetermined resource unit cost per request: + +| Resource units per request | Operations | +| -------------------------- | -------------------------------------------------------------------------------------------------------------- | +| 1 |
  • Single item query, such as get item
  • Delta with a token
  • Download file from drive item | +| 2 |
  • Multi item query, such as list children, except delta with a token
  • Create, update, delete, and upload | +| 5 |
  • All permission resource operations, including `$expand=permissions` | + +> [!NOTE] +> We reserve the right to change the API resource unit cost. + +### User Throttling + +Throttling limits the number of calls and operations collectively made by applications on behalf of a user to prevent the overuse of resources. + +That said, it's rare for a user to get throttled in SharePoint Online. The service is robust, and it's designed to handle high volume. If you do get throttled, 99% of the time it is because of custom code, such as custom web parts, complex list views and queries, or custom apps users run. That doesn’t mean that there aren’t other ways to get throttled, just that they’re less common. For example, one user syncing a large amount of data across 10 machines at the same time could trigger throttling. + +| Category | Type of throttling | Time interval | Limit | +|--------------|------------------------------|-------------------|-----------| +| User | Requests | 5 min | 3,000 | +| User | Ingress | 1 H | 50 GB | +| User | Egress | 1 H | 100 GB | +| User | Delegation Token Request | 5 min | 50 | +| User | External sharing emails | 1 H | 200 | + +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary -- For requests that a user performs directly in the browser, SharePoint Online redirects you to the throttling information page, and the requests fail. -- For all other requests, including CSOM or REST calls, SharePoint Online returns HTTP status code 429 ("Too many requests") or 503 ("Server Too Busy") and the requests will fail. +### Tenant Throttling -If the offending process continues to exceed usage limits, SharePoint Online might completely block the process; in this case, you won't see any successful requests and Microsoft will notify you of the block in the Office 365 Message Center. +Some throttling limits are applied at the Tenant level to ensure the operations collectively made do not overuse resources. + +When a customer enables Multi-Geo, each geo gets its own limits (usage measurement not shared across geos). For the limits that are dependent on license count, the total tenant user license count is used (total users across all geos). + +| Category | Type of throttling | Time interval | Tenant license count | Limit | +|--------------|--------------------------------------|-------------------|--------------------------|-----------| +| Tenant | [Resource Units](#resource-units) | 5 min | 0 - 1,000 | 18,750 | +| Tenant | [Resource Units](#resource-units) | 5 min | 1,001 - 5,000 | 37,500 | +| Tenant | [Resource Units](#resource-units) | 5 min | 5,001 - 15,000 | 56,250 | +| Tenant | [Resource Units](#resource-units) | 5 min | 15,001 - 50,000 | 75,000 | +| Tenant | [Resource Units](#resource-units) | 5 min | 50,000+ | 93,750 | +| Tenant | Assign Sensitivity Label | 5 min | no license bound | 100 | +| Tenant | PeopleManagerAPIs | 5 min | 0 - 1,000 | 3,000 | +| Tenant | PeopleManagerAPIs | 5 min | 1,001 - 5,000 | 6,000 | +| Tenant | PeopleManagerAPIs | 5 min | 5,001 - 15,000 | 9,000 | +| Tenant | PeopleManagerAPIs | 5 min | 15,001 - 50,000 | 12,000 | +| Tenant | PeopleManagerAPIs | 5 min | 50,000+ | 15,000 | + +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary ### Application Throttling -In addition to throttling by user account, limits are also applied to each application. Every application in SharePoint Online has its own available resources, but multiple applications running against the same tenant ultimately share from the same resource bucket and in rare occurrences can cause rate limiting. -In these cases, SharePoint Online will attempt to prioritize interactive user requests over background activities. +In addition to throttling by user account, limits are also applied to applications in a tenant. -## Common throttling scenarios in SharePoint Online +Every application has its own limits in a tenant, which are based on the number of licenses purchased per organization (see the plans listed on [SharePoint Limits](/office365/servicedescriptions/sharepoint-online-service-description/sharepoint-online-limits#limits-by-plan) for licenses included). Every request that an application makes across all API endpoints, including [Microsoft Graph](/graph), CSOM, and REST, counts towards the application’s usage. -The most common causes of per-user throttling in SharePoint Online are client-side object model (CSOM) or Representational State Transfer (REST) code that performs too many actions too frequently. +SharePoint provides various APIs. Different APIs have different costs depending on the complexity of the API. The cost of APIs is normalized by SharePoint and expressed by resource units. Application’s limits are also defined using resource units. -- **Sporadic traffic** +For multitenant applications: - Constant load or repetitive complex queries against SharePoint Online must be optimized for low impact. Failing to follow [best practices for scanning applications](https://aka.ms/ScanGuidance) that process files in bulk will likely result in throttling. These apps include sync engines, backup providers, search indexers, classification engines, data loss prevention tools, and any other tool, which attempts to reason over the entirety of data and apply changes to it. +1. Each tenant hosting the application is considered distinct, operating independently from others. Consequently, every application is subject to its own usage limits within each tenant as defined above. +1. The consumption of resource units by the application is to be measured on a per-tenant, per-application basis. This ensures that each tenant-application pair remains within the permissible resource limits specified for that particular tenant. +1. Should the application reach its resource limit within one tenant, this occurrence will not affect other instances of the application operating in different tenants. Each tenant's resource utilization is isolated, preventing cross-tenant impact. - For example, after migrating files to SharePoint Online, you run a custom CSOM or REST script to update metadata on the files. The CSOM/REST script is updating a large number of files at a high frequency, which triggers throttling. Similarly, an autocomplete UI widget using REST services, making too many calls to lists during each end-user operation, may also cause throttling, depending on what other operations are consuming resources at the same time. +| Category | Type of throttling | Time interval | Tenant license count | Limit | +|--------------------|--------------------------------------|-------------------|--------------------------|------------| +| Per APP Per Tenant | [Resource Units](#resource-units) | 24 H | 0 - 1,000 | 1,200,000 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 24 H | 1,001 - 5,000 | 2,400,000 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 24 H | 5,001 - 15,000 | 3,600,000 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 24 H | 15,001 - 50,000 | 4,800,000 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 24 H | 50,000+ | 6,000,000 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 1 min | 0 - 1,000 | 1,250 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 1 min | 1,001 - 5,000 | 2,500 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 1 min | 5,001 - 15,000 | 3,750 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 1 min | 15,001 - 50,000 | 5,000 | +| Per APP Per Tenant | [Resource Units](#resource-units) | 1 min | 50,000+ | 6,250 | +| Per APP Per Tenant | Ingress | 1 H | no license bound | 400 GB | +| Per APP Per Tenant | Egress | 1 H | no license bound | 400 GB | +| Per APP Per Tenant | Specific Sharing APIs | 5 min | no license bound | 300 | - ![Sporadic throttling](../images/a61afe25-9597-403f-b3fa-d3f630155021.png) +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary -- **Overwhelming traffic** +### Other Limits - A single process dramatically exceeds throttling limits, continually, over a long time period. +| Category | Type of throttling | Time interval | Limit | +|-------------------------------|--------------------------------------|-------------------|-----------| +| SharePoint Embedded containers| [Resource Units](#resource-units) | 1 min | 3,000 | +| Per Site | Anonymous Link | 5 min | 3,000 | +| Per Site | Anonymous Egress (Download) | 2 H | 100 GB | +| Per Site | External sharing emails | 1 H | 200 | - - You used web services to build a tool to synchronize user profile properties. The tool updates user profile properties based on information from your line-of-business (LOB) human resources (HR) system. The tool makes calls at too high a frequency. - - You're running a load-testing script on SharePoint Online and you get throttled. Load testing isn't allowed on SharePoint Online. - - You customized your team site on SharePoint Online, for example, by adding a status indicator on the Home page. This status indicator updates frequently, which causes the page to make too many calls to the SharePoint Online service - this triggered throttling. - - Running the OneDrive Sync client while also running migration applications or applications that crawl sites and write back data can result in high request volumes that may trigger throttling. +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary - ![Steady throttling](../images/7849d413-381f-4558-9e50-b3cc9990d3e3.png) +## How to handle throttling? -- **Unsupported use cases** +Below is a quick summary of the best practices to handle throttling: + +- Reduce the number of concurrent requests +- Avoid request spikes +- Choose [Microsoft Graph APIs](/graph) over CSOM and REST APIs when possible +- Use the `Retry-After` and `RateLimit` HTTP headers +- Decorate your traffic so we know who you are (see section on traffic decoration best practice, more on that below) +- Consider using [Graph Data Connect for SharePoint](https://techcommunity.microsoft.com/blog/microsoft_graph_data_connect_for_sharepo/links-about-microsoft-graph-data-connect-for-sharepoint/4069045) for broad site analytics +- Understand if [service prioritization in SharePoint](https://aka.ms/SharePointPrioritization) is the right fit for your scenario + +As stated earlier, [Microsoft Graph](/graph) is cloud born APIs that have the latest improvements and optimizations. In general, [Microsoft Graph](/graph) consumes fewer resources than CSOM and REST to achieve the same functionality. Hence, adopting [Microsoft Graph](/graph) can improve the application's performance and reduce throttling. + +If you do run into throttling, we require using the `Retry-After` HTTP header to ensure minimum delay until the throttle is removed. The `RateLimit` HTTP headers send you early signals when you're close to limits, and you can proactively reduce requests to avoid hitting the throttle. + +Delta with a token is the most efficient way to scan content in SharePoint, and we talk more in detail at the [best practices for scanning applications](https://aka.ms/ScanGuidance). To help applications that follow the guidance, we lower the resource unit cost of delta requests with a token to 1 resource unit, although it's a multi-item query. The delta request without a token is considered a multi-item query and costs 2 resource units per request. + +In [batching](/graph/json-batching), requests in a batch are evaluated individually by resource units. + +CSOM and REST don't have a predetermined resource unit cost, and they usually consume more resource units than [Microsoft Graph APIs](/graph) to achieve the same functionality. In addition to resource unit limits, CSOM and REST are also subject to other internal resource limits, so if applications call CSOM and REST, they may experience more throttling than the limits described in this document. We highly recommend you choose [Microsoft Graph APIs](/graph) over CSOM and REST APIs when possible. + +Since application limits are in resource units, the actual request rate, such as requests per minute, depends on the application’s API choice and the corresponding API resource unit cost. In general, you can estimate the request rate using an average of 2 resource units per request, and divide resource unit limits by 2 to get the estimated request rate. + +Although each application has its limits within a tenant, and we allow tenants to run more than one application, multiple applications running against the same tenant share the same resource bucket, and in rare occurrences can cause rate limiting when too many applications send requests at the time. + +### Retry-after header - Unsupported use of SharePoint Online may experience throttling. Using SharePoint and OneDrive as an intermediary service between Microsoft 365 and another repository is an example of an unsupported use case. +When applications experience throttling, SharePoint Online returns a `Retry-After` HTTP header in the request indicating how long in seconds the calling application should wait before retrying or making a new request. -## Why can't you just tell me the exact throttling limits? +Honoring the `Retry-After` HTTP header is the fastest way to handle being throttled because SharePoint Online dynamically determines the right time to try again. -Setting and publishing exact throttling limits sounds straightforward, but in fact it would result in more restrictive limits. We continually monitor resource usage on SharePoint Online. Depending on usage, we fine-tune thresholds so users can consume the maximum number of resources without degrading the reliability and performance of SharePoint Online. +Throttled requests count towards usage limits, so failure to honor `Retry-After` may result in more throttling. In other words, aggressive retries work against calling applications because even though the calls fail, they still count toward usage limits. Honoring the `Retry-After` HTTP header will ensure the shortest delay and reduce wasting quotas in throttled requests. -That's why it's so important for your code to honor the `Retry-After` HTTP header value; this lets your code run as fast as possible on any given day, and it lets your code back off "just enough" if it hits throttling limits. The code samples later in this article show you how to use the `Retry-After` HTTP header. +### RateLimit headers - preview -## Search query volume limits when using app-only authentication with Sites.Read.All permission +In addition to the `Retry-After` header in the response to throttled requests, SharePoint Online also returns the [IETF RateLimit headers](https://github.com/ietf-wg-httpapi/ratelimit-headers) for selected limits in certain conditions to help applications manage rate limiting. We recommend applications to take advantage of these headers to avoid hitting the throttle. -In SharePoint and OneDrive, we process multiple billions of documents and enable our customers to issue large query volumes per second. When you are using SharePoint Online search APIs with app-only authentication and the app having `Sites.Read.All` permission (or stronger), the app will be registered with full permissions and is allowed to query all your SharePoint Online content (including user’s private ODB content). +- `RateLimit-Limit` contains the limit in the current time window. +- `RateLimit-Remaining` indicates the remaining quota in the current window. +- `RateLimit-Reset` indicates the number of seconds until the quota is refilled. -We want to let our customers know that SharePoint Online search queries using such permission will be throttled at 25 QPS. The search query will return with a 429 response and you can retry the query after 2 minutes. When waiting for 429 recovery, you should ensure to pause all search query requests you may be making to the service using similar app-only permission. Making additional calls while receiving throttle responses will extend the time it takes for your app to become unthrottled. +> [!NOTE] +> These headers are currently in **beta** and subject to change. At the time when the headers were adopted, the IETF specification was in draft. The current implementation is based on the [draft-03](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers-03) of the IETF specification. There is the potential for changes when the specification is final, and we will adapt to those changes in the future. + +The `RateLimit` headers are returned on a **best-efforts** basis, so applications may not receive the headers under all conditions. Additionally, there are other limits that aren't presented in the `RateLimit` headers, so applications can get throttled even before reaching the limit described in the `RateLimit` headers. +Below is the list of limits that we support the `RateLimit` headers for. The policies and values are subject to change: -As we scale our system, we realize the importance of hardening the system to run it efficiently and also to protect the system and hence this change. This change is expected to roll out to tenants starting Aug into the Fall of 2020. +| limit | Condition | limit value | Description | +|----------------------------|---------------------------|---------------|------------------------------------------------------------------------------------------------------------------| +| App 1-minute resource unit | Usage >= 80% of the limit | Resource unit | When an application consumes 80% or more of its app 1-minute limit, the limit, remaining, and reset are returned.| -## Best practices to handle throttling +Below are some examples to help you understand the `RateLimit` headers: -- Reduce the number of operations per request -- Reduce the frequency of calls -- Choose Microsoft Graph APIs over CSOM and REST APIs when possible -- Decorate your traffic so we know who you are (see section on traffic decoration best practice more on that below) -- Leverage the `Retry-After` HTTP header +- An application has consumed 90% of its resource unit quota (1,080 out of 1,200), and its consumption is within all the limits that apply to it. The request succeeds and the `RateLimit` headers are returned. -Microsoft Graph is cloud born APIs that have the latest improvements and optimizations. In general, Microsoft Graph consumes less resource than CSOM and REST to achieve the same functionality. Hence, adopting Microsoft Graph can improve application's performance and reduce throttling. + ``` + HTTP/1.1 200 Ok + RateLimit-Limit: 1200 + RateLimit-Remaining: 120 + RateLimit-Reset: 5 + ``` -If you do run into throttling, we require leveraging the `Retry-After` HTTP header to ensure minimum delay until the throttle is removed. +- An application has consumed 100% of its resource unit quota, so it gets throttled due to this policy. The request is throttled, and the `RateLimit` headers are returned. The `Retry-After` matches the `RateLimit-Reset`. There are instances where the `Retry-After` returns a smaller value. In such cases, the general rule of thumb is to honor the greater of the two values. -The `Retry-After` HTTP header is the fastest way to handle being throttled because SharePoint Online dynamically determines the right time to try again. In other words, aggressive retries work against you because even though the calls fail, they still accrue against your usage limits. Following the `Retry-After` HTTP header will ensure the shortest delay. + ``` + HTTP/1.1 429 Too Many Requests + Retry-After: 31 + RateLimit-Limit: 1200 + RateLimit-Remaining: 0 + RateLimit-Reset: 31 + ``` -For information about ways to monitor your SharePoint Online activity, see [Diagnosing performance issues with SharePoint Online](https://support.office.com/article/3c364f9e-b9f6-4da4-a792-c8e8c8cd2e86). +- An application has consumed 90% of its resource unit quota, but its consumption has already reached other limits that the `RateLimit` headers don't support. In this case, the request is throttled and the `RateLimit` headers aren't returned to avoid confusion, although the condition to return the headers is satisfied. -For a broader discussion of throttling on the Microsoft Cloud, see [Throttling Pattern](/previous-versions/msp-n-p/dn589798(v=pandp.10)). + ``` + HTTP/1.1 429 Too Many Requests + Retry-After: 9 + ``` -## How to decorate your http traffic to avoid throttling? +Additional information can be found in [Prevent throttling in your application by using RateLimit headers in SharePoint Online](https://devblogs.microsoft.com/microsoft365dev/prevent-throttling-in-your-application-by-using-ratelimit-headers-in-sharepoint-online/) + +### How to decorate your HTTP traffic? -To ensure and maintain high-availability, some traffic may be throttled. Throttling happens when system health is at stake and one of the criteria used for throttling is traffic decoration, which impacts directly on the prioritization of the traffic. Well-decorated traffic will be prioritized over traffic, which isn't properly decorated. +Well-decorated traffic will be prioritized over traffic that isn't properly decorated. -### What is definition of undecorated traffic? +What is the definition of undecorated traffic? -- Traffic is undecorated if there's no AppID/AppTitle and User Agent string in CSOM or REST API call to SharePoint Online. The User Agent string should be in a specific format as described below. +- Traffic is undecorated if there's no AppID/AppTitle and User Agent string in API calls to SharePoint Online. The User-Agent string should be in a specific format as described below. +- If you're developing a web application executing in the browser, most modern browsers don't allow overwriting the User Agent string, and you don't need to implement it. -### What are the recommendations? +What are the recommendations? -- If you've created an application, the recommendation is to register and use AppID and AppTitle – This will ensure the best overall experience and best path for any future issue resolution. Include also the User Agent string information as defined in following step. +- If you've created an application, the recommendation is to register and use AppID and AppTitle – This will ensure the best overall experience and best path for any future issue resolution. Include also the User Agent string information as defined in the following step. > [!NOTE] > Refer to the [Microsoft identity documentation](/azure/active-directory/develop/), such as the [Quickstart: Register an application with the Microsoft identity platform](/azure/active-directory/develop/quickstart-register-app) page, for information on creating an Azure AD application. -- Make sure to include User Agent string in your API call to SharePoint with following naming convention +- Make sure to include the User-Agent string in your API call to SharePoint with the following naming convention | Type | User Agent | Description | -| ---------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| ISV Application | ISV|CompanyName|AppName/Version | Identify as ISV and include Company Name, App Name separated by a pipe character and then adding Version number separated with a slash character | +|------------------------|----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| +| ISV Application | ISV|CompanyName|AppName/Version | Identify as ISV and include Company Name, App Name separated by a pipe character and then add Version number separated with a slash character | | Enterprise application | NONISV|CompanyName|AppName/Version | Identify as NONISV and include Company Name, App Name separated by a pipe character and then adding Version number separated with a slash character | -- If you're building your own JavaScript libraries, which are used to call SharePoint Online APIs, make sure that you include the User Agent information to your http request and potentially register your web application also as an Application, where suitable. +- If you're building your own JavaScript libraries, which are used to call SharePoint Online APIs, make sure that you include the User-Agent information to your HTTP request and potentially register your web application also as an Application, where suitable. > [!NOTE] -> Format of the user agent string is expected to follow [RFC2616](http://www.ietf.org/rfc/rfc2616.txt), so please follow up on the above guidance on the right separators. its also fine to append existing user agent string with the requested information. +> The format of the user agent string is expected to follow [RFC2616](http://www.ietf.org/rfc/rfc2616.txt), so please follow up on the above guidance on the right separators. It is also fine to append the existing user agent string with the requested information. -> [!NOTE] -> If you are developing front end components executing in the browser, most of modern browsers don't allow overwriting the user agent string and you don't need to implement this. - -### Example of decorating traffic with User agent when using Client Side Object Model (CSOM) - -```cs -// Get access to source site -using (var ctx = new ClientContext("https://contoso.sharepoint.com/sites/team")) -{ - //Provide account and pwd for connecting to SharePoint Online - var passWord = new SecureString(); - foreach (char c in pwd.ToCharArray()) passWord.AppendChar(c); - ctx.Credentials = new SharePointOnlineCredentials("contoso@contoso.onmicrosoft.com", passWord); - - // Add our User Agent information - ctx.ExecutingWebRequest += delegate (object sender, WebRequestEventArgs e) - { - e.WebRequestExecutor.WebRequest.UserAgent = "NONISV|Contoso|GovernanceCheck/1.0"; - }; - - // Normal CSOM Call with custom User-Agent information - Web site = ctx.Web; - ctx.Load(site); - ctx.ExecuteQuery(); -} -``` - -### Example of decorating traffic with User agent when using REST APIs - -Following sample is in C# format, but the similar User Agent information is recommended to be used even for the JavaScript libraries used in the SharePoint Online pages. - -```cs -HttpWebRequest endpointRequest = (HttpWebRequest) HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists"); -endpointRequest.Method = "GET"; -endpointRequest.UserAgent = "NONISV|Contoso|GovernanceCheck/1.0"; -endpointRequest.Accept = "application/json;odata=nometadata"; -endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken); -HttpWebResponse endpointResponse = (HttpWebResponse)endpointRequest.GetResponse(); -``` - -### CSOM Code sample: ExecuteQueryWithIncrementalRetry extension method -> [!NOTE] -> You'll need to use SharePoint Online CSOM version 16.1.8316.1200 (December 2018 version) or higher. - -Add this extension method in a static class and use `ExecuteQueryWithIncrementalRetry` instead of `ExecuteQuery` to make your code handle throttling requests. - -```cs -public static void ExecuteQueryWithIncrementalRetry(this ClientContext clientContext, int retryCount, int delay) -{ - int retryAttempts = 0; - int backoffInterval = delay; - int retryAfterInterval = 0; - bool retry = false; - ClientRequestWrapper wrapper = null; - if (retryCount <= 0) - throw new ArgumentException("Provide a retry count greater than zero."); - if (delay <= 0) - throw new ArgumentException("Provide a delay greater than zero."); - - // Do while retry attempt is less than retry count - while (retryAttempts < retryCount) - { - try - { - if (!retry) - { - clientContext.ExecuteQuery(); - return; - } - else - { - //increment the retry count - retryAttempts++; - - // retry the previous request using wrapper - if (wrapper != null && wrapper.Value != null) - { - clientContext.RetryQuery(wrapper.Value); - return; - } - // retry the previous request as normal - else - { - clientContext.ExecuteQuery(); - return; - } - } - } - catch (WebException ex) - { - var response = ex.Response as HttpWebResponse; - // Check if request was throttled - http status code 429 - // Check is request failed due to server unavailable - http status code 503 - if (response != null && (response.StatusCode == (HttpStatusCode)429 || response.StatusCode == (HttpStatusCode)503)) - { - wrapper = (ClientRequestWrapper)ex.Data["ClientRequest"]; - retry = true; - - // Determine the retry after value - use the `Retry-After` header when available - string retryAfterHeader = response.GetResponseHeader("Retry-After"); - if (!string.IsNullOrEmpty(retryAfterHeader)) - { - if (!Int32.TryParse(retryAfterHeader, out retryAfterInterval)) - { - retryAfterInterval = backoffInterval; - } - } - else - { - retryAfterInterval = backoffInterval; - } - - // Delay for the requested seconds - Thread.Sleep(retryAfterInterval * 1000); - - // Increase counters - backoffInterval = backoffInterval * 2; - } - else - { - throw; - } - } - } - throw new MaximumRetryAttemptedException($"Maximum retry attempts {retryCount}, has be attempted."); -} - -[Serializable] -public class MaximumRetryAttemptedException : Exception -{ - public MaximumRetryAttemptedException(string message) : base(message) { } -} -``` +## Common throttling scenarios in SharePoint Online + +The most common causes of per-user throttling in SharePoint Online are client-side object model (CSOM) or Representational State Transfer (REST) code that performs too many actions too frequently. + +- **Sporadic traffic** + + Constant load or repetitive complex queries against SharePoint Online must be optimized for low impact. Failing to follow [best practices for scanning applications](https://aka.ms/ScanGuidance) that process files in bulk will likely result in throttling. These apps include sync engines, backup providers, search indexers, classification engines, data loss prevention tools, and any other tool, that attempts to reason over the entirety of data and apply changes to it. + +- **Overwhelming traffic** + + A single process dramatically exceeds throttling limits, continually, over a long period. + + - You used web services to build a tool to synchronize user profile properties. The tool updates user profile properties based on information from your line-of-business (LOB) human resources (HR) system. The tool makes calls at too high a frequency. + - You're running a load-testing script on SharePoint Online and you get throttled. Load testing isn't allowed on SharePoint Online. + - You customized your team site on SharePoint Online, for example, by adding a status indicator on the Home page. This status indicator updates frequently, which causes the page to make too many calls to the SharePoint Online service - this triggered throttling. + - Running the OneDrive Sync client while also running migration applications or applications that crawl sites and write back data can result in high request volumes that may trigger throttling. + +- **Unsupported use cases** + + Unsupported use of SharePoint Online may result in throttling. Using SharePoint and OneDrive as an intermediary service between Microsoft 365 and another repository is an example of an unsupported use case. + +- **Creating multiple AppIDs for the same application** + + Don't create separate AppIDs where the applications essentially perform the same operations, such as backup or data loss prevention. Applications running against the same tenant ultimately share the same resources as the tenant. Historically, some applications have tried this approach to get around the application throttling but ended up exhausting the tenant’s resource and causing multiple applications to be throttled in the tenant. + +## Scenario specific limits + +### When using app-only authentication with Sites.Read.All permission + +When you're using SharePoint Online search APIs with app-only authentication and the app has **Sites.Read.All** permission (or stronger), the app will be registered with full permissions, and is allowed to query all your SharePoint Online content (including the user’s private OneDrive for Business content). + +To ensure the service remains fast and reliable, queries using such permission are throttled at 25 requests per second. The search query will return an HTTP 429 response. When waiting for throttling recovery, you should ensure to pause all search query requests you may be making to the service using a similar app-only permission. Making more calls while receiving throttle responses will extend the time it takes for your app to become unthrottled. + +### When searching using delegated user permissions + +Searching with delegated user permissions occurs when an application submits a search query request with the signed-in user's permissions. Examples of delegated requests are as follows: the search box on a SharePoint page, a search-based web part or custom application embedded on a SharePoint page, and a Power Automate workflow querying for item information. + +To ensure service stability, the service will throttle delegated user requests that exceed 10 requests per second per user. This per-user limit aggregates across all requests from all apps. If a single user sends more than 10 search query requests per second, an HTTP 429 is returned. The requesting application should wait the duration of the timeout specified in the response header before sending subsequent requests. When designing search-based applications, SharePoint pages, and workflows, implementors should make sure the page and application do not exceed 10 requests per second in aggregate and handle 429 throttling responses. For more information and guidance on page design and search optimization, see [Optimize search requests in SharePoint Online modern site pages](/microsoft-365/enterprise/modern-search-optimization) and [Use the Page Diagnostics tool for SharePoint Online](/microsoft-365/enterprise/page-diagnostics-for-spo). + +### When searching for people search results + +When searching using a result source that requests people results, we may throttle any requests exceeding an organization-wide limit of 25 requests per second. This limit applies to all SharePoint search CSOM and REST requests using either the out-of-the-box "Local People Results" result source or a custom people search result source. + +If you have applications or components that are causing your people search requests to get throttled, we recommend that you: + +1. Consider if the requests are necessary for your application. For example, if you're using a custom search site, that makes many simultaneous queries, check whether some of those requests can be removed without any significant impact on your organization's search experience. Alternatively, consider trying our modern people search experience in [Microsoft Search](/microsoftsearch/get-started-search-in-sharepoint-online) by searching from the [SharePoint](https://sharepoint.com/) start page. People search in Microsoft Search has been optimized for better performance and more relevant results. +1. Avoid making concurrent requests. For example, instead of issuing 10 requests all at once, issue them consecutively - only issue the next query after the previous one has been completed. You may need to consider caching these results if you need them quickly, for example of a page load. +1. Try consolidating the requests into a single query. For example, instead of making 10 simultaneous queries for `WorkEmail:user1@constoso.com`, `WorkEmail:user2@constoso.com`,..., `WorkEmail:user10@contoso.com`, try the single query, `WorkEmail:user1@constoso.com WorkEmail:user2@constoso.com ... WorkEmail:user10@contoso.com`. +1. Consider using the [Microsoft Graph API](/graph/search-concept-person) if a high-request-volume scenario (in excess of 25 requests per second) is truly necessary. + +### When accessing OneDrive sites + +When a client makes excessive attempts to access many OneDrive site collections that do not exist, we may throttle requests from that client's IP address. The client will receive an HTTP 429 response when accessing any OneDrive site collection during the throttling period. + +### Multi-Geo Customers and throttling + +When a customer enables throttling, each gets their own limits (usage measurement not shared across geos). For the limits that are dependant on licenses count, the total tenant user licenses count is used (total users across all geos). ## What should you do if you get blocked in SharePoint Online? -Blocking is the most extreme form of throttling. We rarely ever block a tenant, unless we detect long-term, excessive traffic that may threaten the overall health of the SharePoint Online service. We apply blocks to prevent excessive traffic from degrading the performance and reliability of SharePoint Online. A block - which is placed at the app or user level - prevents the offending process from running until you fix the problem. If we block your subscription, you must take action to modify the offending processes before the block can be removed. +Blocking is the most extreme form of throttling. We rarely ever block a tenant unless we detect long-term, excessive traffic that may threaten the overall health of the SharePoint Online service. We apply blocks to prevent excessive traffic from degrading the performance and reliability of SharePoint Online. A block - which is placed at the app or user level - prevents the offending process from running until you fix the problem. If we block your subscription, you must take action to modify the offending processes before the block can be removed. -If we block your subscription, we will notify you of the block in the Office 365 Message Center. The message describes what caused the block, provides guidance on how to resolve the offending issue, and tells you who to contact to get the block removed. +If we block your subscription, we'll notify you of the block in the Office 365 Message Center. The message describes what caused the block, provides guidance on how to resolve the offending issue, and tells you who to contact to get the block removed. ## See also +- [Service Prioritization in SharePoint](https://aka.ms/SharePointPrioritization) - [Diagnosing performance issues with SharePoint Online](https://support.office.com/article/3c364f9e-b9f6-4da4-a792-c8e8c8cd2e86) - [Capacity planning and load testing SharePoint Online](https://support.office.com/article/capacity-planning-and-load-testing-sharepoint-online-c932bd9b-fb9a-47ab-a330-6979d03688c0) +- [Microsoft Graph dev center](/graph) +- [Microsoft Graph throttling guidance](/graph/throttling) +- [Prevent throttling in your application by using RateLimit headers in SharePoint Online](https://devblogs.microsoft.com/microsoft365dev/prevent-throttling-in-your-application-by-using-ratelimit-headers-in-sharepoint-online/) +- [Four options for site analytics](https://techcommunity.microsoft.com/blog/microsoft_graph_data_connect_for_sharepo/four-options-for-sharepoint-site-analytics/4076416) diff --git a/docs/general-development/how-to-back-up-and-restore-a-search-service-application-in-sharepoint-using.md b/docs/general-development/how-to-back-up-and-restore-a-search-service-application-in-sharepoint-using.md index 909b472f7..818bbb861 100644 --- a/docs/general-development/how-to-back-up-and-restore-a-search-service-application-in-sharepoint-using.md +++ b/docs/general-development/how-to-back-up-and-restore-a-search-service-application-in-sharepoint-using.md @@ -1,9 +1,9 @@ --- title: Back up and restore a search service application in SharePoint using VSS -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to back up and restore a search service application in SharePoint using VSS and provides prerequisites and steps. +ms.date: 06/09/2022 ms.assetid: 87ee28e6-8170-4dba-8c9d-f04ab9e632dc -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/how-to-back-up-and-restore-sharepoint-using-a-vss-requestor.md b/docs/general-development/how-to-back-up-and-restore-sharepoint-using-a-vss-requestor.md index 9feefdf56..045f47664 100644 --- a/docs/general-development/how-to-back-up-and-restore-sharepoint-using-a-vss-requestor.md +++ b/docs/general-development/how-to-back-up-and-restore-sharepoint-using-a-vss-requestor.md @@ -1,9 +1,9 @@ --- title: Back up and restore SharePoint using a VSS requestor -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to back up and restore using a Volume Shadow Copy Service (VSS) requestor for Microsoft SharePoint. +ms.date: 06/09/2022 ms.assetid: cab5ba90-bd23-4cec-82d7-529e3f86ba88 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/how-to-brand-snippets-by-using-css-in-sharepoint.md b/docs/general-development/how-to-brand-snippets-by-using-css-in-sharepoint.md index ff2df2fb8..b72aa8ae3 100644 --- a/docs/general-development/how-to-brand-snippets-by-using-css-in-sharepoint.md +++ b/docs/general-development/how-to-brand-snippets-by-using-css-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Brand snippets by using CSS in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to style snippets by using CSS in SharePoint and provides example snippets with instructions on how to use them. +ms.date: 06/09/2022 ms.assetid: d18d07b6-1a6b-4589-a65c-932b67cef595 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/how-to-build-and-deploy-workflow-custom-actions.md b/docs/general-development/how-to-build-and-deploy-workflow-custom-actions.md index 413ca4d87..290823cc4 100644 --- a/docs/general-development/how-to-build-and-deploy-workflow-custom-actions.md +++ b/docs/general-development/how-to-build-and-deploy-workflow-custom-actions.md @@ -1,9 +1,9 @@ --- title: Build and deploy workflow custom actions -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to create custom workflow actions in SharePoint and provides an example that creates, packages, and deploys a custom activity. +ms.date: 06/09/2022 ms.assetid: 9d2fa681-30c2-4549-9df2-ea9ed757fda9 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/how-to-build-search-driven-mobile-apps-with-the-navigation-and-event-logging-res.md b/docs/general-development/how-to-build-search-driven-mobile-apps-with-the-navigation-and-event-logging-res.md index 80eb41f0c..a24fee190 100644 --- a/docs/general-development/how-to-build-search-driven-mobile-apps-with-the-navigation-and-event-logging-res.md +++ b/docs/general-development/how-to-build-search-driven-mobile-apps-with-the-navigation-and-event-logging-res.md @@ -1,9 +1,9 @@ --- title: Build search-driven mobile apps with the Navigation and Event Logging REST interfaces -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to build search-driven mobile apps for mobile devices that run on non-Windows operating systems. +ms.date: 06/09/2022 ms.assetid: 5b313130-500c-4ccf-80ea-b102f30e5afb -localization_priority: Normal +ms.localizationpriority: medium --- @@ -50,7 +50,7 @@ Typically the **Home** page is displayed when the app starts up. The **Home** pa -![Build search-driven mobile apps](../images/SP15_Buildsearch-drivenmobileappspages_home.gif) +![Diagram that shows the Mobile App communicating with a REST navigation HTTP call to Share Point, which gives a Navigation structure response back.](../images/SP15_Buildsearch-drivenmobileappspages_home.gif) @@ -92,7 +92,7 @@ The **Category** page displays many items in a selected category. Each item list -![Build search-driven mobile apps](../images/Buildsearch-drivenmobileappspages.gif) +![Diagram that shows the Mobile App communicating with a REST search query to Share Point, which gives the search results back.](../images/Buildsearch-drivenmobileappspages.gif) diff --git a/docs/general-development/how-to-catch-exceptions.md b/docs/general-development/how-to-catch-exceptions.md index 0211a16cb..e49b400fd 100644 --- a/docs/general-development/how-to-catch-exceptions.md +++ b/docs/general-development/how-to-catch-exceptions.md @@ -1,12 +1,12 @@ --- title: Catch exceptions +description: You place the sections of code that might throw exceptions in a try block and place code that handles exceptions in a catch block. The order of catch statements is important. When an exception occurs, it is passed up the stack and each catch block is given the opportunity to handle it. ms.date: 09/25/2017 keywords: errors,how to,howdoi,howto f1_keywords: - errors,how to,howdoi,howto -ms.prod: sharepoint ms.assetid: de5fdb67-201b-4d7a-90a8-99ab7e51ea4e -localization_priority: Normal +ms.localizationpriority: medium --- @@ -18,7 +18,7 @@ You place the sections of code that might throw exceptions in a try block and pl -```cs +```csharp catch (SoapException e) { @@ -41,7 +41,7 @@ End Try If no type-specific catch block exists, the exception is caught by a general catch block, if one exists. For example, you can catch general exceptions by adding the following code: -```cs +```csharp catch (Exception e) { @@ -63,7 +63,7 @@ You place catch blocks targeted to specific types of exceptions before a general ## Example -```cs +```csharp using System; using System.Text; diff --git a/docs/general-development/how-to-change-the-preview-page-in-sharepoint-design-manager.md b/docs/general-development/how-to-change-the-preview-page-in-sharepoint-design-manager.md index fa060d93e..9e0aa988f 100644 --- a/docs/general-development/how-to-change-the-preview-page-in-sharepoint-design-manager.md +++ b/docs/general-development/how-to-change-the-preview-page-in-sharepoint-design-manager.md @@ -1,9 +1,9 @@ --- title: Change the preview page in SharePoint Design Manager -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to set, create, and change the preview page in Design Manager in SharePoint, and provides additional resources. +ms.date: 06/09/2022 ms.assetid: e5dfd8df-65de-44fc-aa97-23b4685d33ee -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/how-to-configure-and-use-push-notifications-in-sharepoint-apps-for-windows.md b/docs/general-development/how-to-configure-and-use-push-notifications-in-sharepoint-apps-for-windows.md index 9ed489183..34bc54174 100644 --- a/docs/general-development/how-to-configure-and-use-push-notifications-in-sharepoint-apps-for-windows.md +++ b/docs/general-development/how-to-configure-and-use-push-notifications-in-sharepoint-apps-for-windows.md @@ -1,10 +1,9 @@ --- title: Configure and use push notifications in SharePoint apps for Windows Phone description: Create a solution in SharePoint Server for sending push notifications and develop a Windows Phone app for receiving the notifications. -ms.date: 12/22/2020 -ms.prod: sharepoint +ms.date: 06/09/2022 ms.assetid: 68fa2138-86d9-4e35-9c7c-5cd292087b80 -localization_priority: Normal +ms.localizationpriority: medium --- # Configure and use push notifications in SharePoint apps for Windows Phone @@ -1130,5 +1129,5 @@ When you add an item to the Jobs SharePoint list, the code in the event receiver - [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md) - [Windows Phone SDK 8.0](https://www.microsoft.com/download/details.aspx?id=35471) - [Microsoft SharePoint SDK for Windows Phone 8](https://www.microsoft.com/download/details.aspx?id=36818) -- [Windows Phone SDK 7.1](https://www.microsoft.com/download/details.aspx?id=27570) +- [Windows Phone SDK 7.1](https://www.microsoft.com/download/details.aspx?id=29233) - [Microsoft SharePoint SDK for Windows Phone 7.1](https://www.microsoft.com/download/details.aspx?id=30476) diff --git a/docs/general-development/how-to-configure-item-level-security-in-sharepoint.md b/docs/general-development/how-to-configure-item-level-security-in-sharepoint.md index 6b9ad6ff3..f8e5ffc5c 100644 --- a/docs/general-development/how-to-configure-item-level-security-in-sharepoint.md +++ b/docs/general-development/how-to-configure-item-level-security-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Configure item-level security in SharePoint +description: Learn how to configure item level security when crawling external data with BCS indexing connectors in SharePoint. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: ffd730f2-e7b7-4707-b677-d073da7df7d7 -localization_priority: Normal +ms.localizationpriority: medium --- @@ -139,7 +139,7 @@ The following code is the method signature for the method that is specified in t -```cs +```csharp Public static Byte[]GetItemSecurity (string id) { @@ -156,7 +156,7 @@ If the external system does not support NTLM authentication, but the external sy -```cs +```csharp /// Returns the security descriptor for a user. /// diff --git a/docs/general-development/how-to-configure-msmq-for-sharepoint-workflows.md b/docs/general-development/how-to-configure-msmq-for-sharepoint-workflows.md index f99368596..42a103338 100644 --- a/docs/general-development/how-to-configure-msmq-for-sharepoint-workflows.md +++ b/docs/general-development/how-to-configure-msmq-for-sharepoint-workflows.md @@ -1,9 +1,9 @@ --- title: Configure MSMQ for SharePoint workflows -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to configure Microsoft Message Queuing (MSMQ) for asynchronous event messaging in SharePoint workflows. +ms.date: 06/09/2022 ms.assetid: c0e130f6-c210-44ea-83ed-b327f04551d6 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/how-to-convert-an-add-in-scoped-external-content-type-to-tenant-scoped.md b/docs/general-development/how-to-convert-an-add-in-scoped-external-content-type-to-tenant-scoped.md index f67e033fa..6356260f8 100644 --- a/docs/general-development/how-to-convert-an-add-in-scoped-external-content-type-to-tenant-scoped.md +++ b/docs/general-development/how-to-convert-an-add-in-scoped-external-content-type-to-tenant-scoped.md @@ -1,9 +1,9 @@ --- title: Convert an add-in-scoped external content type to tenant-scoped -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to create an OData-based external content type using Visual Studio 2012 and import it into the BCS metadata store. +ms.date: 06/09/2022 ms.assetid: 35c5d670-e402-4641-b3c5-6f61ae1ec69b -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/how-to-convert-an-html-file-into-a-master-page-in-sharepoint.md b/docs/general-development/how-to-convert-an-html-file-into-a-master-page-in-sharepoint.md index 04bfe4ada..b5b31ff91 100644 --- a/docs/general-development/how-to-convert-an-html-file-into-a-master-page-in-sharepoint.md +++ b/docs/general-development/how-to-convert-an-html-file-into-a-master-page-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Convert an .html file into a master page in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to convert an .html into a SharePoint master page .master file and provides steps and code examples. +ms.date: 06/09/2022 ms.assetid: a76ab289-3256-45de-ac63-d5112a74e3c7 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/how-to-crawl-associated-external-content-types-in-sharepoint.md b/docs/general-development/how-to-crawl-associated-external-content-types-in-sharepoint.md index d944b9baa..5ad7dcbe7 100644 --- a/docs/general-development/how-to-crawl-associated-external-content-types-in-sharepoint.md +++ b/docs/general-development/how-to-crawl-associated-external-content-types-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Crawl associated external content types in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to use the search properties in the Business Data Connectivity (BDC) service metadata model for crawling associations. +ms.date: 06/09/2022 ms.assetid: 187ec42e-f749-4e22-abef-1df604143063 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/how-to-crawl-binary-large-objects-blobs-in-sharepoint.md b/docs/general-development/how-to-crawl-binary-large-objects-blobs-in-sharepoint.md index 9ff908486..ba87852cd 100644 --- a/docs/general-development/how-to-crawl-binary-large-objects-blobs-in-sharepoint.md +++ b/docs/general-development/how-to-crawl-binary-large-objects-blobs-in-sharepoint.md @@ -2,9 +2,8 @@ title: Crawl binary large objects (BLOBs) in SharePoint description: Learn how to modify the BDC model file for a database BCS indexing connector to enable the Search in SharePoint crawler to crawl binary large object (BLOB) data stored in a SQL Server database. ms.date: 12/22/2020 -ms.prod: sharepoint ms.assetid: 99b3dd51-1651-4300-a2de-33681f4cc258 -localization_priority: Normal +ms.localizationpriority: medium --- # Crawl binary large objects (BLOBs) in SharePoint diff --git a/docs/general-development/how-to-create-a-claims-provider-in-sharepoint.md b/docs/general-development/how-to-create-a-claims-provider-in-sharepoint.md index 9b1e82d88..9efdab73d 100644 --- a/docs/general-development/how-to-create-a-claims-provider-in-sharepoint.md +++ b/docs/general-development/how-to-create-a-claims-provider-in-sharepoint.md @@ -1,67 +1,68 @@ --- title: Create a claims provider in SharePoint +description: Learn how to create and implement a SharePoint claims provider that fulfills the requirements for claims augmentation and claims picking. ms.date: 09/25/2017 -ms.prod: sharepoint ms.assetid: 8f3228ca-57fd-4253-a07d-abeb63298c58 -localization_priority: Normal +ms.localizationpriority: medium --- # Create a claims provider in SharePoint Learn how to create and implement a SharePoint claims provider that fulfills the requirements for claims augmentation and claims picking. + A claims provider issues claims and packages claims into security tokens. A claims provider has two roles: augmentation and picking. - - - + + + Claims augmentation enables an application to augment additional claims into the user's token. For example, with Windows-based log-in, the Active Directory directory service can augment all of a user's security groups into the user's Windows token. With claims-based log-in, a customer relationship management (CRM) application can augment roles from a CRM database. By having these claims in the user's token, resources can be authorized against these claims. That is, these claims are used to determine whether a particular user has access to specific resources. Claims can be displayed in the people picker control through claims picking. Claims picking enables an application to surface claims in the people picker, for example, when configuring the security of a SharePoint site or SharePoint service. This functionality enables you to provide search, resolve, and friendly display of claims. - + > [!NOTE] -> A people picker with claims picking functionality is sometimes referred to as a claims picker. For more information, see [People picker and claims provider planning](https://technet.microsoft.com/library/gg602063.aspx). - - - +> A people picker with claims picking functionality is sometimes referred to as a claims picker. For more information, see [People picker and claims provider planning](https://technet.microsoft.com/library/gg602063.aspx). + + + To write a claims provider, your first step is to create a class that derives from the **SPClaimProvider** class. > **Tip:** -> For a code example and more information about the **SPClaimProvider** class and its members, see [SPClaimProvider](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.aspx) . For walkthroughs, tips, and code samples, see [Claims and Security: Technical articles and code samples on MSDN](https://msdn.microsoft.com/library/f773fd4a-53ec-4656-bd08-e6c435e6f103%28Office.15%29.aspx). - - - +> For a code example and more information about the **SPClaimProvider** class and its members, see [SPClaimProvider](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.aspx) . For walkthroughs, tips, and code samples, see [Claims and Security: Technical articles and code samples on MSDN](https://msdn.microsoft.com/library/f773fd4a-53ec-4656-bd08-e6c435e6f103%28Office.15%29.aspx). + + + ## Required implementations The following are required methods and properties when writing a claims provider. - - - + + + ### Required The following [Name](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.Name.aspx) property is a required property. The name should be unique across the farm. - - - -```cs + + + +```csharp public abstract String Name - + ``` ### Required for claims picker Claims can be displayed in the people picker control through claims picking. The following methods in the [SPClaimProvider](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.aspx) class are required methods if you want to implement claim picking in the people picker control. - - - -```cs + + + +```csharp protected abstract void FillSchema(SPProviderSchema schema); protected abstract void FillClaimTypes(List claimTypes); @@ -74,11 +75,11 @@ protected abstract void FillSchema(SPProviderSchema schema); ### Required for claims augmentation When you include additional claims in a user's security token, you are augmenting claims. If you want to augment claims, you must implement the following methods in the [SPClaimProvider](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.aspx) class. - - - -```cs + + + +```csharp public abstract bool SupportsEntityInformation protected abstract void FillClaimsForEntity(Uri context, SPClaim entity, List claims); @@ -89,11 +90,11 @@ public abstract bool SupportsEntityInformation ### Required for displaying hierarchy on the left pane of the claims picker If you want to display hierarchy on the left pane of the claims picker, you must implement the following methods in the [SPClaimProvider](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.aspx) class. - - - -```cs + + + +```csharp public abstract bool SupportsHierarchy protected abstract void FillHierarchy(Uri context, String[] entityTypes, String hierarchyNodeID, int numberOfLevels, bool includeEntityData, SPProviderHierarchyTree hierarchy); @@ -104,11 +105,11 @@ public abstract bool SupportsHierarchy ### Required for resolving claims in the type-in control of the claims picker If you want to be able to resolve claims by using the type-in control of the claims picker, you must implement the following methods in the [SPClaimProvider](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.aspx) class. - - - -```cs + + + +```csharp public abstract bool SupportsResolve protected abstract void FillResolve(Uri context, String[] entityTypes, String resolveInput, List resolved); @@ -120,11 +121,11 @@ public abstract bool SupportsResolve ### Required for searching for claims in the claims picker If you want to be able to search for claims in the claims picker, you must implement the following property and method in the [SPClaimProvider](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaimProvider.aspx) class. - - - -```cs + + + +```csharp public abstract bool SupportsSearch protected abstract void FillSearch(Uri context, String[] entityTypes, String searchPattern, String hierarchyNodeID, int maxCount, SPProviderHierarchyTree searchTree); @@ -136,18 +137,18 @@ public abstract bool SupportsSearch You can also implement a helper method to help you create [SPClaim](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaim.aspx) objects. - - - + + + ### Useful helper method for creating SPClaim objects The following is a helper method that you can implement to help you create [SPClaim](https://msdn.microsoft.com/library/Microsoft.SharePoint.Administration.Claims.SPClaim.aspx) objects. - - - -```cs + + + +```csharp protected SPClaim CreateClaim(String claimType, String value, String valueType) ``` @@ -158,15 +159,15 @@ protected SPClaim CreateClaim(String claimType, String value, String valueType) - [Claims-based identity in SharePoint](claims-based-identity-in-sharepoint.md) - - + + - [Incoming claims: Signing into SharePoint](incoming-claims-signing-into-sharepoint.md) - - + + - [Claims provider in SharePoint](claims-provider-in-sharepoint.md) - - + + - [How to: Deploy a claims provider in SharePoint](how-to-deploy-a-claims-provider-in-sharepoint.md) - - + + diff --git a/docs/general-development/how-to-create-a-mashup-that-uses-an-embedded-workbook-and-bing-maps.md b/docs/general-development/how-to-create-a-mashup-that-uses-an-embedded-workbook-and-bing-maps.md index 0f0d50bdf..52c8d32d9 100644 --- a/docs/general-development/how-to-create-a-mashup-that-uses-an-embedded-workbook-and-bing-maps.md +++ b/docs/general-development/how-to-create-a-mashup-that-uses-an-embedded-workbook-and-bing-maps.md @@ -2,9 +2,8 @@ title: Create a mashup that uses an embedded workbook and Bing Maps description: This article walks you through a powerful Web-based mashup that combines an embedded Excel workbook and Bing Maps. ms.date: 12/22/2020 -ms.prod: sharepoint ms.assetid: 3cfeb8d7-84b8-4673-bc92-b176cba4ac3e -localization_priority: Normal +ms.localizationpriority: medium --- # Create a mashup that uses an embedded workbook and Bing Maps diff --git a/docs/general-development/how-to-create-a-master-page-preview-file-in-sharepoint.md b/docs/general-development/how-to-create-a-master-page-preview-file-in-sharepoint.md index 5849b037f..6706a4a0b 100644 --- a/docs/general-development/how-to-create-a-master-page-preview-file-in-sharepoint.md +++ b/docs/general-development/how-to-create-a-master-page-preview-file-in-sharepoint.md @@ -2,9 +2,8 @@ title: Create a master page preview file in SharePoint description: Learn how to create master page preview files that are used in the SharePoint theming experience to display a preview of selected theme components. ms.date: 01/06/2021 -ms.prod: sharepoint ms.assetid: 6825518d-eeb2-40b0-8a5b-897025f13796 -localization_priority: Normal +ms.localizationpriority: medium --- # Create a master page preview file in SharePoint diff --git a/docs/general-development/how-to-create-a-minimal-master-page-in-sharepoint.md b/docs/general-development/how-to-create-a-minimal-master-page-in-sharepoint.md index 919eebf0b..b0cb20c99 100644 --- a/docs/general-development/how-to-create-a-minimal-master-page-in-sharepoint.md +++ b/docs/general-development/how-to-create-a-minimal-master-page-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Create a minimal master page in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to create a minimal master page in SharePoint, which contains only elements that SharePoint requires to render the page. +ms.date: 06/09/2022 ms.assetid: 634aa471-07e1-41d6-aa80-27f7ef7e9dc8 -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/general-development/how-to-create-a-mobile-app-in-sharepoint-that-contains-data-from-an-externa.md b/docs/general-development/how-to-create-a-mobile-app-in-sharepoint-that-contains-data-from-an-externa.md index e1220d8f0..1bd7f6084 100644 --- a/docs/general-development/how-to-create-a-mobile-app-in-sharepoint-that-contains-data-from-an-externa.md +++ b/docs/general-development/how-to-create-a-mobile-app-in-sharepoint-that-contains-data-from-an-externa.md @@ -1,9 +1,9 @@ --- title: Create a mobile app in SharePoint that contains data from an external data source -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to create a mobile app in SharePoint that contains data from an external data source by using Business Connectivity Services. +ms.date: 06/09/2022 ms.assetid: f1d62256-aca0-4a59-8145-0add9e68a449 -localization_priority: Normal +ms.localizationpriority: medium --- @@ -287,7 +287,7 @@ Now that the app is ready to run, you can test it using phone emulator. - [How to: Set up an environment for developing mobile apps for SharePoint](how-to-set-up-an-environment-for-developing-mobile-apps-for-sharepoint.md) -- [Windows Phone SDK 7.1](https://www.microsoft.com/download/details.aspx?id=27570) +- [Windows Phone SDK 7.1](https://www.microsoft.com/download/details.aspx?id=29233) - [Microsoft SharePoint SDK for Windows Phone 7.1](https://www.microsoft.com/download/details.aspx?id=30476) diff --git a/docs/general-development/how-to-create-a-page-layout-in-sharepoint.md b/docs/general-development/how-to-create-a-page-layout-in-sharepoint.md index 4f59d95e6..7b226bd53 100644 --- a/docs/general-development/how-to-create-a-page-layout-in-sharepoint.md +++ b/docs/general-development/how-to-create-a-page-layout-in-sharepoint.md @@ -1,9 +1,9 @@ --- title: Create a page layout in SharePoint -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Describes how to create a page layout using Design Manager in SharePoint and provides steps and code examples. +ms.date: 06/09/2022 ms.assetid: 5447e6a1-2f14-4667-81d0-7514b468be80 -localization_priority: Priority +ms.localizationpriority: high --- @@ -98,7 +98,7 @@ If you're using Design Manager to create page layouts and master pages, the most - **PlaceHolderMain** The master page contains a content placeholder with `ID="PlaceholderMain"`, which contains the **DefaultContentBlock** `
    ` tag with the yellow box that shows **This area will be filled in by content you create in your page layouts.** You should not put any content inside this placeholder on the master page. The page layout contains a content placeholder with the same ID. You should put markup only inside this placeholder, and put no markup outside this placeholder, on a page layout. The IDs for the two placeholders ( **PlaceholderMain**) should match. -- **PlaceHolderAdditionalPageHead** When you work with a page layout, you typically don't insert elements into the **** tag of the page layout. Instead, you add elements to the content placeholder with `id="PlaceHolderAdditionalPageHead"`. When a content page is rendered in the browser, this additional page head gets merged into the end of the head of the master page. +- **PlaceHolderAdditionalPageHead** When you work with a page layout, you typically don't insert elements into the `` tag of the page layout. Instead, you add elements to the content placeholder with `id="PlaceHolderAdditionalPageHead"`. When a content page is rendered in the browser, this additional page head gets merged into the end of the head of the master page. @@ -184,7 +184,7 @@ When you create HTML mockups for your site, you may have HTML files that represe -You can simply put the styles for one or more page layouts into the same style sheet that the master page links to. But, if you want to minimize the weight of the CSS that is loaded per page, you can also use different style sheets for different page layouts. When you do this, it's important to know that a link to a style sheet cannot go in the **** tag of a page layout. Instead, the link must go in the content placeholder named **PlaceHolderAdditionalPageHead**. +You can simply put the styles for one or more page layouts into the same style sheet that the master page links to. But, if you want to minimize the weight of the CSS that is loaded per page, you can also use different style sheets for different page layouts. When you do this, it's important to know that a link to a style sheet cannot go in the `` tag of a page layout. Instead, the link must go in the content placeholder named **PlaceHolderAdditionalPageHead**. > [!NOTE] > In this markup, the attribute `ms-design-css-conversion="no"` excludes the style sheet from theming. Also, the link to the style sheet should appear after the lines commented ** - + - - ``` - ### Create a workflow -Now we create a workflow so we can test the custom site column and content type. - - - - -1. Add a workflow to our project configure it to be a list workflow. - - -2. Create an association with this workflow using the **Announcements** list that we created earlier. - - -3. Create a new variable of type **DynamicValue** and name it "ItemProperties"; we are going to use this variable to store the item that kicks off the workflow's properties. - - -4. Create an **Int32** variable and name it "ItemAuthorId", as shown in Figure 15. - - **Figure 15. Creating a workflow variable** - - +Now we create a workflow so we can test the custom site column and content type. - ![WorkingWithTasksSharePointWorkflowsFig15](../images/WorkingWithTasksSharePointWorkflowsFig15.png) - +1. Add a workflow to our project and configure it to be a list workflow. +1. Create an association with this workflow using the **Announcements** list that we created earlier. +1. Create a new variable of type **DynamicValue** and name it "ItemProperties"; we're going to use this variable to store the item that kicks off the workflow's properties. +1. Create an **Int32** variable and name it "ItemAuthorId", as shown in Figure 15. - - - + **Figure 15. Creating a workflow variable** + ![The screenshot shows how to create an Int32 variable and name it "ItemAuthorId".](../images/WorkingWithTasksSharePointWorkflowsFig15.png) ### Collect the list item properties Now we collect the list item properties. - - - - -1. Drop the **LookupSPListItem** activity onto the design surface and set the **ListID** property to _(current list)_ and the **ItemId** property to _(current item)_. - - -2. Now set the **Result** output to the **ItemProperties** **DynamicValue** variable that we created a moment ago. - - -3. To get the author of the item from the variable, click the **Get Properties** link in the **LookupSPListItem** activity and add a **GetDynamicValueProperties** activity on the design surface. - - -4. Set the item's **Source** property to the output of the **LookupSPListItem** activity automatically. - - -5. Click the **[???]** button on the **Properties** property to display the **Properties** dialog box. - - -6. Change the **Entity Type** to **List Item of Announcements** to give the dialog box a context and assign the **Created By** path to the variable **ItemAuthorId**, as shown in Figure 16. - - **Figure 16. Properties dialog** - - - - ![WorkingWithTasksSharePointWorkflowsFig16](../images/WorkingWithTasksSharePointWorkflowsFig16.png) - - - - - - -### Create a single task -Now we can create the single task. - - - - -1. Add a **SingleTask** activity to the design surface. - - -2. Click the **Configure** link in the activity to open the **Task Options** dialog box. - - -3. Set the **Body** field to some string (it doesn't matter what), then set the **Assigned To** property to the variable you are using to store the author identifier (in our case, **ItemAuthorId**). - - -4. Change the title of the task, as shown in Figure 17. - - **Figure 17. Task Title setting** +1. Drop the **LookupSPListItem** activity onto the design surface and set the **ListID** property to _(current list)_ and the **ItemId** property to _(current item)_. +1. Now set the **Result** output to the **ItemProperties** **DynamicValue** variable that we created a moment ago. +1. To get the author of the item from the variable, select the **Get Properties** link in the **LookupSPListItem** activity and add a **GetDynamicValueProperties** activity on the design surface. +1. Set the item's **Source** property to the output of the **LookupSPListItem** activity automatically. +1. Select the **[???]** button on the **Properties** property to display the **Properties** dialog box. +1. Change the **Entity Type** to **List Item of Announcements** to give the dialog box a context and assign the **Created By** path to the variable **ItemAuthorId**, as shown in Figure 16. - + **Figure 16. Properties dialog** + ![The screenshot shows how to change the Entity Type to List Item of Announcements](../images/WorkingWithTasksSharePointWorkflowsFig16.png) - ![WorkingWithTasksSharePointWorkflowsFig17](../images/WorkingWithTasksSharePointWorkflowsFig17.png) - - - +### Create a single task - -5. Finally, set the **Outcome Options** to use the new custom content type and custom outcome column. - - The dialog box determines what is available by looking at all the content types that are derived from the **Workflow Task (SharePoint)** content type, as shown in Figure 18. - +Now we can create the single task. - **Figure 18. Outcome Options settings** +1. Add a **SingleTask** activity to the design surface. +1. Select the **Configure** link in the activity to open the **Task Options** dialog box. +1. Set the **Body** field to some string (it doesn't matter what), then set the **Assigned To** property to the variable you're using to store the author identifier (in our case, **ItemAuthorId**). +1. Change the title of the task, as shown in Figure 17. - + **Figure 17. Task Title setting** + ![The screenshot shows how to change the title of the task.](../images/WorkingWithTasksSharePointWorkflowsFig17.png) - ![WorkingWithTasksSharePointWorkflowsFig18](../images/WorkingWithTasksSharePointWorkflowsFig18.png) - +1. Finally, set the **Outcome Options** to use the new custom content type and custom outcome column. - + The dialog box determines what is available by looking at all the content types that are derived from the **Workflow Task (SharePoint 2013)** content type, as shown in Figure 18. - + **Figure 18. Outcome Options settings** + ![The screenshot shows that the dialog box determines what is available by looking at all the content types that are derived from the Workflow Task content type.](../images/WorkingWithTasksSharePointWorkflowsFig18.png) ### Update the AssignedTo field -Before we go any further, we need to update the **AssignedTo** field on the **SingleTask** activity because it is expecting a string, not an integer. To remedy this, add **ToString()** to the end of the expression. - - - +Before we go any further, we need to update the **AssignedTo** field on the **SingleTask** activity because it's expecting a string, not an integer. To remedy this, add **ToString()** to the end of the expression. + Also, notice that the **Outcome** property automatically created a variable named **outcome_0**. To see what is in this variable, add a **WriteToHistory** activity on the design surface and update the message to write out the result. - - - ### Update the workflow task list -The final step is to configure the workflow task list. By default, the task list that the app creates only accepts the content type **Workflow Task (SharePoint)**. This workflow uses a custom content type for the custom outcome. Open the `Elements.xml` file for the workflow task list and change the **** element's **ContentTypeId** attribute to match the content type in the project, as shown in the code example following. - - - +The final step is to configure the workflow task list. By default, the task list that the app creates only accepts the content type **Workflow Task (SharePoint 2013)**. This workflow uses a custom content type for the custom outcome. Open the `Elements.xml` file for the workflow task list and change the **\** element's **ContentTypeId** attribute to match the content type in the project, as shown in the code example following. ```XML - - - ``` - ### Test the custom content task with a custom task outcome -Now let's test the workflow. - - - - -1. In Visual Studio 2012, press **F5** or click the **Start** button. If testing in an on-premises local install of SharePoint, Visual Studio 2012 will start the Workflow Manager Test Service Host utility and deploy the workflow to the developer site. After a moment, the developer site will open. - - -2. Navigate to the **Announcements** list and create a new item. After creating the item, start the custom workflow manually. - - -3. Next, return to the workflow instance's status page to find the task that was created by the workflow. - - -4. Click on the task and, using the **Edit** button in the ribbon, switch to edit mode. At the bottom of the form there should be four buttons. The first two buttons are the custom outcome buttons that, when pressed, will mark the task as complete. The second two buttons are the default **Save** and **Cancel** buttons that simply update the list item without completing the task, as shown in Figure 19. - - **Figure 19. Custom outcome buttons** - - +Now let's test the workflow. - ![WorkingWithTasksSharePointWorkflowsFig19](../images/WorkingWithTasksSharePointWorkflowsFig.png) - +1. In Visual Studio, press **F5** or select the **Start** button. If testing in an on-premises local install of SharePoint, Visual Studio will start the Workflow Manager Test Service Host utility and deploy the workflow to the developer site. After a moment, the developer site will open. +1. Navigate to the **Announcements** list and create a new item. After creating the item, start the custom workflow manually. +1. Next, return to the workflow instance's status page to find the task that was created by the workflow. +1. Select on the task and, using the **Edit** button in the ribbon, switch to edit mode. At the bottom of the form there should be four buttons. The first two buttons are the custom outcome buttons that, when pressed, will mark the task as complete. The second two buttons are the default **Save** and **Cancel** buttons that simply update the list item without completing the task, as shown in Figure 19. - - - + **Figure 19. Custom outcome buttons** + ![The screenshot shows that the second two buttons are the default Save and Cancel buttons that simply update the list item without completing the task.](../images/WorkingWithTasksSharePointWorkflowsFig.png) ## Conclusion -Microsoft introduced workflows into the SharePoint 2007 platform, and they remained mostly unchanged in SharePoint 2010 in architecture, implementation, or process. This was also true for tasks in SharePoint workflows. However, SharePoint has introduced many changes to workflows in architecture and implementation. - - - -This article discussed the changes related to workflow tasks that were driven from changes to the workflow story in SharePoint. It demonstrated how to create a simple workflow that leveraged tasks in SharePoint using Visual Studio 2012. These types of tasks are suitable for many developers, although at times custom tasks and custom outcomes are desired, which can be accomplished using Visual Studio 2012 as has been shown. - - - - -## See also - +Microsoft introduced workflows into the SharePoint Server 2007 platform, and they remained mostly unchanged in SharePoint Server 2010 in architecture, implementation, or process. This was also true for tasks in SharePoint workflows. However, SharePoint Server 2013 has introduced many changes to workflows in architecture and implementation. (And these changes remain accessible in SharePoint Server 2016, SharePoint Server 2019, and SharePoint Server Subscription Edition.) +This article discussed the changes related to workflow tasks that were driven from changes to the workflow story in SharePoint. It demonstrated how to create a simple workflow that applied tasks in SharePoint using Visual Studio. These types of tasks are suitable for many developers, although at times custom tasks and custom outcomes are desired, which can be accomplished using Visual Studio as has been shown. -- [Workflows in SharePoint](https://msdn.microsoft.com/library/jj163986.aspx) - - -- [Authorization and authentication for apps in SharePoint](https://msdn.microsoft.com/library/office/fp142384.aspx) - - -- [How To Customize a List View in Apps for SharePoint Using Client-Side Rendering](https://msdn.microsoft.com/library/jj220045.aspx) - - +## See also +- [Workflows in SharePoint](/sharepoint/dev/general-development/workflows-in-sharepoint) +- [Authorization and authentication for apps in SharePoint](/sharepoint/dev/sp-add-ins/authorization-and-authentication-of-sharepoint-add-ins) +- [How To Customize a List View in Apps for SharePoint Using Client-Side Rendering](/sharepoint/dev/sp-add-ins/customize-a-list-view-in-sharepoint-add-ins-using-client-side-rendering) diff --git a/docs/general-development/working-with-the-excel-services-javascript-object-model.md b/docs/general-development/working-with-the-excel-services-javascript-object-model.md index 9096d126d..b891baa80 100644 --- a/docs/general-development/working-with-the-excel-services-javascript-object-model.md +++ b/docs/general-development/working-with-the-excel-services-javascript-object-model.md @@ -1,9 +1,9 @@ --- title: Working with the Excel Services JavaScript object model -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Learn about working with the Excel Services JavaScript object model and how two scenarios can affect how you write your code. +ms.date: 06/07/2022 ms.assetid: 06219071-a7c1-4f54-b07f-7b7001592330 -localization_priority: Normal +ms.localizationpriority: medium --- diff --git a/docs/general-development/working-with-the-sharepoint-workflow-services-client-side-object-model.md b/docs/general-development/working-with-the-sharepoint-workflow-services-client-side-object-model.md index c32f231fd..eb6d6b388 100644 --- a/docs/general-development/working-with-the-sharepoint-workflow-services-client-side-object-model.md +++ b/docs/general-development/working-with-the-sharepoint-workflow-services-client-side-object-model.md @@ -1,346 +1,202 @@ --- title: Working with the SharePoint Workflow Services Client Side Object Model -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Demonstrates how to use the SharePoint client-side object model (CSOM) API to create and control Workflow Manager 1.0 workflow definitions and instances. +ms.date: 10/15/2022 ms.assetid: e180c2fb-a903-4ded-884e-b7584fa99189 -localization_priority: Priority +ms.localizationpriority: high --- +# Working with the SharePoint Workflow Services Client Side Object Model +Demonstrates how to use the SharePoint client-side object model (CSOM) API to create and control Workflow Manager 1.0 workflow definitions and instances. **Provided by:** [Andrew Connell](https://www.andrewconnell.com), [Voitanos](https://www.voitanos.io) -# Working with the SharePoint Workflow Services Client Side Object Model -Demonstrates how to use the SharePoint client-side object model (CSOM) API to create and control Workflow Manager 1.0 workflow definitions and instances. - **Provided by:** [Andrew Connell](https://social.msdn.microsoft.com/profile/andrew%20connell%20%5bmvp%5d/), [AndrewConnell.com](http://www.andrewconnell.com) - > [!NOTE] > SharePoint 2010 workflows have been retired since August 1, 2020 for new tenants and removed from existing tenants on November 1, 2020. If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions. For more info, see [SharePoint 2010 workflow retirement](https://support.microsoft.com/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f). - + ## Working with the SharePoint Workflow Services Client Side Object Model -The implementation of workflows in SharePoint 2007 and SharePoint 2010 remained largely the same from version to version. Microsoft did add some new functionality in SharePoint 2010, such as the ability to associate workflows with sites, and improved the workflow authoring tools, SharePoint Designer 2010 and Visual Studio 2010, from their predecessors. However, the implementation of workflow tasks, workflow forms, and the workflow server-side APIs remains largely unchanged. - - - -In SharePoint 2010, Microsoft introduced features and capabilities that encouraged customers to move their customizations into sandboxed solution. These would run in an isolated process and were friendly to both types of SharePoint deployments: on-premises, where the SharePoint was installed on company servers and maintained by the company , and to the cloud, or more specifically, Office 365. - - - -In SharePoint, Microsoft added even more capabilities; these updates were oriented toward cloud deployments. Specifically, Microsoft introduced the new SharePoint app model, which went further than the sandboxed solution in that, unlike sandboxed solution, they explicitly blocked server-side code from running in the SharePoint process. Microsoft also built up existing technologies in SharePoint, such as the client-side object model (CSOM), and introduced new capabilities, like support for app identities using [OAuth](https://msdn.microsoft.com/library/office/fp142382.aspx). - - - -And then, with the introduction of SharePoint, Microsoft introduced an entirely new workflow architecture and platform that reflect fundamental shifts in the product direction. - - - +The implementation of workflows in SharePoint 2007 and SharePoint 2010 remained largely the same from version to version. Microsoft did add some new functionality in SharePoint 2010, such as the ability to associate workflows with sites, and improved the workflow authoring tools, SharePoint Designer 2010 and Visual Studio 2010, from their predecessors. However, the implementation of workflow tasks, workflow forms, and the workflow server-side APIs remains largely unchanged. + +In SharePoint 2010, Microsoft introduced features and capabilities that encouraged customers to move their customizations into sandboxed solution. These would run in an isolated process and were friendly to both types of SharePoint deployments: on-premises, where the SharePoint was installed on company servers and maintained by the company , and to the cloud, or more specifically, Office 365. + +In SharePoint, Microsoft added even more capabilities; these updates were oriented toward cloud deployments. Specifically, Microsoft introduced the new SharePoint app model, which went further than the sandboxed solution in that, unlike sandboxed solution, they explicitly blocked server-side code from running in the SharePoint process. Microsoft also built up existing technologies in SharePoint, such as the client-side object model (CSOM), and introduced new capabilities, like support for app identities using [OAuth](/sharepoint/dev/sp-add-ins/context-token-oauth-flow-for-sharepoint-add-ins). + +And then, with the introduction of SharePoint, Microsoft introduced an entirely new workflow architecture and platform that reflect fundamental shifts in the product direction. + The most prominent change in the new architecture is that workflow execution in SharePoint no longer takes place in SharePoint. Instead, SharePoint uses a completely new execution engine: Workflow Manager 1.0. Workflow Manager hosts the Windows Workflow Foundation runtime and all the necessary services required by Windows Workflow Foundation. When a workflow is published, or a new instance of a published workflow is started, SharePoint notifies Workflow Manager, which in turn processes the workflow episodes. When the workflow access information in SharePoint, such as list item properties or user properties, it authenticates using the OAuth support and communicates over new and improved REST APIs. - - - + These changes in the workflow architecture had significant impacts in certain areas, such as custom workflow forms, as discussed in the MSDN article How to: Create Custom SharePoint Workflow Forms with Visual Studio 2012. This article touches on one of the things that Microsoft added to SharePoint to support the new style of creating custom workflow forms: the improvements to the CSOM and addition of the Workflow Services CSOM API. - - - ## Introduction to the Workflow Services CSOM API in SharePoint -In SharePoint 2007 and SharePoint 2010, the workflow API was manifested only in the server-side object model. In SharePoint, this same workflow API is still present, since SharePoint includes the old workflow execution engine in SharePoint for backward compatibility. - - - +In SharePoint 2007 and SharePoint 2010, the workflow API was manifested only in the server-side object model. In SharePoint, this same workflow API is still present, since SharePoint includes the old workflow execution engine in SharePoint for backward compatibility. + However, the new and preferred workflow architecture introduced with SharePoint that uses Workflow Manager includes a brand new server-side API. In SharePoint, Microsoft extended the CSOM to include a robust API for the new workflow architecture. Note that this addition to the CSOM only applies to the new SharePoint and Workflow Manager 1.0 workflow architecture, not the legacy version that is still hosted by SharePoint. - - - + The Workflow Services CSOM API, like the rest of the CSOM, is implemented both in a .NET Silverlight managed API and a JavaScript API known as the JavaScript Object Model (JSOM). JSOM is what developers must use when creating custom workflow forms as those forms will be ASP.NET web forms that must not have any server-side code. Thus the Workflow Services JSOM API is used in custom association forms to create workflow associations as well as on initiation forms to start new workflow instances. - - - + However, the possibilities do not stop there. The Workflow Services CSOM and JSOM is very robust and enables developers to do almost anything with workflows in SharePoint. Aside from creating workflow associations and instances, developers can also programmatically deploy new workflow definitions and even communicate with running workflow instances from the CSOM and JSOM, as is discussed in the remainder of this article. - - - + This article focuses on the topic of workflow forms in the context of SharePoint Sever 2013. It is based on the SharePoint with the March 2013 Public Update applied and Office Developer Tools for Visual Studio 2013. Everything in this article applies to both SharePoint on-premises deployments as well as Office 365. - - - ## Workflow Services CSOM and JSOM API components -This article focuses on the Workflow Services CSOM API and thus, by extension, the JSOM API as well; the server side Workflow Services API is not discussed here. The Workflow Services CSOM consists of several different services that are used to perform different tasks. Each of these is discussed in the following sections. - -> [!NOTE] -> There is one additional service that is not present in the CSOM, but is present instead with the server-side API. This is the Messaging Service, which is used to manage message queuing and message transport. - - - +This article focuses on the Workflow Services CSOM API and thus, by extension, the JSOM API as well; the server side Workflow Services API is not discussed here. The Workflow Services CSOM consists of several different services that are used to perform different tasks. Each of these is discussed in the following sections. + +> [!NOTE] +> There is one additional service that is not present in the CSOM, but is present instead with the server-side API. This is the Messaging Service, which is used to manage message queuing and message transport. To work with the Workflow Services CSOM and JSOM APIs, developers must add the necessary references to their projects (in the case of CSOM) and pages (in the case of JSOM). Both implementations have the same requirements: - - - - Reference the core SharePoint CSOM and JSOM libraries: - - Microsoft.SharePoint.Client.dll - - - Microsoft.SharePoint.Client.Runtime.dll - - - Microsoft.SharePoint.Client.WorkflowServices.dll - - - - Reference the Workflow Services CSOM and JSOM libraries: - - SP.js - - - SP.Runtime.js - - - SP.WorkflowServices.js - - ### Workflow Service Manager -The gateway to all services included in the Workflow Services CSOM API is the Workflow Service Manager. This object is what developers use to obtain instances to all the other services described in the following sections. Similar to other CSOM API implementations, the [WorkflowServicesManager](https://msdn.microsoft.com/library/Microsoft.SharePoint.WorkflowServices.WorkflowServicesManager.aspx) has a dependency on the core SharePoint CSOM and, therefore, you must pass in a valid client context and reference to the SharePoint site you want to connect to, as shown in the following CSOM and JSOM code examples. - - - +The gateway to all services included in the Workflow Services CSOM API is the Workflow Service Manager. This object is what developers use to obtain instances to all the other services described in the following sections. Similar to other CSOM API implementations, the [WorkflowServicesManager](/previous-versions/office/sharepoint-server/jj252321(v=office.15)) has a dependency on the core SharePoint CSOM and, therefore, you must pass in a valid client context and reference to the SharePoint site you want to connect to, as shown in the following CSOM and JSOM code examples. #### CSOM: Creating a WorkflowServicesManager instance - -``` - +```csharp var clientContext = new ClientContext(siteCollectionUrl); -var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); - +var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); ``` - #### JSOM: Creating a WorkflowServicesManager instance - -``` - +```javascript var clientContext = SP.ClientContext.get_current(); -var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); - +var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); ``` - ### Deployment service When you create custom workflows using Visual Studio 2012, either using a solution package (*.wsp) or as a SharePoint app (*.app), you are creating workflow definitions. A definition is the workflow process and all business rules and attributes defined within it, such as the location of custom association and initiation forms. On their own, these definitions are not very useful because they cannot be run outside the context of an association with a site, list, or document library. The workflow definitions published and available in a site can be found by going to the page where a new workflow association can be created, as shown in the following figure. - - - **Figure 1. Add a workflow association** - - - - - - - - ![Figure 1. Add a workflow association](../images/ngSP2013WorkflowCSOM01.png) - - - + The collection of published workflow definitions is accessible through the deployment service. This service enables you to get a list of all currently saved and published definitions on the site, as well as to publish both saved and new definitions, remove existing definitions, and determine what workflow actions are available to SharePoint Designer 2013-authored workflows. - - - + The **WorkflowDeploymentService** object is available through the **WorkflowServicesManager** class, as shown in the following code examples. - - - #### CSOM: Obtaining a WorkflowDeploymentService instance - -``` - +```csharp var clientContext = new ClientContext(siteCollectionUrl); var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); -var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService(); - +var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService(); ``` - #### JSOM: Obtaining a WorkflowDeploymentService instance - -``` - +```javascript var clientContext = SP.ClientContext.get_current(); -var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); +var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); var workflowDeploymentService = workflowServicesManager.getWorkflowDeploymentService(); - ``` - ### Subscription service Recall from the previous section that you create workflows and publish them to SharePoint as definitions. To use these definitions, a user must create an association that links the definition to a specific SharePoint site, list, or document library along with additional metadata. This process basically works and behaves the same way in SharePoint 2010 but the implementation in SharePoint is very different. Workflow Manager 1.0 takes advantage of an instance of Microsoft Azure Service Bus 1.0. - - - -Service Bus is instrumental because it supports the publication and subscription service (also known as PubSub). This is an asynchronous messaging framework that supports a publisher sending a message to a topic stored in Service Bus. Any number of subscribers can request to be notified when a message is published to that topic that meets specific criteria. - - - -SharePoint and Workflow Manager 1.0 use the PubSub model to create associations. Workflow associations are created as subscriptions on topics. For instance, an association for workflow definition may be created on list and set to start automatically when items are added to the list. When an item is added to the list, SharePoint publishes an event to Workflow Manager 1.0, which it sends to the Service Bus topic. The message is evaluated and the registered subscriptions are notified of the event. The subscribed association is found and the workflow is started. For more information about how this process works, see the MSDN article, [SharePoint workflow fundamentals](sharepoint-workflow-fundamentals.md). - - - -This should clarify, then, why workflow associations are now called subscriptions within the API (that is, under the covers). You can use a Subscription Service in the Workflow Services CSOM to explore existing associations and subscriptions, create and delete associations and subscriptions, and request to be notified of events. - - - -The [WorkflowSubscriptionService](https://msdn.microsoft.com/library/Microsoft.SharePoint.WorkflowServices.WorkflowSubscriptionService.aspx) object is available through the **WorkflowServicesManager** class, as shown in the following code examples. - - - -#### CSOM: Obtaining a WorkflowSubscriptionService instance +Service Bus is instrumental because it supports the publication and subscription service (also known as PubSub). This is an asynchronous messaging framework that supports a publisher sending a message to a topic stored in Service Bus. Any number of subscribers can request to be notified when a message is published to that topic that meets specific criteria. +SharePoint and Workflow Manager 1.0 use the PubSub model to create associations. Workflow associations are created as subscriptions on topics. For instance, an association for workflow definition may be created on list and set to start automatically when items are added to the list. When an item is added to the list, SharePoint publishes an event to Workflow Manager 1.0, which it sends to the Service Bus topic. The message is evaluated and the registered subscriptions are notified of the event. The subscribed association is found and the workflow is started. For more information about how this process works, see the MSDN article, [SharePoint workflow fundamentals](sharepoint-workflow-fundamentals.md). -``` +This should clarify, then, why workflow associations are now called subscriptions within the API (that is, under the covers). You can use a Subscription Service in the Workflow Services CSOM to explore existing associations and subscriptions, create and delete associations and subscriptions, and request to be notified of events. + +The [WorkflowSubscriptionService](/previous-versions/office/sharepoint-server/jj253502(v=office.15)) object is available through the **WorkflowServicesManager** class, as shown in the following code examples. + +#### CSOM: Obtaining a WorkflowSubscriptionService instance +```csharp var clientContext = new ClientContext(siteCollectionUrl); var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); var workflowSubscriptionService = workflowServicesManager.GetWorkflowSubscriptionService(); - ``` - #### JSOM: Obtaining a WorkflowSubscriptionService instance - -``` - +```javascript var clientContext = SP.ClientContext.get_current(); -var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); +var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); var workflowSubscriptionService = workflowServicesManager.getWorkflowSubscriptionService(); - ``` - ### Instance service The final service that we'll cover is the instance service. You can use this service to perform several tasks with workflow instances, such as starting, suspending, resuming, terminating, and cancelling workflow instances. You can also use it to collect debug information, as well as enumerate through all currently running workflows, as well as those that have already completed. Finally, you can use this service to publish events to workflows that are currently running, as we'll see later in this article. - - - -The [WorkflowInstanceService](https://msdn.microsoft.com/library/Microsoft.SharePoint.WorkflowServices.WorkflowInstanceService.aspx) object is available through the **WorkflowServicesManager** class, as shown in the following code examples. - - - -#### CSOM: Obtaining a WorkflowInstanceService instance +The [WorkflowInstanceService](/previous-versions/office/sharepoint-server/jj252390(v=office.15)) object is available through the **WorkflowServicesManager** class, as shown in the following code examples. +#### CSOM: Obtaining a WorkflowInstanceService instance -``` +```csharp var clientContext = new ClientContext(siteCollectionUrl); var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService(); - ``` - #### JSOM: Obtaining a WorkflowInstanceService instance - -``` - +```javascript var clientContext = SP.ClientContext.get_current(); -var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); +var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); var workflowInstanceService = workflowServicesManager.getWorkflowInstanceService(); - ``` - ### Interop service In previous versions of SharePoint, specifically SharePoint 2007 and SharePoint 2010, SharePoint hosted the Windows Workflow Foundation runtime. As previously explained, Microsoft moved away from this approach in SharePoint by introducing a dependency on Workflow Manager 1.0, which hosts the workflow runtime outside of SharePoint. Consequently, workflows are no longer executed and managed within SharePoint; instead, SharePoint hands off workflow management and execution responsibilities to Workflow Manager 1.0. - - - + However, to provide backward compatibility, Microsoft retained the legacy model of hosting pre-SharePoint-style workflows within SharePoint by keeping the Windows Workflow Foundation runtime engine. Therefore, all workflows created in SharePoint 2010 will still run as expected in a SharePoint environment. In addition, Microsoft included a new activity, **InvokeSharePointWorkflow**, which can be used in a SharePoint workflow to start an existing workflow in the SharePoint 2010 workflow host that is included in SharePoint. This allows you to take advantage of existing workflow investments migrated from previous versions. - -> [!NOTE] -> The **InvokeSharePointWorkflow** activity is a wrapper for the CSOM method, [StartWorkflow](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.InteropService.StartWorkflow.aspx) . - - - - -The SharePoint Workflow Services CSOM also includes a special service that enables developers to interact with these legacy workflows. The [InteropService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.InteropService.aspx) lets you start and stop workflows, as well as enable and disable event notifications for running workflows. - - - -The [WorkflowDeploymentService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowDeploymentService.aspx) object is available through the **WorkflowServicesManager** class, as shown in the following CSOM and JSOM code examples. - - - -#### CSOM: Obtaining an InteropService instance +> [!NOTE] +> The **InvokeSharePointWorkflow** activity is a wrapper for the CSOM method, [StartWorkflow](/previous-versions/office/sharepoint-csom/dn624213(v=office.15)) . +The SharePoint Workflow Services CSOM also includes a special service that enables developers to interact with these legacy workflows. The [InteropService](/previous-versions/office/sharepoint-csom/dn624199(v=office.15)) lets you start and stop workflows, as well as enable and disable event notifications for running workflows. -``` +The [WorkflowDeploymentService](/previous-versions/office/sharepoint-csom/dn624233(v=office.15)) object is available through the **WorkflowServicesManager** class, as shown in the following CSOM and JSOM code examples. + +#### CSOM: Obtaining an InteropService instance +```chsarp var clientContext = new ClientContext(siteCollectionUrl); var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); var workflowInteropService = workflowServicesManager.GetWorkflowInteropService(); - ``` - #### JSOM: Obtaining an InteropService instance - -``` - +```javascript var clientContext = SP.ClientContext.get_current(); -var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); +var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web()); var workflowInteropService = serviceManager.getWorkflowInteropService(); - ``` - ## Example: Workflow Services CSOM scenarios -The following sections demonstrate how to use the different services in the Workflow Services CSOM to perform common tasks in custom solutions. - - - +The following sections demonstrate how to use the different services in the Workflow Services CSOM to perform common tasks in custom solutions. ### Get all workflows installed -Most of the other services in the Workflow Services CSOM require that you get references to the workflow definition that was previously published. Workflow definitions are usually referenced by their IDs, which are GUIDs. - - - -To get a list of all the published workflow definitions, first get an instance of the deployment service by using the [GetWorkflowDeploymentService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager.GetWorkflowDeploymentService.aspx) method. Then, retrieve the collection of all workflow definitions by using the [EnumerateDefinitions(Boolean)](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowDeploymentService.EnumerateDefinitions.aspx) method. Here is example code: - - - - - +Most of the other services in the Workflow Services CSOM require that you get references to the workflow definition that was previously published. Workflow definitions are usually referenced by their IDs, which are GUIDs. -``` +To get a list of all the published workflow definitions, first get an instance of the deployment service by using the [GetWorkflowDeploymentService](/previous-versions/office/sharepoint-csom/dn624302(v=office.15)) method. Then, retrieve the collection of all workflow definitions by using the [EnumerateDefinitions(Boolean)](/previous-versions/office/sharepoint-csom/dn624250(v=office.15)) method. Here is example code: +```csharp // connect to the workflow services via a CSOM client context var clientContext = new ClientContext(siteCollectionUrl); var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); -// connect to the deployment service +// connect to the deployment service var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService(); // get all installed workflows @@ -352,42 +208,21 @@ clientContext.ExecuteQuery(); foreach (var workflowDefinition in publishedWorkflowDefinitions) { Console.WriteLine("{0} - {1}", workflowDefinition.Id.ToString(), workflowDefinition.DisplayName); } - ``` - - ### Get all associations and subscriptions -To start a new workflow instance, you need to first get a reference to an existing workflow association. Building on the previous code example, the following example demonstrates how to get a list of all workflow associations for a specific workflow definition in a site. - - - -Once you have obtained a workflow definition using the example above, use the [GetWorkflowSubscriptionService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager.GetWorkflowSubscriptionService.aspx) method to create an instance of the subscription service. Next, use the [EnumerateSubscriptionsByDefinition](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscriptionService.EnumerateSubscriptionsByDefinition.aspx) method (passing in the ID of a workflow definition) to get a list of all the associations that exist for the specified workflow. Note that there are several methods available for getting workflow associations, including the following: - - - - -- [EnumerateSubscriptions](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscriptionService.EnumerateSubscriptions.aspx) - - -- [EnumerateSubscriptionsByDefinition](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscriptionService.EnumerateSubscriptionsByDefinition.aspx) - - -- [EnumerateSubscriptionsByEventSource](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscriptionService.EnumerateSubscriptionsByEventSource.aspx) - - -- [EnumerateSubscriptionsByList](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscriptionService.EnumerateSubscriptionsByList.aspx) - - -The following code example demonstrates getting associations and subscriptions. - - - +To start a new workflow instance, you need to first get a reference to an existing workflow association. Building on the previous code example, the following example demonstrates how to get a list of all workflow associations for a specific workflow definition in a site. +Once you have obtained a workflow definition using the example above, use the [GetWorkflowSubscriptionService](/previous-versions/office/sharepoint-csom/dn624312(v=office.15)) method to create an instance of the subscription service. Next, use the [EnumerateSubscriptionsByDefinition](/previous-versions/office/sharepoint-csom/dn624344(v=office.15)) method (passing in the ID of a workflow definition) to get a list of all the associations that exist for the specified workflow. Note that there are several methods available for getting workflow associations, including the following: +- [EnumerateSubscriptions](/previous-versions/office/sharepoint-csom/dn624342(v=office.15)) +- [EnumerateSubscriptionsByDefinition](/previous-versions/office/sharepoint-csom/dn624344(v=office.15)) +- [EnumerateSubscriptionsByEventSource](/previous-versions/office/sharepoint-csom/dn624346(v=office.15)) +- [EnumerateSubscriptionsByList](/previous-versions/office/sharepoint-csom/dn624352(v=office.15)) -``` +The following code example demonstrates getting associations and subscriptions.: +```csharp // connect to the workflow services via a CSOM client context var clientContext = new ClientContext(siteCollectionUrl); var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web); @@ -415,80 +250,48 @@ foreach (var association in workflowAssociations) { Console.WriteLine("{0} - {1}", association.Id, association.Name); } - ``` - ### Creating a workflow association Creating a new workflow association, which can also be referred to as a subscription, requires additional effort before actually publishing the association to SharePoint. This is because each subscription needs to have additional information, which is usually collected on the association page. This metadata includes the following: - - - - The ID of the workflow definition the association is based on. - - - The ID of the SharePoint site, list or document library the workflow association is created on. - - -- The display name of the association. - - +- The display name of the association. - The startup options (whether started manually or automatically when a list item is added or updated). - - - The ID of the list that will store all history list messages for this association. - - - The ID of the list that will store all tasks for this association. - - - Optionally, a collection of any name/value pairs that should be sent to the workflow. These are the fields that are usually passed in from a custom association form. - - ### Creating a custom workflow association +1. To create a custom association, first use the [GetWorkflowSubscriptionService](/previous-versions/office/sharepoint-csom/dn624312(v=office.15)) method to get a reference to the subscription service. -1. To create a custom association, first use the [GetWorkflowSubscriptionService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager.GetWorkflowSubscriptionService.aspx) method to get a reference to the subscription service. - -``` - -// connect to the deployment service -var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService(); + ```csharp + // connect to the deployment service + var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService(); -// get all installed workflows -var publishedWorkflowDefinitions = workflowDeploymentService.EnumerateDefinitions(true); -clientContext.Load(publishedWorkflowDefinitions); -clientContext.ExecuteQuery(); + // get all installed workflows + var publishedWorkflowDefinitions = workflowDeploymentService.EnumerateDefinitions(true); + clientContext.Load(publishedWorkflowDefinitions); + clientContext.ExecuteQuery(); -// find the first workflow definition -var firstWorkflowDefinition = publishedWorkflowDefinitions.First(); - -// connect to the subscription service -var workflowSubscriptionService = workflowServicesManager.GetWorkflowSubscriptionService(); + // find the first workflow definition + var firstWorkflowDefinition = publishedWorkflowDefinitions.First(); -``` + // connect to the subscription service + var workflowSubscriptionService = workflowServicesManager.GetWorkflowSubscriptionService(); + ``` -2. Create a new object instance of the [WorkflowSubscription](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription.aspx) class. - - -3. Set the required properties on the **WorkflowSubscription** object, as illustrated in the following code example. In the example, code comments explain each of the property settings. Note that some properties that are not relevant to CSOM workflow services have been left out for readability. These properties have been omitted: - +1. Create a new object instance of the [WorkflowSubscription](/previous-versions/office/sharepoint-csom/dn624358(v=office.15)) class. +1. Set the required properties on the **WorkflowSubscription** object, as illustrated in the following code example. In the example, code comments explain each of the property settings. Note that some properties that are not relevant to CSOM workflow services have been left out for readability. These properties have been omitted: 1. **listId**. The ID of the list on which the association is created. - - -2. **historyListId**. The ID of the list that stores all history list messages for the association. - - -3. **taskListId**. The ID of the list that will store all tasks for the association. - - -4. Once created, the subscription must be published to SharePoint using the [PublishSubscriptionForList](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscriptionService.PublishSubscriptionForList.aspx) method, as demonstrated in the following code example: - -``` - +1. **historyListId**. The ID of the list that stores all history list messages for the association. +1. **taskListId**. The ID of the list that will store all tasks for the association. +1. Once created, the subscription must be published to SharePoint using the [PublishSubscriptionForList](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscriptionService.PublishSubscriptionForList.aspx) method, as demonstrated in the following code example: + +```csharp // create a new association / subscription WorkflowSubscription newSubscription = new WorkflowSubscription(clientContext) { DefinitionId = firstWorkflowDefinition.Id, @@ -496,7 +299,6 @@ WorkflowSubscription newSubscription = new WorkflowSubscription(clientContext) { Name = "New Workflow Association" }; - var startupOptions = new List(); // automatic start startupOptions.Add("ItemAdded"); @@ -519,43 +321,24 @@ newSubscription.SetProperty("Prop2","Value2"); // create the association workflowSubscriptionService.PublishSubscriptionForList(newSubscription, listId); clientContext.ExecuteQuery(); - ``` - ### Get all workflow instances You can also use the Workflow Services instance service to view all workflow instances that are running on a SharePoint site, list, or document library. The instance object that is returned contains information on the instance, such as when it was last updated, the current status, and any errors that may have occurred when it ran previously. Additionally, it provides a collection of name/value pairs that were submitted to the workflow from the custom initiation form. - - - -To do this, start by using the [GetWorkflowInstanceService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager.GetWorkflowInstanceService.aspx) method to get a reference to the instance service. Note that the [WorkflowInstanceService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.aspx) provides several methods for obtaining the collection of running workflow instances: - - - - -- [Enumerate](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.Enumerate.aspx) . Accepts a workflow association (that is, a subscription) as a parameter, and can be used to get all the instances that have been created based on the specified association. - - -- [EnumerateInstancesForSite](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.EnumerateInstancesForSite.aspx) : Gets a list of all workflow instances that have been started on the SharePoint site that was set when creating the original **WorkflowServiceManager** object. - - -- [EnumerateInstancesForListItem](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.EnumerateInstancesForListItem.aspx) . Accepts a list ID and item ID; use this method to get all workflow instances that have been created on a specific list item. - - -Each of theses methods also has an alternate ***WithOffset()** method (for example, [EnumerateWithOffset](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.EnumerateWithOffset.aspx) ). These alternative methods allow you to get a subset of the workflow instances in cases where working with the entire collection would be cumbersome. To get a count of the number of workflow instances, use the [CountInstances](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.CountInstances.aspx) method, or the [CountInstancesWithStatus](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.CountInstancesWithStatus.aspx) method. - - - -The following code example illustrates getting workflow instances: - - - +To do this, start by using the [GetWorkflowInstanceService](/previous-versions/office/sharepoint-csom/dn624310(v=office.15)) method to get a reference to the instance service. Note that the [WorkflowInstanceService](/previous-versions/office/sharepoint-csom/dn624282(v=office.15)) provides several methods for obtaining the collection of running workflow instances: -``` +- [Enumerate](/previous-versions/office/sharepoint-csom/dn624286(v=office.15)). Accepts a workflow association (that is, a subscription) as a parameter, and can be used to get all the instances that have been created based on the specified association. +- [EnumerateInstancesForSite](/previous-versions/office/sharepoint-csom/dn624294(v=office.15)) : Gets a list of all workflow instances that have been started on the SharePoint site that was set when creating the original **WorkflowServiceManager** object. +- [EnumerateInstancesForListItem](/previous-versions/office/sharepoint-csom/dn624289(v=office.15)) . Accepts a list ID and item ID; use this method to get all workflow instances that have been created on a specific list item. +Each of theses methods also has an alternate ***WithOffset()** method (for example, [EnumerateWithOffset](/previous-versions/office/sharepoint-csom/dn624292(v=office.15)). These alternative methods allow you to get a subset of the workflow instances in cases where working with the entire collection would be cumbersome. To get a count of the number of workflow instances, use the [CountInstances](/previous-versions/office/sharepoint-csom/dn624285(v=office.15)) method, or the [CountInstancesWithStatus](/previous-versions/office/sharepoint-csom/dn624288(v=office.15)) method. + +The following code example illustrates getting workflow instances: + +```csharp // connect to the instance service var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService(); @@ -570,33 +353,19 @@ foreach (var instance in workflowInstances) } ``` - ### Start a workflow instance Starting a new instance of a workflow association involves repeating many of the steps that have been demonstrated in the previous examples. To start a workflow on an item in a list or document library, first obtain a reference to the workflow association and the ID of the item in the list. A collection of name/value pairs of information can be sent to the workflow when it is started. This happens when there is a custom initiation form that is used to collect data from the user starting the workflow. Then pass in a collection, even if it is an empty collection, when starting the workflow or the workflow will fail to start and return an error. - - - -Building from previous examples, use the [GetWorkflowInstanceService](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager.GetWorkflowInstanceService.aspx) method to get an instance of the workflow instance service. Next, start the workflow by calling one of two methods. One starts workflows on a site, while the other starts a workflow on a list item. - - - - -- [StartWorkflow](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.StartWorkflow.aspx) . Starts a workflow on the SharePoint site that was set when creating the original [WorkflowServicesManager](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager.aspx) object. When using this method, you must pass in the workflow association and any additional startup properties present on the initiation form. - - -- [StartWorkflowOnListItem](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.StartWorkflowOnListItem.aspx) . Starts a workflow on a specific list item. Using this method requires you to pass in the ID of the desired list item, in addition to other parameter values required by the **StartWorkflow** method. - - -The following code example demonstrates how to start a workflow instance. - - - +Building from previous examples, use the [GetWorkflowInstanceService](/previous-versions/office/sharepoint-csom/dn624310(v=office.15)) method to get an instance of the workflow instance service. Next, start the workflow by calling one of two methods. One starts workflows on a site, while the other starts a workflow on a list item. +- [StartWorkflow](/previous-versions/office/sharepoint-csom/dn624305(v=office.15)) . Starts a workflow on the SharePoint site that was set when creating the original [WorkflowServicesManager](/previous-versions/office/sharepoint-csom/dn624306(v=office.15)) object. When using this method, you must pass in the workflow association and any additional startup properties present on the initiation form. +- [StartWorkflowOnListItem](/previous-versions/office/sharepoint-csom/dn607351(v=office.15)) . Starts a workflow on a specific list item. Using this method requires you to pass in the ID of the desired list item, in addition to other parameter values required by the **StartWorkflow** method. + +The following code example demonstrates how to start a workflow instance. -``` +```csharp // connect to the deployment service var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService(); @@ -626,25 +395,15 @@ var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService var startParameters = new Dictionary(); workflowInstanceService.StartWorkflowOnListItem(firstWorkflowAssociation, listItemId, startParameters); clientContext.ExecuteQuery(); - ``` - ### Publishing messages and events to running workflows Another powerful feature that was added in SharePoint is the ability to publish custom events to running workflow instances. These workflows can have an activity, **WaitForCustomEvent**, which listens for a specific event to be published to the workflow. The event can also contain a string as part of the message, which the activity can store as a variable. - - - -To publish an event from the client using the Workflow Service CSOM, first get a reference to the specific workflow instance that the event should be published to. Then, using the instance service, publish the event using the [PublishCustomEvent](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.WorkflowServices.WorkflowInstanceService.PublishCustomEvent.aspx) method. When using this method, you must pass in the desired instance, event name, and an optional payload, as shown in the following code example. - - - +To publish an event from the client using the Workflow Service CSOM, first get a reference to the specific workflow instance that the event should be published to. Then, using the instance service, publish the event using the [PublishCustomEvent](/previous-versions/office/sharepoint-csom/dn624296(v=office.15)) method. When using this method, you must pass in the desired instance, event name, and an optional payload, as shown in the following code example. - -``` - +```csharp // connect to the instance service var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService(); @@ -659,47 +418,19 @@ clientContext.ExecuteQuery(); ``` To receive the message in the workflow, add a **WaitForCustomEvent** activity and, using the **Properties** window, set the **EventName** property to the name of the event the activity is listening for (in the example above, this would be the string, "AdHocMaintenanceRequest"). Then, set the **Result** property to the variable in which the event's payload is stored, as shown in Figure 2. - - - **Figure 2. Input EventName and output Result** - - - - - - - - ![Figure 2. Input EventName and Output Result](../images/ngSP2013WorkflowCSOM02.png) - - - + This technique of publishing a custom event is demonstrated in the MSDN Code Sample: SharePoint: Route Workflows to States Depending on Actions and Events. - - - ## Conclusion Microsoft introduced workflows into the SharePoint 2007 platform, and the workflow platform remained largely unchanged in SharePoint 2010. This was also true when it came to Custom Forms in SharePoint workflows. SharePoint, on the other hand, introduced many changes to workflow platform and architecture. - - - + One of the major improvements to workflows in SharePoint is the expansion of CSOM to include a complete Workflow Services API. This addition enables developers to interact with workflow definitions, associations, and subscriptions, and to create and interact with instances of these workflows. - - - ## See also - - - -- [Workflows in SharePoint](https://msdn.microsoft.com/library/jj163986.aspx) - - -- [What is Workflow Manager 1.0?](https://msdn.microsoft.com/library/windowsazure/jj193471%28v=azure.10%29.aspx) - - +- [Workflows in SharePoint](/sharepoint/dev/general-development/workflows-in-sharepoint) +- [What is Workflow Manager 1.0?](/previous-versions/dotnet/workflow-manager/jj193471(v=azure.10)) diff --git a/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-sharepoint-designer.md b/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-sharepoint-designer.md index a08164bf3..efc789892 100644 --- a/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-sharepoint-designer.md +++ b/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-sharepoint-designer.md @@ -1,405 +1,398 @@ --- title: Working with Web Services in SharePoint Workflows using SharePoint Designer 2013 -ms.date: 09/25/2017 -ms.prod: sharepoint +description: Demonstrates how to use web services in SharePoint Designer 2013 workflows. +ms.date: 10/15/2022 ms.assetid: bc8769c6-ae71-4519-abf3-c1b6fb071059 -localization_priority: Priority +ms.localizationpriority: high --- # Working with Web Services in SharePoint Workflows using SharePoint Designer 2013 -Demonstrates how to use web services in SharePoint Designer 2013 workflows. - **Provided by:** [Andrew Connell](https://social.msdn.microsoft.com/profile/andrew%20connell%20%5bmvp%5d/), [www.AndrewConnell.com](http://www.andrewconnell.com) - +Demonstrates how to use web services in SharePoint Designer 2013 workflows. + **Provided by:** [Andrew Connell](https://www.andrewconnell.com), [Voitanos](https://www.voitanos.io) + > [!NOTE] > SharePoint 2010 workflows have been retired since August 1, 2020 for new tenants and removed from existing tenants on November 1, 2020. If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions. For more info, see [SharePoint 2010 workflow retirement](https://support.microsoft.com/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f). - - + + The workflow team worked with the Microsoft Azure team to create a product called Workflow Manager. Workflow Manager serves as the host for the latest version of the Windows Workflow Foundation runtime and provides all of the necessary services as well as leveraging the Microsoft Azure Service Bus to enhance performance and scalability. Once deployed, it runs the same whether in an on-premises deployment or deployed to the cloud. Importantly, SharePoint hands off all workflow execution and related tasks to the Workflow Manager farm, which is external to SharePoint. One of the more significant changes to the workflow architecture is that now all workflows are authored in a declaratively, on a designer surface, including those built using Visual Studio 2012. In previous versions of SharePoint, workflows developed with Visual Studio 2012 were not exclusively declarative. Instead, they were a mix of declarative XAML and a compiled assembly that contained the workflow business logic. - - - + + + For those customers who have created workflows using SharePoint Designer in the past, this is nothing new. Workflows authored using SharePoint Designer have always been fully declarative. This change does benefit customers who create workflows using SharePoint Designer 2013, however, because SharePoint Designer 2013 workflows now support calling and consuming web services. ## Why are web services important for SharePoint workflows Let's start by understanding scenarios in which using web services makes sense. In the days of SharePoint 2007 or SharePoint 2010, writing custom code was common when using Visual Studio to author workflows because that was the best way to perform calculations or implement custom business logic. Any time you encountered a situation in which the out-of-the-box actions and activities didn't meet your needs, you could fall back on custom code in a managed assembly. - - - + + + For the non-developer users of SharePoint Designer 2013, on the other hand, this was not so easy. When you ran into a use cases that you couldn't handle with existing workflow actions, you had to call in a developer to write a custom action. Often, this was difficult because they could only create code for the sandbox (when in a hosted environment), or could only use fully-trusted solutions if in an on-premises deployment. In other cases, the workflow had to be completely handed over to a developer to build as a fully-trusted solution because what was needed could not be achieved in SharePoint Designer. - - - + + + Now comes the good news: In the world of SharePoint, when SharePoint Designer 2013 lacks an action that you need, all you need is to create a custom web service. And creating a custom web service is much easier than creating a custom action. Not only that, but whereas a custom action could only be used by the workflow in which it's installed (or, at best, by only a SharePoint workflow), a custom web service is portable and can be used by any number of consumers. - - - + + + Perhaps best of all, in cases where there is an existing web service that you need to access - either a public one, or perhaps a private web service that is hosted by your company - SharePoint Designer 2013 now provides an action that you can use to call the web service. There is no longer any need to rely on a developer when you need to call an existing web service. - - - + + + While SharePoint can consume any type of web service, it is easiest (and recommended) that you use web services that accept and return data using the standard [OData](http://www.odata.org/) formats of [Atom](https://msdn.microsoft.com/library/ff478141.aspx) or [JSON](http://json.org/) (JavaScript Object Notation). - - - + + + This recommendation is based on their being support for these OData formats in SharePoint workflow authoring tools (both SharePoint Designer 2013 and Visual Studio 2012). Both tools support building payloads to submit to the service and for handling the responses returned by the web services. Additionally, the OData formats support communication with anonymous web services as well as with those protected by various types of authentication. In short, you have full control over the request and response for each service call. This allows you to use a series of activities within a workflow to first authenticate using one service and obtain an OAuth token, and then include that token in future requests to services secured using the [OAuth 2.0](http://oauth.net/2/) protocol. - - - + + + ## Leveraging web services in SharePoint workflows Invoking web services from workflows using SharePoint takes place in two stages: first is calling the web service, then is exchanging data with the web service. - - - + + + In SharePoint workflows, you call a web service using a new action introduced in SharePoint named **Call HTTP Web Service**. This action is flexible and allow you to make simple calls to a web service easily, or, if needed, you can create more complex calls using HTTP verbs as well as allowing you to add HTTP headers. Figure 1 shows you the **Call HTTP Web Service** action on the SharePoint Designer 2013 surface. - - - + + + **Figure 1. SharePoint Designer 2013 stage showing the Call HTTP Web Service action** - - - - - - + + + + + + ![Figure 1. Call HTTP Web Service action](../images/ngWSSP2013WorkflowSPD2013.png) - - - + + + The **Call HTTP Web Service** action lets you specify any of several request methods, including **GET**, **PUT**, **POST**, and **DELETE**. This lets you tell the web services, specifically [RESTful](https://msdn.microsoft.com/library/office/jj164022.aspx) services, what to do on the service that you've specified with the URI property on the activity. - - - + + + For instance, to get all the properties of a specific item, the service URL would contain the unique address of the item, and you would set the method to **GET**. To delete the item, the process is the same, except you set the method to **DELETE**. The same is true for updating an item, except for setting the method to **POST**. When you create an item, set the URL to the unique address of the collection where the item is to be created, and then set the method to **POST**. When creating or updating items, services generally require the data to use, which you pass along as content in the request, then indicate using the **request** property on the **Call HTTP Web Service** action. - - - + + + The second stage of working with web services involves submitting data to, and receiving data from, a web service, which you do by using either the **request** or **response** properties on the **Call HTTP Web Service** action. Note, however, that rather than as a stream, data is passed as a complex structure using the [Dynamic Value](https://msdn.microsoft.com/library/windowsazure/microsoft.activities.dynamicvalue%28v=azure.10%29.aspx) object. (For more information about dynamic values, see [Understanding Dynamic Value](https://msdn.microsoft.com/library/windowsazure/jj193505%28v=azure.10%29.aspx).) - - - + + + Dynamic value data structures are formatted as JavaScript Object Notation (JSON) strings. However, instead of having a developer create and manipulate strings manually within the workflow, Microsoft has provided the object type **DynamicValue** that can be used to store both hierarchal data as well as the response to a web service call. - - - + + + There is a series of activities associated with the **DynamicValue** type that can be used to count the number of items in the response, extract values from the response, or build up a new structure for updating or creating items. Note that SharePoint Designer 2013 does not support working directly with the **DynamicValue** type and instead, workflow authors will use the **Dictionary** type. - - - + + + ## Creating web services for SharePoint workflows So we've learned that SharePoint Designer 2013 supports calling web services, but that it *doesn't* support invoking custom code from workflows. Consequently, you will need to know how to create a web service if you wish to extend the functionality of your workflows beyond the default actions. - - - + + + Fortunately, there are plenty of options for creating custom web services for use in SharePoint workflows. Specifically, the **HttpSend** activity, along with the **DynamicValue** data type, are ideally suited for creating RESTful web services that conform to the OData protocol. - - - + + + OData is a protocol for creating and consuming data based on the principles of REST services. It was developed to standardize exchanging data using mature, reliable, and robust HTTP protocols. Once the OData specification was complete, different organizations implemented the protocol on their own technology stacks. Microsoft implemented its own version of OData, which it branded [WCF Data Services](https://msdn.microsoft.com/library/hh487257%28v=vs.103%29.aspx). - - - + + + Following are discussions of two common scenarios in which RESTful web services are useful to workflow developers: - - - + + + - Implementing OData service CRUD-Q operations - - + + - Implementing OData service operations - - + + ### Implementing OData service CRUD-Q operations -A common use for web services is performing simple create, read, update, delete, and query (CRUD-Q) operations on data in a database. It is relatively easy to create an OData web service for a SharePoint workflow WCF data service an OData service to be used by a workflow by using WCF Data services. You can review the walkthroughs and samples on creating web services at sites like [WCF Data Services](https://msdn.microsoft.com/library/cc668792.aspx), [www.OData.org](http://www.odata.org), and others. - - - +A common use for web services is performing simple create, read, update, delete, and query (CRUD-Q) operations on data in a database. It is relatively easy to create an OData web service for a SharePoint workflow WCF data service an OData service to be used by a workflow by using WCF Data services. You can review the walkthroughs and samples on creating web services at sites like [WCF Data Services](https://msdn.microsoft.com/library/cc668792.aspx), [www.OData.org](http://www.odata.org), and others. + + + Assuming that you already have database that you can operate against, there are four short steps: - - - + + + 1. Create a model of the database using the Microsoft [Entity Framework](https://msdn.microsoft.com/data/aa937723). There is no code required as this is a wizard-based creation in Visual Studio. For additional information, see [Entity Framework 4.0 and WCF Data Services 4.0 in Visual Studio 2010](https://msdn.microsoft.com/magazine/ee336128.aspx) and [Entity Framework Designer Gets Some Love in Visual Studio 2012](https://msdn.microsoft.com/magazine/jj721589.aspx). - - + + 2. Create a new WCF Data Service. Again, no code is required in this Visual Studio wizard. For more information, see Walkthrough: [Creating and Accessing a WCF Data Service in Visual Studio](https://msdn.microsoft.com/library/vstudio/cc668184.aspx). - - + + 3. In the service code file, set the name of the entity model that you created in step one to the source of the service; then, set the accessibility and permission for the entities in the model (both steps implemented in as little as two lines of code). - - + + 4. Publish the service to a location that Workflow Manager can access. - - + + ### Implementing OData service operations There's a pretty good chance that your workflow wants to run some business logic that doesn't fit into limited the CRUD-Q model. For example, there may be an OData service that supports CRUD-Q operations when it creates a new bank loan. This service might also ask for consumers to call the service and provide a credit score so it can then retrieve the current interest rate. Such a task exceeds the capability of simple CRUD-Q operations, since it calls a method, passes in an integer, and receives a response. - - - + + + However, you can support this scenario by using OData and WCF Data Services, through which you can implement [Service Operations](https://msdn.microsoft.com/library/cc668788.aspx). Service operations are common, and are even used in the SharePoint services. For example, when SharePoint retrieves a specific list using the address format `http://[..]/_api/web/lists/GetByTitle('ListTitle')`, the **GetByTitle()** function in the address is actually a service operator that was created by the SharePoint team. Typically, developers create their custom service operations in web services they create using WCF Data Services. - - - + + + ## Create a workflow with SharePoint Designer 2013 The following walkthrough demonstrates how to create a custom workflow that calls the OData web service of the Northwind database, which you can find publically hosted at the [www.odata.org](http://www.odata.org) site. In this sample, the user enters a customer ID and then starts the workflow, which takes the customer ID and uses it to query the web service to collect additional information about the customer - specifically, the user's full name and employer. The workflow then takes this information and updates the list item by adding the user's customer name and employer. - - - + + + ### Create a customer list 1. In SharePoint Designer 2013, create a custom list and name it "Customers". - - + + 2. Rename the **Title** field **to Customer Id**. - - + + 3. Add two new fields of type **String** and name them **Full Name** and **Employer**, as shown in Figure 2. - + **Figure 2. Creating the Customers list in SharePoint Designer 2013** - + ![Figure 2. Creating the Customers list in SP](../images/ngWSSP2013WorkflowSPD201302.png) - - - + + + ### Create the workflow 1. In the SharePoint Designer 2013 navigation pane, select the **Workflows** option. - - + + 2. On the ribbon, click the **List Workflows** button and select **Customers** from the resulting drop-down list. - - + + 3. Name the workflow "Get Customer Details". - - + + 4. Set the **Platform Type** to **SharePoint Workflow**, as shown in Figure 3. - + **Figure 3. Creating a new List Workflow using SharePoint Designer 2013** - + ![Figure 3. Creating a new List Workflow using SP](../images/ngWSSP2013WorkflowSPD201303.png) - - - + + + ### Query the web service for the customer details Now that we've created the workflow, we want to enable it to call a web service, which we do by adding a **Call HTTP Web Service** action to the workflow's default stage. - - - + + + 1. Click on the link labled **this**. - - + + 2. To the right of the **Enter the HTTP web service URL** text box, click the builder button ( **???**) to open the **String Builder** dialog box. - - -3. In the **String Builder**, enter this URL: `http://services.odata.org/Northwind/Northwind.svc/Customers('CUSTOMERID')?$format=json&$select=ContactName,CompanyName`. Notice the " `$select`" portion of the URL is retrieving only the fields that are relevant to this list. - - + + +3. In the **String Builder**, enter this URL: `http://services.odata.org/Northwind/Northwind.svc/Customers('CUSTOMERID')?$format=json&$select=ContactName,CompanyName`. Notice the " `$select`" portion of the URL is retrieving only the fields that are relevant to this list. + + 4. In the URL, locate the URL segment `CUSTOMERID` and remove it. Leave the parentheses and single quotes in place. - - + + 5. To then dynamically create the full URL, click the **Add or Change Lookup** button in the **String Builder**. - - + + 6. In the resulting **Lookup for String** dialog box, set the **Data Source** to **Current Item** and set the **Field from Source** to **CustomerId**, as shown in Figure 4. - + **Figure 4. Dynamically creating the URL for the web service request** - + ![Figure 4. Dynamically Creating the URL for the Web](../images/ngWSSP2013WorkflowSPD201304.png) - - - + + + 7. Click **OK**, then **OK** again to accept the new URL. - + Now that we've set this up to receive results from the web service, next we need to store the results in another variable. - - + + 8. In the **Call HTTP Web Service** action, click the **response** link in the action and create a new variable of type **Dictionary** and name it **nwServiceResponse**. - + The entire **Call HTTP Web Service** action is not likely visible, since it is a long sentence in the designer. Scroll to the right and notice that the response status code is stored in a variable called **responseCode**. This is convenient, and something that can be written to the workflow instance's statistics page using the workflow history list. - - + + 9. Add a **Log to History List** action after the **Call HTTP Web Service** action and set its **message** to write the status code for the response to the log, as shown in Figure 5. - + **Figure 5. Writing the Web Service Response Code to the History List** - + ![Figure 5. Writing the Web Service Response Code to](../images/ngWSSP2013WorkflowSPD201305.png) - - - + + + ### Extract values from response Now that we have the web service response stored in the **nwServiceResponse** variable, the next step is to extract these values and place them in local variables. - - - + + + To do this, we're going to add two **Get item from dictionary** actions to the workflow. Note that the path to the item from which we're going to extract a value has to match the structure of the response and be in a specific format. A good way to figure this out is to enter the URL into the browser to see the response that comes back. Notice that the results are nested within the object called **d**. Therefore the path to the field **CompanyName** in the web service response is `d/CompanyName`. - - - + + + 1. Add two **Get item from dictionary** actions to the workflow. - - + + 2. On the first of these new actions, set **item by name or path** to `d/ComopanyName`. - - + + 3. Set the **dictionary** link to **nwServiceResponse**. - - + + 4. Set the **item** link to a new **String** variable named **CompanyName**. - - + + 5. Repeat steps 2, 3, and 4 on the second **Get item from dictionary** action, except to use **ContactName** instead of "CompanyName", as shown in Figure 6. - + **Figure 6. Extracting Values from the Web Service Dictionary Response** - + ![Figure 6. Extracting Values from the Web Service D](../images/ngWSSP2013WorkflowSPD201306.png) - - - + + + ### Update the list item The final step is to update the list item using two of the **Set field in current item** actions. These set the fields in the list item to the values stored in the variables we created, as shown in Figure 7. - - - + + + **Figure 7. Update the List Item** - - - - - - + + + + + + ![Figure 7. Update the List Item](../images/ngWSSP2013WorkflowSPD201307.png) - - - + + + And finally, we complete the **Transition to stage** section of the workflow stage. - - - + + + 1. Add a **Go To Stage** action. - - + + 2. Select **End of workflow**. - - + + 3. Save and publish the workflow. - - + + ### Test the workflow 1. Open a browser and navigate to the **Customers** list. - - + + 2. Add the two customer IDs that are in the Northwind service on two new list items, **ALFKI** and **ANATR**. - - + + 3. Manually start the workflows by selecting each item, then clicking the **Workflows** button on the ribbon. - - + + 4. Select the **Get Customer Details** workflow. - + At this point the workflow will start and will query the web service. - - + + 5. Navigate back to the **Customers** list and refresh the page. It might take a few refreshes for the workflows to complete, but eventually it should look like the image in Figure 8. You should see both list items updated with the customer's full name and their employer, which came from the Northwind web service. - + **Figure 8. List Items Updated by Custom Workflow** - + ![Figure 8. List Items Updated by Custom Workflow](../images/ngWSSP2013WorkflowSPD201308.png) - - - + + + ## Conclusion SharePointintroduced a new workflow architecture facilitated by a new product, Workflow Manager 1.0. To ensure that all custom workflows worked regardless of the SharePoint deployment choice, either on-premises or hosted in Office 365, all workflows are now 100 percent declarative. The added support for calling web services from SharePoint Designer 2013-authored workflows provides a more flexible and powerful workflow authoring process than in previous versions. - - - + + + Microsoft introduced support for calling web services in Workflow Manager using the new **Call HTTP Web Service** action in SharePoint Designer 2013. Workflow Manager also introduced support for creating structures to submit to web services as well as consuming their responses using the **Dictionary** variable type. When creating workflows, use the **Dictionary** type and associated actions in SharePoint workflows that use external web services. - - - + + + ## See also - [Workflows in SharePoint](workflows-in-sharepoint.md) - - + + - [OData](http://www.odata.org/) - - + + - [Introducing JSON](http://json.org/) - - + + - [Get started with the SharePoint REST service](https://msdn.microsoft.com/library/office/fp142380.aspx) - - -- [Entity Framework 4.0 and WCF Data Services 4.0 in Visual Studio 2010](https://msdn.microsoft.com/magazine/ee336128.aspx) - - - - - +- [Entity Framework 4.0 and WCF Data Services 4.0 in Visual Studio 2010](https://msdn.microsoft.com/magazine/ee336128.aspx) diff --git a/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-visual-studio-2012.md b/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-visual-studio-2012.md index 8345aab66..619094951 100644 --- a/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-visual-studio-2012.md +++ b/docs/general-development/working-with-web-services-in-sharepoint-workflows-using-visual-studio-2012.md @@ -1,16 +1,15 @@ --- title: Working with Web Services in SharePoint Workflows using Visual Studio 2012 description: Demonstrates how to use web services in SharePoint workflows using Visual Studio 2012. -ms.date: 01/06/2020 -ms.prod: sharepoint +ms.date: 10/15/2022 ms.assetid: 5ffaa585-a872-4e14-bc0e-4a38c6a16b04 -localization_priority: Normal +ms.localizationpriority: medium --- # Working with Web Services in SharePoint Workflows using Visual Studio 2012 Demonstrates how to use web services in SharePoint workflows using Visual Studio 2012. -**Provided by:** [Andrew Connell](https://www.andrewconnell), [Voitanos](https://www.voitanos.io) +**Provided by:** [Andrew Connell](https://www.andrewconnell.com), [Voitanos](https://www.voitanos.io) > [!NOTE] > SharePoint 2010 workflows have been retired since August 1, 2020 for new tenants and removed from existing tenants on November 1, 2020. If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions. For more info, see [SharePoint 2010 workflow retirement](https://support.microsoft.com/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f). diff --git a/docs/images/118-release-notes/ace-search-box.png b/docs/images/118-release-notes/ace-search-box.png new file mode 100644 index 000000000..8640cf6c5 Binary files /dev/null and b/docs/images/118-release-notes/ace-search-box.png differ diff --git a/docs/images/118-release-notes/ace-text-input-body.png b/docs/images/118-release-notes/ace-text-input-body.png new file mode 100644 index 000000000..6f7a71a79 Binary files /dev/null and b/docs/images/118-release-notes/ace-text-input-body.png differ diff --git a/docs/images/118-release-notes/ace-text-input-footer.png b/docs/images/118-release-notes/ace-text-input-footer.png new file mode 100644 index 000000000..ff1a64f1f Binary files /dev/null and b/docs/images/118-release-notes/ace-text-input-footer.png differ diff --git a/docs/images/119-release-notes/chart-card-viva-connections.png b/docs/images/119-release-notes/chart-card-viva-connections.png new file mode 100644 index 000000000..f400665bd Binary files /dev/null and b/docs/images/119-release-notes/chart-card-viva-connections.png differ diff --git a/docs/images/120-release-notes/chart-cards-options.png b/docs/images/120-release-notes/chart-cards-options.png new file mode 100644 index 000000000..e35deb436 Binary files /dev/null and b/docs/images/120-release-notes/chart-cards-options.png differ diff --git a/docs/images/120-release-notes/html-quick-views.png b/docs/images/120-release-notes/html-quick-views.png new file mode 100644 index 000000000..25b355490 Binary files /dev/null and b/docs/images/120-release-notes/html-quick-views.png differ diff --git a/docs/images/121-release-notes/card-personalization.png b/docs/images/121-release-notes/card-personalization.png new file mode 100644 index 000000000..227a84abc Binary files /dev/null and b/docs/images/121-release-notes/card-personalization.png differ diff --git a/docs/images/121-release-notes/flex-layout.png b/docs/images/121-release-notes/flex-layout.png new file mode 100644 index 000000000..527d2c6c6 Binary files /dev/null and b/docs/images/121-release-notes/flex-layout.png differ diff --git a/docs/images/add-in-add-from-file.png b/docs/images/add-in-add-from-file.png deleted file mode 100644 index c51f73652..000000000 Binary files a/docs/images/add-in-add-from-file.png and /dev/null differ diff --git a/docs/images/add-in-get-add-ins-context-menu.png b/docs/images/add-in-get-add-ins-context-menu.png deleted file mode 100644 index edd96fec8..000000000 Binary files a/docs/images/add-in-get-add-ins-context-menu.png and /dev/null differ diff --git a/docs/images/add-in-install-warning.png b/docs/images/add-in-install-warning.png deleted file mode 100644 index cb16e502d..000000000 Binary files a/docs/images/add-in-install-warning.png and /dev/null differ diff --git a/docs/images/add-in-my-addins-menu.png b/docs/images/add-in-my-addins-menu.png deleted file mode 100644 index c5a960565..000000000 Binary files a/docs/images/add-in-my-addins-menu.png and /dev/null differ diff --git a/docs/images/add-in-solution-structure.png b/docs/images/add-in-solution-structure.png deleted file mode 100644 index ddcecb61a..000000000 Binary files a/docs/images/add-in-solution-structure.png and /dev/null differ diff --git a/docs/images/add-in-solution-upload-catalog.png b/docs/images/add-in-solution-upload-catalog.png deleted file mode 100644 index 4509e6798..000000000 Binary files a/docs/images/add-in-solution-upload-catalog.png and /dev/null differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-add-api-permissions.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-add-api-permissions.png new file mode 100644 index 000000000..5dc7ea25b Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-add-api-permissions.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-automatic-permissions.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-automatic-permissions.png new file mode 100644 index 000000000..ccd9b6a35 Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-automatic-permissions.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-grant-api-permissions.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-grant-api-permissions.png new file mode 100644 index 000000000..4d7459ea7 Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-grant-api-permissions.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-manual-certificate-upload.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-manual-certificate-upload.png new file mode 100644 index 000000000..c0aa1e15d Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-manual-certificate-upload.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-registered.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-registered.png new file mode 100644 index 000000000..ef014bdbe Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-registered.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-registrations.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-registrations.png new file mode 100644 index 000000000..2d9f9e25f Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-app-registrations.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-register-an-application.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-register-an-application.png new file mode 100644 index 000000000..d0d556967 Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-aad-register-an-application.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-appinv.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-appinv.png new file mode 100644 index 000000000..15b9778ee Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-appinv.png differ diff --git a/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-appregnew.png b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-appregnew.png new file mode 100644 index 000000000..e8533c3b0 Binary files /dev/null and b/docs/images/add-in-transform/from-acs-to-aad-apps/from-acs-to-aad-apps-acs-appregnew.png differ diff --git a/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-app-manifest.png b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-app-manifest.png new file mode 100644 index 000000000..33c6c757c Binary files /dev/null and b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-app-manifest.png differ diff --git a/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-app-part-ui.png b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-app-part-ui.png new file mode 100644 index 000000000..8fa7fdea9 Binary files /dev/null and b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-app-part-ui.png differ diff --git a/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-spfx-outline.png b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-spfx-outline.png new file mode 100644 index 000000000..78cdfbb8a Binary files /dev/null and b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-spfx-outline.png differ diff --git a/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-workbench-add.png b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-workbench-add.png new file mode 100644 index 000000000..28dd87473 Binary files /dev/null and b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-workbench-add.png differ diff --git a/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-workbench-output.png b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-workbench-output.png new file mode 100644 index 000000000..e5408b588 Binary files /dev/null and b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-workbench-output.png differ diff --git a/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-yo-console.png b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-yo-console.png new file mode 100644 index 000000000..5c3d22806 Binary files /dev/null and b/docs/images/add-in-transform/from-app-parts-to-modern-web-parts/from-app-parts-to-modern-web-parts-yo-console.png differ diff --git a/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-output.png b/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-output.png new file mode 100644 index 000000000..281d954b4 Binary files /dev/null and b/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-output.png differ diff --git a/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-spfx-outline.png b/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-spfx-outline.png new file mode 100644 index 000000000..37fa6ed69 Binary files /dev/null and b/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-spfx-outline.png differ diff --git a/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-yo-console.png b/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-yo-console.png new file mode 100644 index 000000000..a9f4a116d Binary files /dev/null and b/docs/images/add-in-transform/from-classic-dialogs-to-modern-dialogs/from-classic-dialogs-to-modern-dialogs-yo-console.png differ diff --git a/docs/images/add-in-transform/from-jsom-to-client-side/from-jsom-to-client-side-yo-console-react.png b/docs/images/add-in-transform/from-jsom-to-client-side/from-jsom-to-client-side-yo-console-react.png new file mode 100644 index 000000000..cf7654de4 Binary files /dev/null and b/docs/images/add-in-transform/from-jsom-to-client-side/from-jsom-to-client-side-yo-console-react.png differ diff --git a/docs/images/add-in-transform/from-jsom-to-client-side/from-jsom-to-client-side-yo-console.png b/docs/images/add-in-transform/from-jsom-to-client-side/from-jsom-to-client-side-yo-console.png new file mode 100644 index 000000000..f1c523816 Binary files /dev/null and b/docs/images/add-in-transform/from-jsom-to-client-side/from-jsom-to-client-side-yo-console.png differ diff --git a/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-header-output.png b/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-header-output.png new file mode 100644 index 000000000..abaa009c8 Binary files /dev/null and b/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-header-output.png differ diff --git a/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-spfx-outline.png b/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-spfx-outline.png new file mode 100644 index 000000000..aba992ffc Binary files /dev/null and b/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-spfx-outline.png differ diff --git a/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-yo-console.png b/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-yo-console.png new file mode 100644 index 000000000..7e2b12c84 Binary files /dev/null and b/docs/images/add-in-transform/from-notifications-to-application-customizers/from-notifications-to-application-customizers-yo-console.png differ diff --git a/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-aad-app-permissions.png b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-aad-app-permissions.png new file mode 100644 index 000000000..2dfb6d703 Binary files /dev/null and b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-aad-app-permissions.png differ diff --git a/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-01.png b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-01.png new file mode 100644 index 000000000..44021cbb3 Binary files /dev/null and b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-01.png differ diff --git a/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-02.png b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-02.png new file mode 100644 index 000000000..fa4d464c1 Binary files /dev/null and b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-02.png differ diff --git a/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-03.png b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-03.png new file mode 100644 index 000000000..c820926eb Binary files /dev/null and b/docs/images/add-in-transform/from-provider-hosted-to-aad-applications/from-provider-hosted-to-aad-applications-vs2022-wizard-03.png differ diff --git a/docs/images/add-in-transform/from-remote-event-receivers-to-webhooks/from-remote-event-receivers-to-webhooks-outline.png b/docs/images/add-in-transform/from-remote-event-receivers-to-webhooks/from-remote-event-receivers-to-webhooks-outline.png new file mode 100644 index 000000000..0d443ad6d Binary files /dev/null and b/docs/images/add-in-transform/from-remote-event-receivers-to-webhooks/from-remote-event-receivers-to-webhooks-outline.png differ diff --git a/docs/images/add-in-transform/from-sharepoint-hosted-to-client-side/from-sharepoint-hosted-to-client-side-generator.png b/docs/images/add-in-transform/from-sharepoint-hosted-to-client-side/from-sharepoint-hosted-to-client-side-generator.png new file mode 100644 index 000000000..a0410e9b8 Binary files /dev/null and b/docs/images/add-in-transform/from-sharepoint-hosted-to-client-side/from-sharepoint-hosted-to-client-side-generator.png differ diff --git a/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-app-manifest.png b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-app-manifest.png new file mode 100644 index 000000000..9032ca015 Binary files /dev/null and b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-app-manifest.png differ diff --git a/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-ecb.png b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-ecb.png new file mode 100644 index 000000000..d01adbb99 Binary files /dev/null and b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-ecb.png differ diff --git a/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-old-output.png b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-old-output.png new file mode 100644 index 000000000..eabdf3b56 Binary files /dev/null and b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-old-output.png differ diff --git a/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-ribbon.png b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-ribbon.png new file mode 100644 index 000000000..b23d78363 Binary files /dev/null and b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-ribbon.png differ diff --git a/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-spfx-outline.png b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-spfx-outline.png new file mode 100644 index 000000000..482fa4934 Binary files /dev/null and b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-spfx-outline.png differ diff --git a/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-spfx-output.png b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-spfx-output.png new file mode 100644 index 000000000..022342e6f Binary files /dev/null and b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-spfx-output.png differ diff --git a/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-yo-console.png b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-yo-console.png new file mode 100644 index 000000000..8b2d605d1 Binary files /dev/null and b/docs/images/add-in-transform/from-ui-extensions-to-listview-command-sets/from-ui-extension-to-listview-command-set-yo-console.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-maker-ui-01.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-maker-ui-01.png new file mode 100644 index 000000000..49c4320b1 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-maker-ui-01.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-maker-ui-02.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-maker-ui-02.png new file mode 100644 index 000000000..a23ff9dec Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-maker-ui-02.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-01.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-01.png new file mode 100644 index 000000000..f996c5559 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-01.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-02.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-02.png new file mode 100644 index 000000000..8af3599a0 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-02.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-03.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-03.png new file mode 100644 index 000000000..ab31482a2 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-03.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-04.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-04.png new file mode 100644 index 000000000..c8dc45748 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-04.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-05.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-05.png new file mode 100644 index 000000000..95513157f Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-05.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-06.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-06.png new file mode 100644 index 000000000..3759ccd43 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-06.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-07.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-07.png new file mode 100644 index 000000000..a3b60c0c2 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-07.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-08.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-08.png new file mode 100644 index 000000000..f5f4da85a Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-08.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-09.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-09.png new file mode 100644 index 000000000..780312e0b Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-09.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-10.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-10.png new file mode 100644 index 000000000..24a6cfab5 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-10.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-11.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-11.png new file mode 100644 index 000000000..c54814988 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-11.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-12.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-12.png new file mode 100644 index 000000000..3ab4773d1 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-12.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-13.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-13.png new file mode 100644 index 000000000..641dc7a6e Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-13.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-14.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-14.png new file mode 100644 index 000000000..5b10bbb8e Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-14.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-15.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-15.png new file mode 100644 index 000000000..2f3405033 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-spo-ui-15.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-01.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-01.png new file mode 100644 index 000000000..1111bf9dc Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-01.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-02.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-02.png new file mode 100644 index 000000000..dda1dde2a Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-02.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-03.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-03.png new file mode 100644 index 000000000..f6a485e0b Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-03.png differ diff --git a/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-04.png b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-04.png new file mode 100644 index 000000000..20ac5d2c6 Binary files /dev/null and b/docs/images/add-in-transform/from-workflow-apps-to-power-automate/from-workflow-apps-to-power-automate-vs2019-04.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-01.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-01.png new file mode 100644 index 000000000..1693eec35 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-01.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-02.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-02.png new file mode 100644 index 000000000..26d8cdad7 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-02.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-03.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-03.png new file mode 100644 index 000000000..2461433af Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-03.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-04.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-04.png new file mode 100644 index 000000000..e30a7e163 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-04.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-05.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-05.png new file mode 100644 index 000000000..422709e30 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-05.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-06.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-06.png new file mode 100644 index 000000000..f27b1e322 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-06.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-07.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-07.png new file mode 100644 index 000000000..f1ec8804e Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-column-formatting-ui-07.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-01.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-01.png new file mode 100644 index 000000000..5013e0537 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-01.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-02.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-02.png new file mode 100644 index 000000000..55d10a129 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-02.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-03.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-03.png new file mode 100644 index 000000000..5213c6bb9 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-03.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-04.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-04.png new file mode 100644 index 000000000..0e9f151bc Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-form-formatting-ui-04.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-initial-list.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-initial-list.png new file mode 100644 index 000000000..27baf4918 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-initial-list.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-01.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-01.png new file mode 100644 index 000000000..fa5069db1 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-01.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-02.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-02.png new file mode 100644 index 000000000..69fe670d7 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-02.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-03.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-03.png new file mode 100644 index 000000000..d9d20cd4d Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-03.png differ diff --git a/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-04.png b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-04.png new file mode 100644 index 000000000..aa6b64ac2 Binary files /dev/null and b/docs/images/add-in-transform/from-xslt-to-list-formatting/from-xslt-to-list-formatting-list-view-formatting-ui-04.png differ diff --git a/docs/images/add-in-transform/modern-provisioning/modern-provisioning-spfx-outline.png b/docs/images/add-in-transform/modern-provisioning/modern-provisioning-spfx-outline.png new file mode 100644 index 000000000..02046e2e8 Binary files /dev/null and b/docs/images/add-in-transform/modern-provisioning/modern-provisioning-spfx-outline.png differ diff --git a/docs/images/add-in-transform/modern-provisioning/modern-provisioning-vs-addin-outline.png b/docs/images/add-in-transform/modern-provisioning/modern-provisioning-vs-addin-outline.png new file mode 100644 index 000000000..ea51c32e1 Binary files /dev/null and b/docs/images/add-in-transform/modern-provisioning/modern-provisioning-vs-addin-outline.png differ diff --git a/docs/images/add-in-transform/modern-provisioning/modern-provisioning-yo-console.png b/docs/images/add-in-transform/modern-provisioning/modern-provisioning-yo-console.png new file mode 100644 index 000000000..7ed756382 Binary files /dev/null and b/docs/images/add-in-transform/modern-provisioning/modern-provisioning-yo-console.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-app-registration.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-app-registration.png new file mode 100644 index 000000000..12c9f5dba Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-app-registration.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-endpoints.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-endpoints.png new file mode 100644 index 000000000..a9c79cddb Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-endpoints.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-enterprise-application.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-enterprise-application.png new file mode 100644 index 000000000..64ce75e65 Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-enterprise-application.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-admin-tenant-not-admin.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-admin-tenant-not-admin.png new file mode 100644 index 000000000..0d16f1ac9 Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-admin-tenant-not-admin.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-admin-tenant.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-admin-tenant.png new file mode 100644 index 000000000..c35387cde Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-admin-tenant.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-user-admin.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-user-admin.png new file mode 100644 index 000000000..d8b8d16e0 Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-user-admin.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-user-not-admin.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-user-not-admin.png new file mode 100644 index 000000000..1b80a3556 Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions-grant-user-not-admin.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions.png new file mode 100644 index 000000000..5e721780b Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-permissions.png differ diff --git a/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-spfx-consent-flow.png b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-spfx-consent-flow.png new file mode 100644 index 000000000..55cfb6b1b Binary files /dev/null and b/docs/images/add-in-transform/multi-tenant-applications/multi-tenant-applications-aad-spfx-consent-flow.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-01.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-01.png new file mode 100644 index 000000000..8435e6f80 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-01.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-02.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-02.png new file mode 100644 index 000000000..dd96f01f3 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-02.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-03.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-03.png new file mode 100644 index 000000000..390a69e81 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-03.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-04.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-04.png new file mode 100644 index 000000000..be55238de Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-04.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-05.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-05.png new file mode 100644 index 000000000..eae601af6 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-05.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-06.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-06.png new file mode 100644 index 000000000..aad608120 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-06.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-07.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-07.png new file mode 100644 index 000000000..fef1faa3e Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-07.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-08.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-08.png new file mode 100644 index 000000000..41b69865d Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-08.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-09.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-09.png new file mode 100644 index 000000000..26dd8c70e Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-09.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-10.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-10.png new file mode 100644 index 000000000..f6f0674ef Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-10.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-11.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-11.png new file mode 100644 index 000000000..fc248c3e6 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-11.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-12.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-12.png new file mode 100644 index 000000000..4e36c9958 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-12.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-13.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-13.png new file mode 100644 index 000000000..276b0c299 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-13.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-14.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-14.png new file mode 100644 index 000000000..514ac20d7 Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-14.png differ diff --git a/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-15.png b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-15.png new file mode 100644 index 000000000..ae5c0862f Binary files /dev/null and b/docs/images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-15.png differ diff --git a/docs/images/add-in-transform/understanding-aad-oauth-for-spfx/understanding-aad-oauth-for-spfx-msgraph-access-token-claims.png b/docs/images/add-in-transform/understanding-aad-oauth-for-spfx/understanding-aad-oauth-for-spfx-msgraph-access-token-claims.png new file mode 100644 index 000000000..ebfe5f417 Binary files /dev/null and b/docs/images/add-in-transform/understanding-aad-oauth-for-spfx/understanding-aad-oauth-for-spfx-msgraph-access-token-claims.png differ diff --git a/docs/images/add-in-transform/understanding-aad-oauth-for-spfx/understanding-aad-oauth-for-spfx-msgraph-access-token-webpart-ui.png b/docs/images/add-in-transform/understanding-aad-oauth-for-spfx/understanding-aad-oauth-for-spfx-msgraph-access-token-webpart-ui.png new file mode 100644 index 000000000..e0ad055da Binary files /dev/null and b/docs/images/add-in-transform/understanding-aad-oauth-for-spfx/understanding-aad-oauth-for-spfx-msgraph-access-token-webpart-ui.png differ diff --git a/docs/images/add-in-transform/understanding-rsc-for-msgraph-and-sharepoint-online/understanding-rsc-for-msgraph-and-sharepoint-online-sites.selected-graph.png b/docs/images/add-in-transform/understanding-rsc-for-msgraph-and-sharepoint-online/understanding-rsc-for-msgraph-and-sharepoint-online-sites.selected-graph.png new file mode 100644 index 000000000..4ae737bb3 Binary files /dev/null and b/docs/images/add-in-transform/understanding-rsc-for-msgraph-and-sharepoint-online/understanding-rsc-for-msgraph-and-sharepoint-online-sites.selected-graph.png differ diff --git a/docs/images/add-in-transform/understanding-rsc-for-msgraph-and-sharepoint-online/understanding-rsc-for-msgraph-and-sharepoint-online-sites.selected-spo.png b/docs/images/add-in-transform/understanding-rsc-for-msgraph-and-sharepoint-online/understanding-rsc-for-msgraph-and-sharepoint-online-sites.selected-spo.png new file mode 100644 index 000000000..c2249fb68 Binary files /dev/null and b/docs/images/add-in-transform/understanding-rsc-for-msgraph-and-sharepoint-online/understanding-rsc-for-msgraph-and-sharepoint-online-sites.selected-spo.png differ diff --git a/docs/images/add-in-upload-solution-deploy.png b/docs/images/add-in-upload-solution-deploy.png deleted file mode 100644 index 88365e890..000000000 Binary files a/docs/images/add-in-upload-solution-deploy.png and /dev/null differ diff --git a/docs/images/app-installed-your-site.png b/docs/images/app-installed-your-site.png index c983ba5c1..72dd35f88 100644 Binary files a/docs/images/app-installed-your-site.png and b/docs/images/app-installed-your-site.png differ diff --git a/docs/images/appregnewaspx.png b/docs/images/appregnewaspx.png new file mode 100644 index 000000000..ae371d078 Binary files /dev/null and b/docs/images/appregnewaspx.png differ diff --git a/docs/images/brand-center-spfx-01.png b/docs/images/brand-center-spfx-01.png new file mode 100644 index 000000000..de9de224c Binary files /dev/null and b/docs/images/brand-center-spfx-01.png differ diff --git a/docs/images/brand-center-spfx-02.png b/docs/images/brand-center-spfx-02.png new file mode 100644 index 000000000..4ee2380c6 Binary files /dev/null and b/docs/images/brand-center-spfx-02.png differ diff --git a/docs/images/brand-center-spfx-03.png b/docs/images/brand-center-spfx-03.png new file mode 100644 index 000000000..c951e8e2b Binary files /dev/null and b/docs/images/brand-center-spfx-03.png differ diff --git a/docs/images/brand-center-spfx-04.png b/docs/images/brand-center-spfx-04.png new file mode 100644 index 000000000..c648b76f2 Binary files /dev/null and b/docs/images/brand-center-spfx-04.png differ diff --git a/docs/images/brand-center-spfx-05.png b/docs/images/brand-center-spfx-05.png new file mode 100644 index 000000000..6640c1e2f Binary files /dev/null and b/docs/images/brand-center-spfx-05.png differ diff --git a/docs/images/calendar-view-formatting-result.gif b/docs/images/calendar-view-formatting-result.gif new file mode 100644 index 000000000..6173eff22 Binary files /dev/null and b/docs/images/calendar-view-formatting-result.gif differ diff --git a/docs/images/calendar-view-formatting.png b/docs/images/calendar-view-formatting.png new file mode 100644 index 000000000..26e5f8706 Binary files /dev/null and b/docs/images/calendar-view-formatting.png differ diff --git a/docs/images/cdn-override-helloworld-webpart-package.png b/docs/images/cdn-override-helloworld-webpart-package.png index 86172b364..37411f9f2 100644 Binary files a/docs/images/cdn-override-helloworld-webpart-package.png and b/docs/images/cdn-override-helloworld-webpart-package.png differ diff --git a/docs/images/cdn-web-part-rendering.png b/docs/images/cdn-web-part-rendering.png index cfe50164c..87086737f 100644 Binary files a/docs/images/cdn-web-part-rendering.png and b/docs/images/cdn-web-part-rendering.png differ diff --git a/docs/images/cnd-trust-helloworld-webpart-solution.png b/docs/images/cnd-trust-helloworld-webpart-solution.png index 3f20d7dd3..b9a07ec9d 100644 Binary files a/docs/images/cnd-trust-helloworld-webpart-solution.png and b/docs/images/cnd-trust-helloworld-webpart-solution.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/add-app-with-tss.png b/docs/images/content-securty-policy-trusted-script-sources/add-app-with-tss.png new file mode 100644 index 000000000..9c0aaafb8 Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/add-app-with-tss.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/add-script-source.png b/docs/images/content-securty-policy-trusted-script-sources/add-script-source.png new file mode 100644 index 000000000..bcfa4234b Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/add-script-source.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/browser-console.png b/docs/images/content-securty-policy-trusted-script-sources/browser-console.png new file mode 100644 index 000000000..a81043c0e Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/browser-console.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/purview-audit-record.png b/docs/images/content-securty-policy-trusted-script-sources/purview-audit-record.png new file mode 100644 index 000000000..247ab069f Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/purview-audit-record.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/purview-results.png b/docs/images/content-securty-policy-trusted-script-sources/purview-results.png new file mode 100644 index 000000000..491a23ee3 Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/purview-results.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/purview-search.png b/docs/images/content-securty-policy-trusted-script-sources/purview-search.png new file mode 100644 index 000000000..a61356271 Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/purview-search.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/spac-tss-nav.png b/docs/images/content-securty-policy-trusted-script-sources/spac-tss-nav.png new file mode 100644 index 000000000..2efbafa58 Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/spac-tss-nav.png differ diff --git a/docs/images/content-securty-policy-trusted-script-sources/spac-tss-page.png b/docs/images/content-securty-policy-trusted-script-sources/spac-tss-page.png new file mode 100644 index 000000000..9c40b5537 Binary files /dev/null and b/docs/images/content-securty-policy-trusted-script-sources/spac-tss-page.png differ diff --git a/docs/images/custom-property-pane-control-cascading-items-loaded-enabled.png b/docs/images/custom-property-pane-control-cascading-items-loaded-enabled.png index 37ea16c03..72ec5c01d 100644 Binary files a/docs/images/custom-property-pane-control-cascading-items-loaded-enabled.png and b/docs/images/custom-property-pane-control-cascading-items-loaded-enabled.png differ diff --git a/docs/images/custom-property-pane-control-cascading-lists-loaded-items-disabled.png b/docs/images/custom-property-pane-control-cascading-lists-loaded-items-disabled.png index d58e664f7..b7a9fbf9a 100644 Binary files a/docs/images/custom-property-pane-control-cascading-lists-loaded-items-disabled.png and b/docs/images/custom-property-pane-control-cascading-lists-loaded-items-disabled.png differ diff --git a/docs/images/custom-property-pane-control-cascading-loading-items.png b/docs/images/custom-property-pane-control-cascading-loading-items.png index 5c6dce0a7..23ea52e93 100644 Binary files a/docs/images/custom-property-pane-control-cascading-loading-items.png and b/docs/images/custom-property-pane-control-cascading-loading-items.png differ diff --git a/docs/images/custom-property-pane-control-cascading-loading-lists.png b/docs/images/custom-property-pane-control-cascading-loading-lists.png index 47c16d9d2..5021180ae 100644 Binary files a/docs/images/custom-property-pane-control-cascading-loading-lists.png and b/docs/images/custom-property-pane-control-cascading-loading-lists.png differ diff --git a/docs/images/custom-property-pane-control-cascading-selected-list-item.png b/docs/images/custom-property-pane-control-cascading-selected-list-item.png index 460e9e986..ad9bd65dd 100644 Binary files a/docs/images/custom-property-pane-control-cascading-selected-list-item.png and b/docs/images/custom-property-pane-control-cascading-selected-list-item.png differ diff --git a/docs/images/custom-property-pane-control-loading-options.png b/docs/images/custom-property-pane-control-loading-options.png index b68678e70..fa62315e4 100644 Binary files a/docs/images/custom-property-pane-control-loading-options.png and b/docs/images/custom-property-pane-control-loading-options.png differ diff --git a/docs/images/custom-property-pane-control-selecting-option.png b/docs/images/custom-property-pane-control-selecting-option.png index 8e7ebecdc..0b695c961 100644 Binary files a/docs/images/custom-property-pane-control-selecting-option.png and b/docs/images/custom-property-pane-control-selecting-option.png differ diff --git a/docs/images/custom-property-pane-control-web-part-first-run.png b/docs/images/custom-property-pane-control-web-part-first-run.png index 8243c5415..c4c93eab0 100644 Binary files a/docs/images/custom-property-pane-control-web-part-first-run.png and b/docs/images/custom-property-pane-control-web-part-first-run.png differ diff --git a/docs/images/deploy-create-cdn-cache-control-header.png b/docs/images/deploy-create-cdn-cache-control-header.png new file mode 100644 index 000000000..be9274a2f Binary files /dev/null and b/docs/images/deploy-create-cdn-cache-control-header.png differ diff --git a/docs/images/discoverdomainisolatedwebpartusage.png b/docs/images/discoverdomainisolatedwebpartusage.png new file mode 100644 index 000000000..c23769db3 Binary files /dev/null and b/docs/images/discoverdomainisolatedwebpartusage.png differ diff --git a/docs/images/edit-webpart-modern-page.png b/docs/images/edit-webpart-modern-page.png index 566f6cf94..cdc094b75 100644 Binary files a/docs/images/edit-webpart-modern-page.png and b/docs/images/edit-webpart-modern-page.png differ diff --git a/docs/images/ext-app-approve-cdn-address.png b/docs/images/ext-app-approve-cdn-address.png index ee6709f99..1c69a0a7e 100644 Binary files a/docs/images/ext-app-approve-cdn-address.png and b/docs/images/ext-app-approve-cdn-address.png differ diff --git a/docs/images/ext-app-header-footer-visible.png b/docs/images/ext-app-header-footer-visible.png index 1309a4063..ac3cd3063 100644 Binary files a/docs/images/ext-app-header-footer-visible.png and b/docs/images/ext-app-header-footer-visible.png differ diff --git a/docs/images/ext-app-install-solution-to-site.png b/docs/images/ext-app-install-solution-to-site.png index 2d002e84a..668864314 100644 Binary files a/docs/images/ext-app-install-solution-to-site.png and b/docs/images/ext-app-install-solution-to-site.png differ diff --git a/docs/images/ext-app-sppkg-deploy-trust.png b/docs/images/ext-app-sppkg-deploy-trust.png index aeb3a4ad5..c20cb39b1 100644 Binary files a/docs/images/ext-app-sppkg-deploy-trust.png and b/docs/images/ext-app-sppkg-deploy-trust.png differ diff --git a/docs/images/ext-forcustomizer-accept-debug-scripts.png b/docs/images/ext-forcustomizer-accept-debug-scripts.png new file mode 100644 index 000000000..b03cdb9cc Binary files /dev/null and b/docs/images/ext-forcustomizer-accept-debug-scripts.png differ diff --git a/docs/images/ext-forcustomizer-blank-list.png b/docs/images/ext-forcustomizer-blank-list.png new file mode 100644 index 000000000..4d05f27e3 Binary files /dev/null and b/docs/images/ext-forcustomizer-blank-list.png differ diff --git a/docs/images/ext-forcustomizer-create-new-list.png b/docs/images/ext-forcustomizer-create-new-list.png new file mode 100644 index 000000000..1762b3a97 Binary files /dev/null and b/docs/images/ext-forcustomizer-create-new-list.png differ diff --git a/docs/images/ext-forcustomizer-custom-form.png b/docs/images/ext-forcustomizer-custom-form.png new file mode 100644 index 000000000..bf39c0844 Binary files /dev/null and b/docs/images/ext-forcustomizer-custom-form.png differ diff --git a/docs/images/ext-forcustomizer-default-output.png b/docs/images/ext-forcustomizer-default-output.png new file mode 100644 index 000000000..30e71e5b3 Binary files /dev/null and b/docs/images/ext-forcustomizer-default-output.png differ diff --git a/docs/images/ext-forcustomizer-gulp-serve.png b/docs/images/ext-forcustomizer-gulp-serve.png new file mode 100644 index 000000000..aadf890ad Binary files /dev/null and b/docs/images/ext-forcustomizer-gulp-serve.png differ diff --git a/docs/images/ext-forcustomizer-new-list-business.png b/docs/images/ext-forcustomizer-new-list-business.png new file mode 100644 index 000000000..41b8a9ebc Binary files /dev/null and b/docs/images/ext-forcustomizer-new-list-business.png differ diff --git a/docs/images/ext-tenant-wide-solution-deployment-modern.png b/docs/images/ext-tenant-wide-solution-deployment-modern.png new file mode 100644 index 000000000..abd78938d Binary files /dev/null and b/docs/images/ext-tenant-wide-solution-deployment-modern.png differ diff --git a/docs/images/helloworld-wp-gulp-serve.png b/docs/images/helloworld-wp-gulp-serve.png deleted file mode 100644 index d9fd16414..000000000 Binary files a/docs/images/helloworld-wp-gulp-serve.png and /dev/null differ diff --git a/docs/images/image-helper-api-01.png b/docs/images/image-helper-api-01.png new file mode 100644 index 000000000..875908e38 Binary files /dev/null and b/docs/images/image-helper-api-01.png differ diff --git a/docs/images/image-helper-api-02.png b/docs/images/image-helper-api-02.png new file mode 100644 index 000000000..00d150018 Binary files /dev/null and b/docs/images/image-helper-api-02.png differ diff --git a/docs/images/install-app-your-site.png b/docs/images/install-app-your-site.png index 9e55514f7..fe7ee8e4d 100644 Binary files a/docs/images/install-app-your-site.png and b/docs/images/install-app-your-site.png differ diff --git a/docs/images/msteams-app-leadassistdashboard-install-apps.png b/docs/images/msteams-app-leadassistdashboard-install-apps.png new file mode 100644 index 000000000..6f7d55ff6 Binary files /dev/null and b/docs/images/msteams-app-leadassistdashboard-install-apps.png differ diff --git a/docs/images/msteams-app-leadassistdashboard-installed-app-sharepoint-01.png b/docs/images/msteams-app-leadassistdashboard-installed-app-sharepoint-01.png new file mode 100644 index 000000000..962842eb2 Binary files /dev/null and b/docs/images/msteams-app-leadassistdashboard-installed-app-sharepoint-01.png differ diff --git a/docs/images/msteams-app-leadassistdashboard-installed-app-teams-01.png b/docs/images/msteams-app-leadassistdashboard-installed-app-teams-01.png new file mode 100644 index 000000000..d11e63452 Binary files /dev/null and b/docs/images/msteams-app-leadassistdashboard-installed-app-teams-01.png differ diff --git a/docs/images/msteams-app-leadassistdashboard-installed-app-teams-02.png b/docs/images/msteams-app-leadassistdashboard-installed-app-teams-02.png new file mode 100644 index 000000000..c57c67feb Binary files /dev/null and b/docs/images/msteams-app-leadassistdashboard-installed-app-teams-02.png differ diff --git a/docs/images/new-app-catalog-experience-notice.png b/docs/images/new-app-catalog-experience-notice.png new file mode 100644 index 000000000..95908234f Binary files /dev/null and b/docs/images/new-app-catalog-experience-notice.png differ diff --git a/docs/images/overview/spfx-across-apps.png b/docs/images/overview/spfx-across-apps.png new file mode 100644 index 000000000..a960e43cc Binary files /dev/null and b/docs/images/overview/spfx-across-apps.png differ diff --git a/docs/images/overview/viva-spfx-extensibility.png b/docs/images/overview/viva-spfx-extensibility.png new file mode 100644 index 000000000..d7b94d5dd Binary files /dev/null and b/docs/images/overview/viva-spfx-extensibility.png differ diff --git a/docs/images/property-validation-description-error-apply-disabled.png b/docs/images/property-validation-description-error-apply-disabled.png index 2f8068b74..1ee975fa8 100644 Binary files a/docs/images/property-validation-description-error-apply-disabled.png and b/docs/images/property-validation-description-error-apply-disabled.png differ diff --git a/docs/images/property-validation-description-too-long-error.png b/docs/images/property-validation-description-too-long-error.png index 92f520680..6c1ca1355 100644 Binary files a/docs/images/property-validation-description-too-long-error.png and b/docs/images/property-validation-description-too-long-error.png differ diff --git a/docs/images/property-validation-empty-description-error.png b/docs/images/property-validation-empty-description-error.png index 6d4cba9ab..90054ae40 100644 Binary files a/docs/images/property-validation-empty-description-error.png and b/docs/images/property-validation-empty-description-error.png differ diff --git a/docs/images/property-validation-empty-list-name-error.png b/docs/images/property-validation-empty-list-name-error.png index 142298de4..f023ab0d4 100644 Binary files a/docs/images/property-validation-empty-list-name-error.png and b/docs/images/property-validation-empty-list-name-error.png differ diff --git a/docs/images/property-validation-invalid-list-name-error.png b/docs/images/property-validation-invalid-list-name-error.png index 8490f4b0b..c897aaa90 100644 Binary files a/docs/images/property-validation-invalid-list-name-error.png and b/docs/images/property-validation-invalid-list-name-error.png differ diff --git a/docs/images/property-validation-list-name-property.png b/docs/images/property-validation-list-name-property.png index 443363a6a..044b412bd 100644 Binary files a/docs/images/property-validation-list-name-property.png and b/docs/images/property-validation-list-name-property.png differ diff --git a/docs/images/property-validation-partial-list-name-validation.png b/docs/images/property-validation-partial-list-name-validation.png deleted file mode 100644 index fb40b0df2..000000000 Binary files a/docs/images/property-validation-partial-list-name-validation.png and /dev/null differ diff --git a/docs/images/property-validation-valid-list-name.png b/docs/images/property-validation-valid-list-name.png index 0a4fe8777..f5fb339c7 100644 Binary files a/docs/images/property-validation-valid-list-name.png and b/docs/images/property-validation-valid-list-name.png differ diff --git a/docs/images/react-cascading-dropdowns-item-dropdown-list-items.png b/docs/images/react-cascading-dropdowns-item-dropdown-list-items.png index 55eba750f..757f77180 100644 Binary files a/docs/images/react-cascading-dropdowns-item-dropdown-list-items.png and b/docs/images/react-cascading-dropdowns-item-dropdown-list-items.png differ diff --git a/docs/images/react-cascading-dropdowns-itemname-property-pane-dropdown.png b/docs/images/react-cascading-dropdowns-itemname-property-pane-dropdown.png index 34d726903..16efa490d 100644 Binary files a/docs/images/react-cascading-dropdowns-itemname-property-pane-dropdown.png and b/docs/images/react-cascading-dropdowns-itemname-property-pane-dropdown.png differ diff --git a/docs/images/react-cascading-dropdowns-list-dropdown-available-lists.png b/docs/images/react-cascading-dropdowns-list-dropdown-available-lists.png index a59131418..722ab3a02 100644 Binary files a/docs/images/react-cascading-dropdowns-list-dropdown-available-lists.png and b/docs/images/react-cascading-dropdowns-list-dropdown-available-lists.png differ diff --git a/docs/images/react-cascading-dropdowns-list-selected-item-disabled.png b/docs/images/react-cascading-dropdowns-list-selected-item-disabled.png index 0874732be..f88e54c24 100644 Binary files a/docs/images/react-cascading-dropdowns-list-selected-item-disabled.png and b/docs/images/react-cascading-dropdowns-list-selected-item-disabled.png differ diff --git a/docs/images/react-cascading-dropdowns-listname-property-pane-dropdown.png b/docs/images/react-cascading-dropdowns-listname-property-pane-dropdown.png index f66bcb710..0c3c6275e 100644 Binary files a/docs/images/react-cascading-dropdowns-listname-property-pane-dropdown.png and b/docs/images/react-cascading-dropdowns-listname-property-pane-dropdown.png differ diff --git a/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-items.png b/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-items.png index bfa0614d0..22e60d00b 100644 Binary files a/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-items.png and b/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-items.png differ diff --git a/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-list-info.png b/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-list-info.png index 17904cd1c..cf666b5a9 100644 Binary files a/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-list-info.png and b/docs/images/react-cascading-dropdowns-loading-indicator-when-loading-list-info.png differ diff --git a/docs/images/react-cascading-dropdowns-web-part-first-run.png b/docs/images/react-cascading-dropdowns-web-part-first-run.png index c91f39826..5223d61af 100644 Binary files a/docs/images/react-cascading-dropdowns-web-part-first-run.png and b/docs/images/react-cascading-dropdowns-web-part-first-run.png differ diff --git a/docs/images/release-notes/114/file-action.jpg b/docs/images/release-notes/114/file-action.jpg new file mode 100644 index 000000000..d70fde0e0 Binary files /dev/null and b/docs/images/release-notes/114/file-action.jpg differ diff --git a/docs/images/release-notes/114/location-action.jpg b/docs/images/release-notes/114/location-action.jpg new file mode 100644 index 000000000..1c24b41a0 Binary files /dev/null and b/docs/images/release-notes/114/location-action.jpg differ diff --git a/docs/images/release-notes/114/location-panel.jpg b/docs/images/release-notes/114/location-panel.jpg new file mode 100644 index 000000000..50b39206e Binary files /dev/null and b/docs/images/release-notes/114/location-panel.jpg differ diff --git a/docs/images/release-notes/114/media-panel.jpg b/docs/images/release-notes/114/media-panel.jpg new file mode 100644 index 000000000..69cdbc647 Binary files /dev/null and b/docs/images/release-notes/114/media-panel.jpg differ diff --git a/docs/images/sp-app-deploy-trust.png b/docs/images/sp-app-deploy-trust.png index 5393fda83..b342d1ecf 100644 Binary files a/docs/images/sp-app-deploy-trust.png and b/docs/images/sp-app-deploy-trust.png differ diff --git a/docs/images/sp-columnformatting-inline-editing.gif b/docs/images/sp-columnformatting-inline-editing.gif new file mode 100644 index 000000000..8ba8f0999 Binary files /dev/null and b/docs/images/sp-columnformatting-inline-editing.gif differ diff --git a/docs/images/sp-lists-render-localhost.png b/docs/images/sp-lists-render-localhost.png index c45c58cd7..a7e2f7d45 100644 Binary files a/docs/images/sp-lists-render-localhost.png and b/docs/images/sp-lists-render-localhost.png differ diff --git a/docs/images/sp-lists-render-online-workbench.png b/docs/images/sp-lists-render-online-workbench.png new file mode 100644 index 000000000..adb81ecf2 Binary files /dev/null and b/docs/images/sp-lists-render-online-workbench.png differ diff --git a/docs/images/sp-lists-render-spsite.png b/docs/images/sp-lists-render-spsite.png deleted file mode 100644 index 70a6e5b26..000000000 Binary files a/docs/images/sp-lists-render-spsite.png and /dev/null differ diff --git a/docs/images/sp-lists-spsiteurl-wp.png b/docs/images/sp-lists-spsiteurl-wp.png index d2103ff7c..3074a8f03 100644 Binary files a/docs/images/sp-lists-spsiteurl-wp.png and b/docs/images/sp-lists-spsiteurl-wp.png differ diff --git a/docs/images/sp-pnp-js-guide-completed-setup.png b/docs/images/sp-pnp-js-guide-completed-setup.png deleted file mode 100644 index 7d21e8ba1..000000000 Binary files a/docs/images/sp-pnp-js-guide-completed-setup.png and /dev/null differ diff --git a/docs/images/sp-pnp-js-guide-first-open.png b/docs/images/sp-pnp-js-guide-first-open.png index 6cb0b6c29..d6f9110d5 100644 Binary files a/docs/images/sp-pnp-js-guide-first-open.png and b/docs/images/sp-pnp-js-guide-first-open.png differ diff --git a/docs/images/sp-pnp-js-guide-first-run.png b/docs/images/sp-pnp-js-guide-first-run.png index 13774c786..fe9bd06e6 100644 Binary files a/docs/images/sp-pnp-js-guide-first-run.png and b/docs/images/sp-pnp-js-guide-first-run.png differ diff --git a/docs/images/sp-pnp-js-guide-with-mock-data.png b/docs/images/sp-pnp-js-guide-with-mock-data.png deleted file mode 100644 index 2bb056715..000000000 Binary files a/docs/images/sp-pnp-js-guide-with-mock-data.png and /dev/null differ diff --git a/docs/images/sp-workbench-helloworld-pp.png b/docs/images/sp-workbench-helloworld-pp.png index c5dc32784..217d31606 100644 Binary files a/docs/images/sp-workbench-helloworld-pp.png and b/docs/images/sp-workbench-helloworld-pp.png differ diff --git a/docs/images/sp-workbench-helloworld-wp.png b/docs/images/sp-workbench-helloworld-wp.png index f7e233b5e..7b5d62b29 100644 Binary files a/docs/images/sp-workbench-helloworld-wp.png and b/docs/images/sp-workbench-helloworld-wp.png differ diff --git a/docs/images/sp-workbench-o365-helloworld-wp.png b/docs/images/sp-workbench-o365-helloworld-wp.png index 94163aae5..89da4095b 100644 Binary files a/docs/images/sp-workbench-o365-helloworld-wp.png and b/docs/images/sp-workbench-o365-helloworld-wp.png differ diff --git a/docs/images/sp-workbench-o365.png b/docs/images/sp-workbench-o365.png index 9e75beefc..047580436 100644 Binary files a/docs/images/sp-workbench-o365.png and b/docs/images/sp-workbench-o365.png differ diff --git a/docs/images/sp-workbench-toolbox.png b/docs/images/sp-workbench-toolbox.png index 9ae4ae9d5..e02651889 100644 Binary files a/docs/images/sp-workbench-toolbox.png and b/docs/images/sp-workbench-toolbox.png differ diff --git a/docs/images/sp-wp-modern-page-pp.png b/docs/images/sp-wp-modern-page-pp.png index 28eeea999..10cb7878c 100644 Binary files a/docs/images/sp-wp-modern-page-pp.png and b/docs/images/sp-wp-modern-page-pp.png differ diff --git a/docs/images/sp-wp-modern-page.png b/docs/images/sp-wp-modern-page.png index c97539d4a..db7d35071 100644 Binary files a/docs/images/sp-wp-modern-page.png and b/docs/images/sp-wp-modern-page.png differ diff --git a/docs/images/spfx-add-to-all-sites.png b/docs/images/spfx-add-to-all-sites.png new file mode 100644 index 000000000..6f8009932 Binary files /dev/null and b/docs/images/spfx-add-to-all-sites.png differ diff --git a/docs/images/spfx-add-to-teams.png b/docs/images/spfx-add-to-teams.png new file mode 100644 index 000000000..1ff5aa56a Binary files /dev/null and b/docs/images/spfx-add-to-teams.png differ diff --git a/docs/images/theme-defaults.png b/docs/images/theme-defaults.png index d4cdbe0c8..175e588b3 100644 Binary files a/docs/images/theme-defaults.png and b/docs/images/theme-defaults.png differ diff --git a/docs/images/upload-solution-app-catalog.png b/docs/images/upload-solution-app-catalog.png index eed3d6384..51222bc02 100644 Binary files a/docs/images/upload-solution-app-catalog.png and b/docs/images/upload-solution-app-catalog.png differ diff --git a/docs/images/viva-design/img-card-design.gif b/docs/images/viva-design/img-card-design.gif new file mode 100644 index 000000000..f724102df Binary files /dev/null and b/docs/images/viva-design/img-card-design.gif differ diff --git a/docs/images/viva-design/img-card-design2.gif b/docs/images/viva-design/img-card-design2.gif new file mode 100644 index 000000000..d21c28fae Binary files /dev/null and b/docs/images/viva-design/img-card-design2.gif differ diff --git a/docs/images/viva-design/img-custom-card-layouts.png b/docs/images/viva-design/img-custom-card-layouts.png new file mode 100644 index 000000000..12177a71a Binary files /dev/null and b/docs/images/viva-design/img-custom-card-layouts.png differ diff --git a/docs/images/viva-design/img-examples-01-card-withoutimage.png b/docs/images/viva-design/img-examples-01-card-withoutimage.png new file mode 100644 index 000000000..9df0d2132 Binary files /dev/null and b/docs/images/viva-design/img-examples-01-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-examples-02-card-withoutimage.png b/docs/images/viva-design/img-examples-02-card-withoutimage.png new file mode 100644 index 000000000..cf706474c Binary files /dev/null and b/docs/images/viva-design/img-examples-02-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-examples-03-card-withoutimage.png b/docs/images/viva-design/img-examples-03-card-withoutimage.png new file mode 100644 index 000000000..9b3867455 Binary files /dev/null and b/docs/images/viva-design/img-examples-03-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-examples-04-card-withoutimage.png b/docs/images/viva-design/img-examples-04-card-withoutimage.png new file mode 100644 index 000000000..0306aec9b Binary files /dev/null and b/docs/images/viva-design/img-examples-04-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-examples-05-card-withoutimage.png b/docs/images/viva-design/img-examples-05-card-withoutimage.png new file mode 100644 index 000000000..16023f1c9 Binary files /dev/null and b/docs/images/viva-design/img-examples-05-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-examples-06-card-withoutimage.png b/docs/images/viva-design/img-examples-06-card-withoutimage.png new file mode 100644 index 000000000..7987bd368 Binary files /dev/null and b/docs/images/viva-design/img-examples-06-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-examples-07-card-withoutimage.png b/docs/images/viva-design/img-examples-07-card-withoutimage.png new file mode 100644 index 000000000..15db9834b Binary files /dev/null and b/docs/images/viva-design/img-examples-07-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-examples-08-card-withoutimage.png b/docs/images/viva-design/img-examples-08-card-withoutimage.png new file mode 100644 index 000000000..ad7ba79b1 Binary files /dev/null and b/docs/images/viva-design/img-examples-08-card-withoutimage.png differ diff --git a/docs/images/viva-design/img-large-card-layout.png b/docs/images/viva-design/img-large-card-layout.png new file mode 100644 index 000000000..55884c054 Binary files /dev/null and b/docs/images/viva-design/img-large-card-layout.png differ diff --git a/docs/images/viva-design/img-medium-card-layout.png b/docs/images/viva-design/img-medium-card-layout.png new file mode 100644 index 000000000..d151c17bd Binary files /dev/null and b/docs/images/viva-design/img-medium-card-layout.png differ diff --git a/docs/images/viva-design/img-permutation-01-card-layout.png b/docs/images/viva-design/img-permutation-01-card-layout.png new file mode 100644 index 000000000..6db004a68 Binary files /dev/null and b/docs/images/viva-design/img-permutation-01-card-layout.png differ diff --git a/docs/images/viva-design/img-permutation-02-card-layout.png b/docs/images/viva-design/img-permutation-02-card-layout.png new file mode 100644 index 000000000..083cd56b7 Binary files /dev/null and b/docs/images/viva-design/img-permutation-02-card-layout.png differ diff --git a/docs/images/viva-design/img-permutation-03-card-layout.png b/docs/images/viva-design/img-permutation-03-card-layout.png new file mode 100644 index 000000000..93d41a1d2 Binary files /dev/null and b/docs/images/viva-design/img-permutation-03-card-layout.png differ diff --git a/docs/images/viva-design/img-permutation-04-card-layout.png b/docs/images/viva-design/img-permutation-04-card-layout.png new file mode 100644 index 000000000..2f5fc12a2 Binary files /dev/null and b/docs/images/viva-design/img-permutation-04-card-layout.png differ diff --git a/docs/images/viva-design/img-permutation-05-card-layout.png b/docs/images/viva-design/img-permutation-05-card-layout.png new file mode 100644 index 000000000..641e8cac0 Binary files /dev/null and b/docs/images/viva-design/img-permutation-05-card-layout.png differ diff --git a/docs/images/viva-design/img-search-box-card.png b/docs/images/viva-design/img-search-box-card.png new file mode 100644 index 000000000..e6e582e58 Binary files /dev/null and b/docs/images/viva-design/img-search-box-card.png differ diff --git a/docs/images/viva-design/img-search-template.png b/docs/images/viva-design/img-search-template.png new file mode 100644 index 000000000..87d523aca Binary files /dev/null and b/docs/images/viva-design/img-search-template.png differ diff --git a/docs/images/viva-design/img_card_base.jpg b/docs/images/viva-design/img_card_base.jpg new file mode 100644 index 000000000..8728728c1 Binary files /dev/null and b/docs/images/viva-design/img_card_base.jpg differ diff --git a/docs/images/viva-design/img_card_collections.jpg b/docs/images/viva-design/img_card_collections.jpg new file mode 100644 index 000000000..80444b162 Binary files /dev/null and b/docs/images/viva-design/img_card_collections.jpg differ diff --git a/docs/images/viva-design/img_card_description.jpg b/docs/images/viva-design/img_card_description.jpg new file mode 100644 index 000000000..e1a6bd4ac Binary files /dev/null and b/docs/images/viva-design/img_card_description.jpg differ diff --git a/docs/images/viva-design/img_card_heading.jpg b/docs/images/viva-design/img_card_heading.jpg new file mode 100644 index 000000000..6dd34cf49 Binary files /dev/null and b/docs/images/viva-design/img_card_heading.jpg differ diff --git a/docs/images/viva-design/img_card_image.jpg b/docs/images/viva-design/img_card_image.jpg new file mode 100644 index 000000000..53e8dd52f Binary files /dev/null and b/docs/images/viva-design/img_card_image.jpg differ diff --git a/docs/images/viva-design/img_card_interactions.jpg b/docs/images/viva-design/img_card_interactions.jpg new file mode 100644 index 000000000..4648152f5 Binary files /dev/null and b/docs/images/viva-design/img_card_interactions.jpg differ diff --git a/docs/images/viva-design/img_card_modes.jpg b/docs/images/viva-design/img_card_modes.jpg new file mode 100644 index 000000000..217397c59 Binary files /dev/null and b/docs/images/viva-design/img_card_modes.jpg differ diff --git a/docs/images/viva-design/img_card_platforms.jpg b/docs/images/viva-design/img_card_platforms.jpg new file mode 100644 index 000000000..d38335455 Binary files /dev/null and b/docs/images/viva-design/img_card_platforms.jpg differ diff --git a/docs/images/viva-design/img_card_settings.jpg b/docs/images/viva-design/img_card_settings.jpg new file mode 100644 index 000000000..86c60ca5b Binary files /dev/null and b/docs/images/viva-design/img_card_settings.jpg differ diff --git a/docs/images/viva-design/img_card_toolbox.jpg b/docs/images/viva-design/img_card_toolbox.jpg new file mode 100644 index 000000000..7e7cbb485 Binary files /dev/null and b/docs/images/viva-design/img_card_toolbox.jpg differ diff --git a/docs/images/viva-design/img_card_toolbox2.jpg b/docs/images/viva-design/img_card_toolbox2.jpg new file mode 100644 index 000000000..56b8168eb Binary files /dev/null and b/docs/images/viva-design/img_card_toolbox2.jpg differ diff --git a/docs/images/viva-design/img_card_truncation.jpg b/docs/images/viva-design/img_card_truncation.jpg new file mode 100644 index 000000000..b4440cf19 Binary files /dev/null and b/docs/images/viva-design/img_card_truncation.jpg differ diff --git a/docs/images/viva-design/img_quickview_backstack.gif b/docs/images/viva-design/img_quickview_backstack.gif new file mode 100644 index 000000000..fb72faf89 Binary files /dev/null and b/docs/images/viva-design/img_quickview_backstack.gif differ diff --git a/docs/images/viva-design/img_quickview_ios_theme.jpg b/docs/images/viva-design/img_quickview_ios_theme.jpg new file mode 100644 index 000000000..9a4d96549 Binary files /dev/null and b/docs/images/viva-design/img_quickview_ios_theme.jpg differ diff --git a/docs/images/viva-design/img_quickview_layout.jpg b/docs/images/viva-design/img_quickview_layout.jpg new file mode 100644 index 000000000..a5f69b640 Binary files /dev/null and b/docs/images/viva-design/img_quickview_layout.jpg differ diff --git a/docs/images/viva-design/img_quickview_new_ios_theme.png b/docs/images/viva-design/img_quickview_new_ios_theme.png new file mode 100644 index 000000000..a9ede4a6b Binary files /dev/null and b/docs/images/viva-design/img_quickview_new_ios_theme.png differ diff --git a/docs/images/viva-design/img_quickview_tutorial_dark.png b/docs/images/viva-design/img_quickview_tutorial_dark.png new file mode 100644 index 000000000..c95d30187 Binary files /dev/null and b/docs/images/viva-design/img_quickview_tutorial_dark.png differ diff --git a/docs/images/viva-design/img_quickview_tutorial_light.png b/docs/images/viva-design/img_quickview_tutorial_light.png new file mode 100644 index 000000000..0d6a68742 Binary files /dev/null and b/docs/images/viva-design/img_quickview_tutorial_light.png differ diff --git a/docs/images/viva-design/img_quickview_tutorial_light_and_dark.png b/docs/images/viva-design/img_quickview_tutorial_light_and_dark.png new file mode 100644 index 000000000..2b59f988c Binary files /dev/null and b/docs/images/viva-design/img_quickview_tutorial_light_and_dark.png differ diff --git a/docs/images/viva-design/img_quickview_web_theme.jpg b/docs/images/viva-design/img_quickview_web_theme.jpg new file mode 100644 index 000000000..2723bd6a5 Binary files /dev/null and b/docs/images/viva-design/img_quickview_web_theme.jpg differ diff --git a/docs/images/viva-design/img_quickview_webview.jpg b/docs/images/viva-design/img_quickview_webview.jpg new file mode 100644 index 000000000..e324f9eec Binary files /dev/null and b/docs/images/viva-design/img_quickview_webview.jpg differ diff --git a/docs/images/viva-design/img_quickviews.jpg b/docs/images/viva-design/img_quickviews.jpg new file mode 100644 index 000000000..2118da79c Binary files /dev/null and b/docs/images/viva-design/img_quickviews.jpg differ diff --git a/docs/images/viva-design/mobile-video-preview.png b/docs/images/viva-design/mobile-video-preview.png new file mode 100644 index 000000000..e1a4f148c Binary files /dev/null and b/docs/images/viva-design/mobile-video-preview.png differ diff --git a/docs/images/viva-design/samples/benefits.png b/docs/images/viva-design/samples/benefits.png new file mode 100644 index 000000000..ce089a199 Binary files /dev/null and b/docs/images/viva-design/samples/benefits.png differ diff --git a/docs/images/viva-design/samples/events.png b/docs/images/viva-design/samples/events.png new file mode 100644 index 000000000..8a335edd8 Binary files /dev/null and b/docs/images/viva-design/samples/events.png differ diff --git a/docs/images/viva-design/samples/faq.png b/docs/images/viva-design/samples/faq.png new file mode 100644 index 000000000..d81c6690e Binary files /dev/null and b/docs/images/viva-design/samples/faq.png differ diff --git a/docs/images/viva-design/samples/holidays.png b/docs/images/viva-design/samples/holidays.png new file mode 100644 index 000000000..4c7dcd305 Binary files /dev/null and b/docs/images/viva-design/samples/holidays.png differ diff --git a/docs/images/viva-design/samples/image-carousel.png b/docs/images/viva-design/samples/image-carousel.png new file mode 100644 index 000000000..d97ef5680 Binary files /dev/null and b/docs/images/viva-design/samples/image-carousel.png differ diff --git a/docs/images/viva-design/samples/inventory.png b/docs/images/viva-design/samples/inventory.png new file mode 100644 index 000000000..c64f5f1fc Binary files /dev/null and b/docs/images/viva-design/samples/inventory.png differ diff --git a/docs/images/viva-design/samples/payslip.png b/docs/images/viva-design/samples/payslip.png new file mode 100644 index 000000000..53804ee7e Binary files /dev/null and b/docs/images/viva-design/samples/payslip.png differ diff --git a/docs/images/viva-design/samples/praise.png b/docs/images/viva-design/samples/praise.png new file mode 100644 index 000000000..7acb65ea8 Binary files /dev/null and b/docs/images/viva-design/samples/praise.png differ diff --git a/docs/images/viva-design/samples/teamcalendar.png b/docs/images/viva-design/samples/teamcalendar.png new file mode 100644 index 000000000..696c50ca5 Binary files /dev/null and b/docs/images/viva-design/samples/teamcalendar.png differ diff --git a/docs/images/viva-design/samples/timeoff.png b/docs/images/viva-design/samples/timeoff.png new file mode 100644 index 000000000..1535dfdfc Binary files /dev/null and b/docs/images/viva-design/samples/timeoff.png differ diff --git a/docs/images/viva-design/samples/vaccination.png b/docs/images/viva-design/samples/vaccination.png new file mode 100644 index 000000000..d24f3bdd8 Binary files /dev/null and b/docs/images/viva-design/samples/vaccination.png differ diff --git a/docs/images/viva-design/samples/visual-list.png b/docs/images/viva-design/samples/visual-list.png new file mode 100644 index 000000000..01f4ae3ee Binary files /dev/null and b/docs/images/viva-design/samples/visual-list.png differ diff --git a/docs/images/viva-design/viva-design_card_collections.jpg b/docs/images/viva-design/viva-design_card_collections.jpg new file mode 100644 index 000000000..c21e9782f Binary files /dev/null and b/docs/images/viva-design/viva-design_card_collections.jpg differ diff --git a/docs/images/viva-design/viva-design_card_layouts.jpg b/docs/images/viva-design/viva-design_card_layouts.jpg new file mode 100644 index 000000000..c805b7362 Binary files /dev/null and b/docs/images/viva-design/viva-design_card_layouts.jpg differ diff --git a/docs/images/viva-design/viva-design_card_patterns.jpg b/docs/images/viva-design/viva-design_card_patterns.jpg new file mode 100644 index 000000000..baf69dd09 Binary files /dev/null and b/docs/images/viva-design/viva-design_card_patterns.jpg differ diff --git a/docs/images/viva-design/viva-design_card_states.jpg b/docs/images/viva-design/viva-design_card_states.jpg new file mode 100644 index 000000000..3eb81e6df Binary files /dev/null and b/docs/images/viva-design/viva-design_card_states.jpg differ diff --git a/docs/images/viva-design/viva-design_cards_platforms.jpg b/docs/images/viva-design/viva-design_cards_platforms.jpg new file mode 100644 index 000000000..5016f9a3d Binary files /dev/null and b/docs/images/viva-design/viva-design_cards_platforms.jpg differ diff --git a/docs/images/viva-design/viva-design_dashboard_overview.jpg b/docs/images/viva-design/viva-design_dashboard_overview.jpg new file mode 100644 index 000000000..488c8f267 Binary files /dev/null and b/docs/images/viva-design/viva-design_dashboard_overview.jpg differ diff --git a/docs/images/viva-design/viva-design_dashboard_qview.jpg b/docs/images/viva-design/viva-design_dashboard_qview.jpg new file mode 100644 index 000000000..8c0eaac22 Binary files /dev/null and b/docs/images/viva-design/viva-design_dashboard_qview.jpg differ diff --git a/docs/images/viva-design/viva-design_ia_schema.jpg b/docs/images/viva-design/viva-design_ia_schema.jpg new file mode 100644 index 000000000..3a320ab49 Binary files /dev/null and b/docs/images/viva-design/viva-design_ia_schema.jpg differ diff --git a/docs/images/viva-design/viva-design_light_dark.jpg b/docs/images/viva-design/viva-design_light_dark.jpg new file mode 100644 index 000000000..25eb7ea2b Binary files /dev/null and b/docs/images/viva-design/viva-design_light_dark.jpg differ diff --git a/docs/images/viva-design/viva-design_qv_backstack.jpg b/docs/images/viva-design/viva-design_qv_backstack.jpg new file mode 100644 index 000000000..a7793e330 Binary files /dev/null and b/docs/images/viva-design/viva-design_qv_backstack.jpg differ diff --git a/docs/images/viva-design/viva-design_two_cards.jpg b/docs/images/viva-design/viva-design_two_cards.jpg new file mode 100644 index 000000000..5c4b39181 Binary files /dev/null and b/docs/images/viva-design/viva-design_two_cards.jpg differ diff --git a/docs/images/viva-extensibility/ace-basic-html-quickview-01.png b/docs/images/viva-extensibility/ace-basic-html-quickview-01.png new file mode 100644 index 000000000..cdfe65cf0 Binary files /dev/null and b/docs/images/viva-extensibility/ace-basic-html-quickview-01.png differ diff --git a/docs/images/viva-extensibility/ace-basic-html-quickview-02.png b/docs/images/viva-extensibility/ace-basic-html-quickview-02.png new file mode 100644 index 000000000..2d153c24e Binary files /dev/null and b/docs/images/viva-extensibility/ace-basic-html-quickview-02.png differ diff --git a/docs/images/viva-extensibility/data-visualization/ace-dataviz-allup.png b/docs/images/viva-extensibility/data-visualization/ace-dataviz-allup.png new file mode 100644 index 000000000..f094aced0 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/ace-dataviz-allup.png differ diff --git a/docs/images/viva-extensibility/data-visualization/ace-default.png b/docs/images/viva-extensibility/data-visualization/ace-default.png new file mode 100644 index 000000000..400fa0029 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/ace-default.png differ diff --git a/docs/images/viva-extensibility/data-visualization/bar-chart.png b/docs/images/viva-extensibility/data-visualization/bar-chart.png new file mode 100644 index 000000000..fad7ddadb Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/bar-chart.png differ diff --git a/docs/images/viva-extensibility/data-visualization/chart-on-right-side.png b/docs/images/viva-extensibility/data-visualization/chart-on-right-side.png new file mode 100644 index 000000000..ebe45b330 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/chart-on-right-side.png differ diff --git a/docs/images/viva-extensibility/data-visualization/chart-three-series.png b/docs/images/viva-extensibility/data-visualization/chart-three-series.png new file mode 100644 index 000000000..7bc3f4050 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/chart-three-series.png differ diff --git a/docs/images/viva-extensibility/data-visualization/donut-chart.png b/docs/images/viva-extensibility/data-visualization/donut-chart.png new file mode 100644 index 000000000..ad6110b75 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/donut-chart.png differ diff --git a/docs/images/viva-extensibility/data-visualization/pie-chart.png b/docs/images/viva-extensibility/data-visualization/pie-chart.png new file mode 100644 index 000000000..99ad323b8 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/pie-chart.png differ diff --git a/docs/images/viva-extensibility/data-visualization/regular-chart.png b/docs/images/viva-extensibility/data-visualization/regular-chart.png new file mode 100644 index 000000000..f20005e09 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/regular-chart.png differ diff --git a/docs/images/viva-extensibility/data-visualization/toolbox.png b/docs/images/viva-extensibility/data-visualization/toolbox.png new file mode 100644 index 000000000..745880918 Binary files /dev/null and b/docs/images/viva-extensibility/data-visualization/toolbox.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionAppIcon.png b/docs/images/viva-extensibility/geolocation/geoloactionAppIcon.png new file mode 100644 index 000000000..bcced85be Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionAppIcon.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionCardView.png b/docs/images/viva-extensibility/geolocation/geoloactionCardView.png new file mode 100644 index 000000000..251665267 Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionCardView.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardAction.png b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardAction.png new file mode 100644 index 000000000..15e495fbd Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardAction.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardGenerated.png b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardGenerated.png new file mode 100644 index 000000000..c034350bd Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardGenerated.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionPropertyPanePrimaryButtonAction.png b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPanePrimaryButtonAction.png new file mode 100644 index 000000000..d373b0342 Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPanePrimaryButtonAction.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneSecondaryButtonAction.png b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneSecondaryButtonAction.png new file mode 100644 index 000000000..1767fd067 Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneSecondaryButtonAction.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneStrings.png b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneStrings.png new file mode 100644 index 000000000..67be9b2f9 Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneStrings.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionQuickView.png b/docs/images/viva-extensibility/geolocation/geoloactionQuickView.png new file mode 100644 index 000000000..f8c5bba61 Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionQuickView.png differ diff --git a/docs/images/viva-extensibility/geolocation/geoloactionQuickViewCoordinates.png b/docs/images/viva-extensibility/geolocation/geoloactionQuickViewCoordinates.png new file mode 100644 index 000000000..fe3dbe433 Binary files /dev/null and b/docs/images/viva-extensibility/geolocation/geoloactionQuickViewCoordinates.png differ diff --git a/docs/images/viva-extensibility/icons-limitations-card-bar-mobile.png b/docs/images/viva-extensibility/icons-limitations-card-bar-mobile.png new file mode 100644 index 000000000..25bda5d46 Binary files /dev/null and b/docs/images/viva-extensibility/icons-limitations-card-bar-mobile.png differ diff --git a/docs/images/viva-extensibility/icons-limitations-card-bar.png b/docs/images/viva-extensibility/icons-limitations-card-bar.png new file mode 100644 index 000000000..4bde9e64b Binary files /dev/null and b/docs/images/viva-extensibility/icons-limitations-card-bar.png differ diff --git a/docs/images/viva-extensibility/icons-limitations-supported-icons.png b/docs/images/viva-extensibility/icons-limitations-supported-icons.png new file mode 100644 index 000000000..20b14db02 Binary files /dev/null and b/docs/images/viva-extensibility/icons-limitations-supported-icons.png differ diff --git a/docs/images/viva-extensibility/icons-limitations-toolbox.png b/docs/images/viva-extensibility/icons-limitations-toolbox.png new file mode 100644 index 000000000..4ad88d289 Binary files /dev/null and b/docs/images/viva-extensibility/icons-limitations-toolbox.png differ diff --git a/docs/images/viva-extensibility/lab1-basic-ace.png b/docs/images/viva-extensibility/lab1-basic-ace.png new file mode 100644 index 000000000..0a40fa31c Binary files /dev/null and b/docs/images/viva-extensibility/lab1-basic-ace.png differ diff --git a/docs/images/viva-extensibility/lab1-default.png b/docs/images/viva-extensibility/lab1-default.png new file mode 100644 index 000000000..69772fc52 Binary files /dev/null and b/docs/images/viva-extensibility/lab1-default.png differ diff --git a/docs/images/viva-extensibility/lab1-hw-ace.png b/docs/images/viva-extensibility/lab1-hw-ace.png new file mode 100644 index 000000000..5b9515b5a Binary files /dev/null and b/docs/images/viva-extensibility/lab1-hw-ace.png differ diff --git a/docs/images/viva-extensibility/lab1-hw-ql.png b/docs/images/viva-extensibility/lab1-hw-ql.png new file mode 100644 index 000000000..8ab211ade Binary files /dev/null and b/docs/images/viva-extensibility/lab1-hw-ql.png differ diff --git a/docs/images/viva-extensibility/lab1-image-ace.png b/docs/images/viva-extensibility/lab1-image-ace.png new file mode 100644 index 000000000..11c0c8f6b Binary files /dev/null and b/docs/images/viva-extensibility/lab1-image-ace.png differ diff --git a/docs/images/viva-extensibility/lab1-large.png b/docs/images/viva-extensibility/lab1-large.png new file mode 100644 index 000000000..b064b90c8 Binary files /dev/null and b/docs/images/viva-extensibility/lab1-large.png differ diff --git a/docs/images/viva-extensibility/lab1-medium.png b/docs/images/viva-extensibility/lab1-medium.png new file mode 100644 index 000000000..cda7f42ad Binary files /dev/null and b/docs/images/viva-extensibility/lab1-medium.png differ diff --git a/docs/images/viva-extensibility/lab1-new-ql.png b/docs/images/viva-extensibility/lab1-new-ql.png new file mode 100644 index 000000000..d6748a12a Binary files /dev/null and b/docs/images/viva-extensibility/lab1-new-ql.png differ diff --git a/docs/images/viva-extensibility/lab1-preview.png b/docs/images/viva-extensibility/lab1-preview.png new file mode 100644 index 000000000..0dac82798 Binary files /dev/null and b/docs/images/viva-extensibility/lab1-preview.png differ diff --git a/docs/images/viva-extensibility/lab1-primary-ace.png b/docs/images/viva-extensibility/lab1-primary-ace.png new file mode 100644 index 000000000..bc12668fe Binary files /dev/null and b/docs/images/viva-extensibility/lab1-primary-ace.png differ diff --git a/docs/images/viva-extensibility/lab1-size.png b/docs/images/viva-extensibility/lab1-size.png new file mode 100644 index 000000000..e2506bad7 Binary files /dev/null and b/docs/images/viva-extensibility/lab1-size.png differ diff --git a/docs/images/viva-extensibility/lab1-static-ace.png b/docs/images/viva-extensibility/lab1-static-ace.png new file mode 100644 index 000000000..b0335d65c Binary files /dev/null and b/docs/images/viva-extensibility/lab1-static-ace.png differ diff --git a/docs/images/viva-extensibility/lab1-textinput-ace.png b/docs/images/viva-extensibility/lab1-textinput-ace.png new file mode 100644 index 000000000..b23014192 Binary files /dev/null and b/docs/images/viva-extensibility/lab1-textinput-ace.png differ diff --git a/docs/images/viva-extensibility/lab1-toolbox.png b/docs/images/viva-extensibility/lab1-toolbox.png new file mode 100644 index 000000000..c9722ddae Binary files /dev/null and b/docs/images/viva-extensibility/lab1-toolbox.png differ diff --git a/docs/images/viva-extensibility/lab2-ace-1.png b/docs/images/viva-extensibility/lab2-ace-1.png new file mode 100644 index 000000000..f8e77688e Binary files /dev/null and b/docs/images/viva-extensibility/lab2-ace-1.png differ diff --git a/docs/images/viva-extensibility/lab2-ace-2.png b/docs/images/viva-extensibility/lab2-ace-2.png new file mode 100644 index 000000000..4c7f8e027 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-ace-2.png differ diff --git a/docs/images/viva-extensibility/lab2-ace-3.png b/docs/images/viva-extensibility/lab2-ace-3.png new file mode 100644 index 000000000..88069bb46 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-ace-3.png differ diff --git a/docs/images/viva-extensibility/lab2-ace-4.png b/docs/images/viva-extensibility/lab2-ace-4.png new file mode 100644 index 000000000..24ab54b67 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-ace-4.png differ diff --git a/docs/images/viva-extensibility/lab2-ace-5.png b/docs/images/viva-extensibility/lab2-ace-5.png new file mode 100644 index 000000000..abed1eba2 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-ace-5.png differ diff --git a/docs/images/viva-extensibility/lab2-ace-6.png b/docs/images/viva-extensibility/lab2-ace-6.png new file mode 100644 index 000000000..77ce499d3 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-ace-6.png differ diff --git a/docs/images/viva-extensibility/lab2-empty-list.png b/docs/images/viva-extensibility/lab2-empty-list.png new file mode 100644 index 000000000..9924352a4 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-empty-list.png differ diff --git a/docs/images/viva-extensibility/lab2-list-id.png b/docs/images/viva-extensibility/lab2-list-id.png new file mode 100644 index 000000000..1373c2dc4 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-list-id.png differ diff --git a/docs/images/viva-extensibility/lab2-list-settings.png b/docs/images/viva-extensibility/lab2-list-settings.png new file mode 100644 index 000000000..27da01966 Binary files /dev/null and b/docs/images/viva-extensibility/lab2-list-settings.png differ diff --git a/docs/images/viva-extensibility/lab3-ace-1.png b/docs/images/viva-extensibility/lab3-ace-1.png new file mode 100644 index 000000000..0107b16f2 Binary files /dev/null and b/docs/images/viva-extensibility/lab3-ace-1.png differ diff --git a/docs/images/viva-extensibility/lab3-detailed.png b/docs/images/viva-extensibility/lab3-detailed.png new file mode 100644 index 000000000..42cd60012 Binary files /dev/null and b/docs/images/viva-extensibility/lab3-detailed.png differ diff --git a/docs/images/viva-extensibility/lab4-add.png b/docs/images/viva-extensibility/lab4-add.png new file mode 100644 index 000000000..19a110d6f Binary files /dev/null and b/docs/images/viva-extensibility/lab4-add.png differ diff --git a/docs/images/viva-extensibility/lab4-apps.png b/docs/images/viva-extensibility/lab4-apps.png new file mode 100644 index 000000000..e0290a55e Binary files /dev/null and b/docs/images/viva-extensibility/lab4-apps.png differ diff --git a/docs/images/viva-extensibility/lab4-catalog.png b/docs/images/viva-extensibility/lab4-catalog.png new file mode 100644 index 000000000..d8ea61e53 Binary files /dev/null and b/docs/images/viva-extensibility/lab4-catalog.png differ diff --git a/docs/images/viva-extensibility/lab4-confirm.png b/docs/images/viva-extensibility/lab4-confirm.png new file mode 100644 index 000000000..f9f36dd80 Binary files /dev/null and b/docs/images/viva-extensibility/lab4-confirm.png differ diff --git a/docs/images/viva-extensibility/lab4-deploy.png b/docs/images/viva-extensibility/lab4-deploy.png new file mode 100644 index 000000000..9a8c4ac82 Binary files /dev/null and b/docs/images/viva-extensibility/lab4-deploy.png differ diff --git a/docs/images/viva-extensibility/lab4-new.png b/docs/images/viva-extensibility/lab4-new.png new file mode 100644 index 000000000..00c234221 Binary files /dev/null and b/docs/images/viva-extensibility/lab4-new.png differ diff --git a/docs/images/viva-extensibility/lab4-sync.png b/docs/images/viva-extensibility/lab4-sync.png new file mode 100644 index 000000000..41d953a95 Binary files /dev/null and b/docs/images/viva-extensibility/lab4-sync.png differ diff --git a/docs/images/viva-extensibility/lab4-url.png b/docs/images/viva-extensibility/lab4-url.png new file mode 100644 index 000000000..41d7fbfb8 Binary files /dev/null and b/docs/images/viva-extensibility/lab4-url.png differ diff --git a/docs/images/viva-extensibility/people-search/ace-default.png b/docs/images/viva-extensibility/people-search/ace-default.png new file mode 100644 index 000000000..8640cf6c5 Binary files /dev/null and b/docs/images/viva-extensibility/people-search/ace-default.png differ diff --git a/docs/images/viva-extensibility/people-search/qv-item-default.png b/docs/images/viva-extensibility/people-search/qv-item-default.png new file mode 100644 index 000000000..80f59b5b6 Binary files /dev/null and b/docs/images/viva-extensibility/people-search/qv-item-default.png differ diff --git a/docs/images/viva-extensibility/people-search/qv-person.png b/docs/images/viva-extensibility/people-search/qv-person.png new file mode 100644 index 000000000..0b3dacbb8 Binary files /dev/null and b/docs/images/viva-extensibility/people-search/qv-person.png differ diff --git a/docs/images/viva-extensibility/people-search/qv-results-default.png b/docs/images/viva-extensibility/people-search/qv-results-default.png new file mode 100644 index 000000000..cb1e8e649 Binary files /dev/null and b/docs/images/viva-extensibility/people-search/qv-results-default.png differ diff --git a/docs/images/viva-extensibility/people-search/qv-suggested.png b/docs/images/viva-extensibility/people-search/qv-suggested.png new file mode 100644 index 000000000..ef2d149c0 Binary files /dev/null and b/docs/images/viva-extensibility/people-search/qv-suggested.png differ diff --git a/docs/images/viva-extensibility/people-search/search-results.png b/docs/images/viva-extensibility/people-search/search-results.png new file mode 100644 index 000000000..bc9c82d57 Binary files /dev/null and b/docs/images/viva-extensibility/people-search/search-results.png differ diff --git a/docs/images/viva-extensibility/people-search/toolbox.png b/docs/images/viva-extensibility/people-search/toolbox.png new file mode 100644 index 000000000..0a413d8b1 Binary files /dev/null and b/docs/images/viva-extensibility/people-search/toolbox.png differ diff --git a/docs/images/webpart-top-actions.png b/docs/images/webpart-top-actions.png new file mode 100644 index 000000000..010338c18 Binary files /dev/null and b/docs/images/webpart-top-actions.png differ diff --git a/docs/images/yeoman-sp-complete.png b/docs/images/yeoman-sp-complete.png deleted file mode 100644 index 7987bcb3c..000000000 Binary files a/docs/images/yeoman-sp-complete.png and /dev/null differ diff --git a/docs/index.yml b/docs/index.yml index 3c27590b1..b2648b18f 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -6,12 +6,11 @@ summary: Build SharePoint Framework solutions or take advantage of other extensi metadata: title: SharePoint developer documentation # Required; page title displayed in search results. Include the brand. < 60 chars. description: Build SharePoint Framework solutions or take advantage of other extensibility options in SharePoint and in Microsoft 365 in general. # Required; article description that is displayed in search results. < 160 chars. - ms.prod: sharepoint #Required; service per approved list. service slug assigned to your service by ACOM. ms.topic: landing-page # Required ms.audience: Developer # Optional; Remove if no collection is used. author: VesaJuvonen #Required; your GitHub user alias, with correct capitalization. ms.author: vesaj #Required; microsoft alias of author; optional team alias. - ms.date: 26/05/2021 #Required; mm/dd/yyyy format. + ms.date: 01/18/2022 #Required; mm/dd/yyyy format. # linkListType: architecture | concept | deploy | download | get-started | how-to-guide | learn | overview | quickstart | reference | sample | tutorial | video | whats-new @@ -24,7 +23,7 @@ landingContent: - linkListType: overview links: - text: Overview of the SharePoint Framework - url: /sharepoint/dev/spfx/sharepoint-framework-overview + url: /sharepoint/dev/spfx/sharepoint-framework-overview - linkListType: get-started links: - text: Set up your SharePoint Framework development environment @@ -39,28 +38,22 @@ landingContent: url: /sharepoint/dev/spfx/web-parts/get-started/using-web-part-as-ms-teams-tab - text: Use Microsoft Graph in your SharePoint Framework solution url: /sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis - - text: Use Microsoft Graph in your SharePoint Framework solution - url: /sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis - + # Card (optional) - - title: Contact us + - title: SharePoint Embedded linkLists: - - linkListType: video - links: - - text: Microsoft 365 & SharePoint Community - PnP - url: https://www.youtube.com/channel/UC_mKdhw-V6CeCM7gTo_Iy7w - linkListType: overview links: - - text: Developer Blog - url: https://developer.microsoft.com/microsoft-365/blogs/ - - text: Community - url: https://pnp.github.io/ - - text: Submit a new idea - url: https://sharepoint.uservoice.com/forums/329220-sharepoint-dev-platform - - text: Issues - url: https://github.com/SharePoint/sp-dev-docs/issues - - text: Forum - url: https://aka.ms/spdev-community + - text: Overview of SharePoint Embedded + url: /sharepoint/dev/embedded/overview + - text: Enable SharePoint Embedded + url: /sharepoint/dev/embedded/getting-started/enable-sharepoint-embedded + - linkListType: tutorial + links: + - text: SharePoint Embedded - Overview & Configuration + url: /training/modules/sharepoint-embedded-setup + - text: SharePoint Embedded - Building an App + url: /training/modules/sharepoint-embedded-create-app # Card (optional) - title: Samples @@ -70,9 +63,9 @@ landingContent: - text: SharePoint Framework Web Part url: https://aka.ms/spfx-webparts - text: Column and View formatting samples - url: https://aka.ms/list-formatting + url: https://aka.ms/list-formatting - text: SharePoint Framework Extensions - url: https://aka.ms/spfx-extensions + url: https://aka.ms/spfx-extensions # Card (optional) - title: Capabilities and Features @@ -115,7 +108,7 @@ landingContent: - text: PnP Core SDK.NET library url: https://pnp.github.io/pnpcore/ - text: PnP PowerShell - url: https://pnp.github.io/powershell/ + url: https://pnp.github.io/powershell/ - text: CLI for Microsoft 365 url: https://pnp.github.io/cli-microsoft365/ - text: SharePoint Framework React Controls @@ -135,7 +128,7 @@ landingContent: - linkListType: concept links: - text: SharePoint sites and content API overview - url: https://docs.microsoft.com/graph/sharepoint-concept-overview + url: /graph/sharepoint-concept-overview # Card (optional) - title: SharePoint REST service @@ -143,7 +136,7 @@ landingContent: - linkListType: concept links: - text: Get to know the SharePoint REST service - url: https://docs.microsoft.com/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service + url: /sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service - linkListType: reference links: - text: Complete basic operations @@ -151,7 +144,7 @@ landingContent: # Card - title: SharePoint webhooks - linkLists: + linkLists: - linkListType: overview links: - text: Overview of SharePoint webhooks @@ -187,4 +180,24 @@ landingContent: - text: Avoid getting throttled or blocked in SharePoint Online url: /sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online - text: Modernize your classic SharePoint sites - url: /sharepoint/dev/transform/modernize-classic-sites + url: /sharepoint/dev/transform/modernize-classic-sites + + # Card (optional) + - title: Contact us + linkLists: + - linkListType: video + links: + - text: Microsoft 365 Community + url: https://www.youtube.com/channel/UC_mKdhw-V6CeCM7gTo_Iy7w + - linkListType: overview + links: + - text: Developer Blog + url: https://devblogs.microsoft.com/microsoft365dev/ + - text: Community + url: https://pnp.github.io/ + - text: Submit a new idea + url: https://aka.ms/feedback/sharepoint + - text: Issues + url: https://github.com/SharePoint/sp-dev-docs/issues + - text: Forum + url: https://aka.ms/spdev-community diff --git a/docs/scenario-guidance/Application-lifecycle-management.md b/docs/scenario-guidance/Application-lifecycle-management.md index c378a5338..eace0f4ae 100644 --- a/docs/scenario-guidance/Application-lifecycle-management.md +++ b/docs/scenario-guidance/Application-lifecycle-management.md @@ -1,8 +1,8 @@ --- title: Scenario Guidance - Application Lifecycle Management description: Scenario guidance on application lifecycle management topics with SharePoint Framework and SharePoint add-ins. -ms.date: 03/26/2018 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # Application Lifecycle Management @@ -18,9 +18,9 @@ _**Applies to:** SharePoint Online | SharePoint 2013 | SharePoint 2016_ The SharePoint Add-In Model introduces new development techniques, mainly based on client-side code. Thus, the ALM of SharePoint Add-In solutions is slightly different from the previous Sandbox or Full Trust Code (FTC) solutions. Here follow articles and videos about how to manage ALM with the SharePoint Add-In model. ### Articles -* [SharePoint Application Lifecycle Management](https://docs.microsoft.com/sharepoint/dev/general-development/sharepoint-server-application-lifecycle-management) -* [Application Lifecycle Management (ALM) APIs](https://docs.microsoft.com/sharepoint/dev/apis/alm-api-for-spfx-add-ins) -* [Set up a general development environment for SharePoint](https://docs.microsoft.com/sharepoint/dev/general-development/set-up-a-general-development-environment-for-sharepoint) +* [SharePoint Application Lifecycle Management](/sharepoint/dev/general-development/sharepoint-server-application-lifecycle-management) +* [Application Lifecycle Management (ALM) APIs](/sharepoint/dev/apis/alm-api-for-spfx-add-ins) +* [Set up a general development environment for SharePoint](/sharepoint/dev/general-development/set-up-a-general-development-environment-for-sharepoint) ### Solutions * [Tenant Information Portal](https://github.com/SharePoint/PnP-Tools/tree/master/Solutions/Tenant%20Information%20Portal) @@ -35,12 +35,12 @@ _**Applies to:** Office 365 | SharePoint Online | SharePoint 2016 (FP2)_ The new development model of SharePoint Framework (SPFx) introduces new tools and techniques to develop SPFx solutions. Here follows a list of useful articles about ALM with SPFx. ### Articles -* [Set up your Office 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant) -* [Set up your SharePoint Framework development environment](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment) -* [SharePoint Framework (SPFx) enterprise guidance](https://docs.microsoft.com/sharepoint/dev/spfx/enterprise-guidance) -* [Team-based development on the SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/team-based-development-on-sharepoint-framework) -* [SharePoint Framework solutions governance considerations](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/guidance/governance-considerations) -* [Application Lifecycle Management (ALM) APIs](https://docs.microsoft.com/sharepoint/dev/apis/alm-api-for-spfx-add-ins) +* [Set up your Office 365 tenant](/sharepoint/dev/spfx/set-up-your-developer-tenant) +* [Set up your SharePoint Framework development environment](/sharepoint/dev/spfx/set-up-your-development-environment) +* [SharePoint Framework (SPFx) enterprise guidance](/sharepoint/dev/spfx/enterprise-guidance) +* [Team-based development on the SharePoint Framework](/sharepoint/dev/spfx/team-based-development-on-sharepoint-framework) +* [SharePoint Framework solutions governance considerations](/sharepoint/dev/spfx/web-parts/guidance/governance-considerations) +* [Application Lifecycle Management (ALM) APIs](/sharepoint/dev/apis/alm-api-for-spfx-add-ins) * [Working With: ALM API](https://github.com/SharePoint/PnP-JS-Core/wiki/Working-With:-ALM-API) ### Videos diff --git a/docs/scenario-guidance/Branding.md b/docs/scenario-guidance/Branding.md index 9b6286c90..92023d429 100644 --- a/docs/scenario-guidance/Branding.md +++ b/docs/scenario-guidance/Branding.md @@ -1,8 +1,8 @@ --- title: Scenario Guidance - Branding description: Scenario guidance on branding options with SharePoint. -ms.date: 05/01/2020 -localization_priority: Priority +ms.date: 06/28/2022 +ms.localizationpriority: high --- # Branding @@ -80,7 +80,7 @@ The classic SharePoint user experience is based on ASP.NET master pages and page - [SharePoint 2013/2016/Online Responsive UI](https://github.com/SharePoint/PnP-Tools/tree/master/Solutions/SharePoint.UI.Responsive) - [SharePoint Modernization scanner](https://github.com/SharePoint/sp-dev-modernization/tree/master/Tools/SharePoint.Modernization) -- [PnP Starter Intranet for SharePoint 2013/2016 and SharePoint Online](https://dev.office.com/patterns-and-practices-detail/11128) +- [PnP Starter Intranet for SharePoint 2013/2016 and SharePoint Online](https://github.com/pnp/PnP/tree/master/Solutions/Business.StarterIntranet) ### Videos @@ -93,7 +93,7 @@ _**Applies to:** Modern sites_ SharePoint site owners have new options for applying custom styles and colors to sites that make it easier to define and manage themes across site collections. These new features include: - The ability to define custom themes and make them available to site owners. Themes are defined in a [JSON schema](../declarative-customization/site-theming/sharepoint-site-theming-overview.md) that stores color settings and related metadata for each theme. -- An online [Theme Generator tool](/fabric#/styles/themegenerator) that you can use to define new custom themes. +- An online [Theme Generator tool](https://aka.ms/themedesigner) that you can use to define new custom themes. - A simplified set of default themes, with six light themes and two dark themes presently available. - An updated color palette, with 12 light colors and 6 dark colors, as well as 16 supplementary themes. - Control over which themes are available for use on pages within your sites. For example, you can define custom themes based on your organization's branding or identity, and make those the only available themes within your sites. @@ -149,14 +149,14 @@ Because Microsoft SharePoint is built on top of Microsoft ASP.NET, it supports m - [Master pages in the SharePoint Add-in model](../solution-guidance/master-pages-sharepoint-add-in.md) - [SharePoint Page Layouts and Master Pages (ECM)](https://msdn.microsoft.com/library/office/ms543497(v=office.14).aspx) - [Master Pages](https://msdn.microsoft.com/library/office/ms443795(v=office.14).aspx) -- [Transformation guidance from farm solutions to add-in model - Replacement of files deployed via Modules (lab)](https://github.com/OfficeDev/TrainingContent/tree/master/Archive/O3658/10%20Transformation%20guidance%20from%20farm%20solutions%20to%20add-in%20model) +- [Transformation guidance from farm solutions to add-in model - Replacement of files deployed via Modules (lab)](https://github.com/OfficeDev/TrainingContent/blob/master/SharePoint/AddIns/14%20Transformation%20guidance%20from%20farm%20solutions%20to%20add-in%20model/Readme.md) - [Branding SharePoint sites in the SharePoint Add-in model](../solution-guidance/branding-sharepoint-sites-sharepoint-add-in.md) ### Videos - [PnP Webcast - Customizations options with SharePoint Online “modern” experiences](https://www.youtube.com/watch?v=724Spxu3hF4) - [Learn best practices for customizing and branding SharePoint Team Sites](https://www.youtube.com/watch?v=2AxN-G56-d4) -- [Office Dev PnP Web Cast – Branding SharePoint using add-in model techniques](/office/blogs/branding-sharepoint-using-add-in-model-techniques) +- [Office Dev PnP Web Cast – Branding SharePoint using add-in model techniques](/sharepoint/dev/solution-guidance/branding-sharepoint-sites-sharepoint-add-in) ### Solutions @@ -199,9 +199,9 @@ Cascading style sheet (CSS) plays a large role in SharePoint branding. To succes ### Samples -- [CSS injection pattern](https://dev.office.com/patterns-and-practices-detail/1852) -- [AlternateCssUrl & SiteLogoUrl properties in web object](https://dev.office.com/patterns-and-practices-detail/1849) -- [Making out-of-the-box Seattle master responsive](https://dev.office.com/patterns-and-practices-detail/5823) +- [CSS injection pattern](https://github.com/pnp/PnP/tree/master/Samples/Branding.InjectResponsiveCSS/Branding.InjectResponsiveCSS) +- [AlternateCssUrl & SiteLogoUrl properties in web object](https://github.com/pnp/PnP/tree/master/Samples/Branding.AlternateCSSAndSiteLogo) +- [Making out-of-the-box Seattle master responsive](https://github.com/pnp/PnP/tree/master/Samples/Branding.InjectResponsiveCSS) ## Script Embedding and DOM manipulation @@ -222,7 +222,7 @@ Script Embedding means a pattern where custom JavaScript is added on the page wh - [JavaScript injection in SharePoint Online - Office 365 Developer Patterns and Practices](https://channel9.msdn.com/Blogs/Office-365-Dev/JavaScript-injection-in-SharePoint-Online-Office-365-Developer-Patterns-and-Practices) - [How to update your SharePoint pages via the embedding of JavaScript](https://channel9.msdn.com/blogs/OfficeDevPnP/JavaScript-embedding-demo) -- [Office Dev PnP Web Cast – JavaScript development patterns with SharePoint](/office/blogs/javascript-development-patterns-with-sharepoint) +- [Office Dev PnP Web Cast – JavaScript development patterns with SharePoint](/sharepoint/dev/solution-guidance/javascript-patterns-and-performance) ### Samples @@ -231,4 +231,4 @@ Script Embedding means a pattern where custom JavaScript is added on the page wh - [Core.EmbedJavaScript - Shows basic JavaScript embedding scenarios](https://github.com/OfficeDev/PnP/tree/master/Samples/Core.EmbedJavaScript) - [Core.EmbedJavaScriptJSOM - Shows how to do JavaScript embedding from SP hosted add-in](https://github.com/OfficeDev/PnP/tree/master/Samples/Core.EmbedJavaScriptJSOM) - [Core.EmbedJavaScript.HeaderFooter - Shows how to add custom header and footer with JavaScript embed pattern](https://github.com/OfficeDev/PnP/tree/master/Samples/Core.EmbedJavaScript.HeaderFooter) -- [CDN Manager](https://dev.office.com/patterns-and-practices-detail/5822) +- [CDN Manager](https://github.com/pnp/PnP/tree/master/Solutions/Core.CDNManager) diff --git a/docs/scenario-guidance/Business-processes.md b/docs/scenario-guidance/Business-processes.md index 106d027b5..93b72e24e 100644 --- a/docs/scenario-guidance/Business-processes.md +++ b/docs/scenario-guidance/Business-processes.md @@ -1,8 +1,8 @@ --- title: Scenario Guidance - Business Processes description: Scenario guidance on business process options in SharePoint Online and in on-premises. -ms.date: 03/26/2018 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # Business Processes diff --git a/docs/scenario-guidance/Custom-configurations.md b/docs/scenario-guidance/Custom-configurations.md index c8238641e..898511428 100644 --- a/docs/scenario-guidance/Custom-configurations.md +++ b/docs/scenario-guidance/Custom-configurations.md @@ -1,8 +1,8 @@ --- title: Scenario Guidance - Custom configurations description: Scenario guidance on where and how to store configuration values. -ms.date: 03/26/2018 -localization_priority: Normal +ms.date: 06/28/2022 +ms.localizationpriority: medium --- # Custom configurations @@ -25,7 +25,7 @@ Tenant properties allow tenant administrators to add properties in the App Catal ### Articles -- [SharePoint Online tenant properties](https://docs.microsoft.com/sharepoint/dev/spfx/tenant-properties) +- [SharePoint Online tenant properties](/sharepoint/dev/spfx/tenant-properties) ### Videos @@ -52,11 +52,11 @@ _**Applies to:** Office 365 | SharePoint Server_ ### Articles -- [Make your SharePoint client-side web part configurable](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/basics/integrate-with-property-pane) -- [Simplify adding web parts with preconfigured entries](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/guidance/simplify-adding-web-parts-with-preconfigured-entries) -- [Validate web part property values](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/guidance/validate-web-part-property-values) -- [Integrate web part properties with SharePoint](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/guidance/integrate-web-part-properties-with-sharepoint) -- [Build custom controls for the property pane](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/guidance/build-custom-property-pane-controls) +- [Make your SharePoint client-side web part configurable](/sharepoint/dev/spfx/web-parts/basics/integrate-with-property-pane) +- [Simplify adding web parts with preconfigured entries](/sharepoint/dev/spfx/web-parts/guidance/simplify-adding-web-parts-with-preconfigured-entries) +- [Validate web part property values](/sharepoint/dev/spfx/web-parts/guidance/validate-web-part-property-values) +- [Integrate web part properties with SharePoint](/sharepoint/dev/spfx/web-parts/guidance/integrate-web-part-properties-with-sharepoint) +- [Build custom controls for the property pane](/sharepoint/dev/spfx/web-parts/guidance/build-custom-property-pane-controls) ### Videos @@ -78,7 +78,7 @@ _**Applies to:** Office 365 | SharePoint Server_ _**Applies to:** Office 365 | SharePoint Server_ -Description. +Description. ### Articles diff --git a/docs/scenario-guidance/Development-models.md b/docs/scenario-guidance/Development-models.md index 3ebaac988..accf1b928 100644 --- a/docs/scenario-guidance/Development-models.md +++ b/docs/scenario-guidance/Development-models.md @@ -1,12 +1,11 @@ --- title: Development models description: Development models -ms.date: 04/21/2020 -ms.prod: sharepoint +ms.date: 03/08/2023 author: vesajuvonen ms.author: vesaj -ms.topic: sharepoint -localization_priority: normal +ms.topic: article +ms.localizationpriority: medium --- # Development models @@ -24,11 +23,11 @@ _**Applies to:** Office 365 | SharePoint Online | SharePoint 2016 FP2_ The SharePoint Framework (SPFx) is a page and web part model that provides full support for client-side SharePoint development, easy integration with SharePoint data, and support for open source tooling. With the SharePoint Framework, you can use modern web technologies and tools in your preferred development environment to build productive experiences and apps that are natively responsive and mobile-ready. The SharePoint Framework works for SharePoint Online and for on-premises (from SharePoint 2016 Feature Pack 2 forward). You can built client-side web parts and SharePoint Framework Extensions with the SharePoint Framework. ### Articles -* [Overview of the SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview) -* [Overview of SharePoint client-side web parts](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/overview-client-side-web-parts) -* [Overview of SharePoint Framework Extensions](https://docs.microsoft.com/sharepoint/dev/spfx/extensions/overview-extensions) -* [SharePoint Framework (SPFx) enterprise guidance](https://docs.microsoft.com/sharepoint/dev/spfx/enterprise-guidance) -* [SharePoint Framework roadmap](https://docs.microsoft.com/sharepoint/dev/spfx/roadmap) +* [Overview of the SharePoint Framework](/sharepoint/dev/spfx/sharepoint-framework-overview) +* [Overview of SharePoint client-side web parts](/sharepoint/dev/spfx/web-parts/overview-client-side-web-parts) +* [Overview of SharePoint Framework Extensions](/sharepoint/dev/spfx/extensions/overview-extensions) +* [SharePoint Framework (SPFx) enterprise guidance](/sharepoint/dev/spfx/enterprise-guidance) +* [SharePoint Framework roadmap](/sharepoint/dev/spfx/roadmap) ### Samples * [SharePoint Framework client-side web part samples & tutorial materials](https://github.com/SharePoint/sp-dev-fx-webparts) @@ -47,21 +46,21 @@ The SharePoint Framework (SPFx) is a page and web part model that provides full _**Applies to:** SharePoint 2013 | SharePoint 2016 | SharePoint Online_ -The SharePoint Add-In model is a development model for SharePoint Online and SharePoint 2013/2016 on-premises. The main goal of this model is to make developers able of customizing and extending SharePoint sites without the need of having full trust access to the target farm, being able to work remotely with client-side code, which is based on the Client Side Object Model (CSOM) and the REST API of SharePoint. +The SharePoint Add-In model is a development model for SharePoint Online and SharePoint 2013/2016 on-premises. The main goal of this model is to make developers able of customizing and extending SharePoint sites without the need of having full trust access to the target farm, being able to work remotely with client-side code, which is based on the Client Side Object Model (CSOM) and the REST API of SharePoint. This goal adheres perfectly to the cloud offering model and philosophy. Users can discover and download SharePoint Add-ins from a public SharePoint add-in store or from their organization's corporate add-in catalog. With the SharePoint Add-In model you can create SharePoint-hosted and provider-hosted solutions. The former are just client-side and JavaScript based applications, hosted in SharePoint. The latter typically are .NET applications hosted on Microsoft Azure, or on any other hosting platform. With the SharePoint Add-In model you can create: * Full-page solutions: an immersive full-page experience that can have the look and feel of a SharePoint page. -* App-Parts: parts of a webpage, using a special kind of control called an add-in part, to surface an iframe element that contains the add-in. +* App-Parts: parts of a webpage, using a special kind of control called an add-in part, to surface an ` +> [!VIDEO https://mgt.dev/iframe.html?id=components-mgt-agenda--simple&source=docs] [Open this example in mgt.dev](https://mgt.dev/?path=/story/components-mgt-agenda--simple&source=docs) ## Why use Microsoft Graph Toolkit in SharePoint Framework? -When building solutions using SharePoint Framework, you connect to Microsoft Graph using the [MSGraphClient](./use-msgraph.md) exposed by SharePoint Framework. The **MSGraphClient** handles authentication with Microsoft Graph for you, allowing you to focus on building your app. Still, you need to build the necessary API requests, execute them, handle their responses and show the data in your app. +When building solutions using SharePoint Framework, you connect to Microsoft Graph using the [MSGraphClient](./use-msgraph.md) exposed by SharePoint Framework. The **MSGraphClient** handles authentication with Microsoft Graph for you, allowing you to focus on building your app. Still, you need to build the necessary API requests, execute them, handle their responses, and show the data in your app. -Microsoft Graph Toolkit simplifies working with Microsoft Graph even further. Not only it handles the authentication, but it also communicates with Microsoft Graph for you and automatically shows the retrieved data in your app, saving you precious time. +Microsoft Graph Toolkit simplifies working with Microsoft Graph even further. Not only does it handle the authentication, but it also communicates with Microsoft Graph for you and automatically shows the retrieved data in your app, saving you precious time. -Following example shows how to use the toolkit's Agenda component in a plain JavaScript SharePoint Framework web part to display the current user's calendar events: +The following example shows how to use the toolkit's Agenda component in a plain JavaScript SharePoint Framework web part to display the current user's calendar events: ```typescript import { Providers, SharePointProvider } from '@microsoft/mgt-spfx'; @@ -57,14 +56,14 @@ Notice, how Microsoft Graph Toolkit uses the current context from SharePoint Fra Microsoft Graph Toolkit connects to Microsoft Graph to retrieve data stored in Microsoft 365. To access the data, the service principal, that facilitates the communication with APIs, will require the necessary API permissions for Microsoft Graph. The necessary permissions for your project depend on which toolkit components you use. For more information about the Microsoft Graph permissions required by components, see [their documentation](/graph/toolkit/overview?WT.mc_id=m365-29707-wmastyka). -After you determined the list of API permissions needed for your SharePoint Framework project, [add them to the project's configuration](./use-aadhttpclient.md#request-permissions-to-an-azure-ad-application). +After you have determined the list of API permissions needed for your SharePoint Framework project, [add them to the project's configuration](./use-aadhttpclient.md#request-permissions-to-an-azure-ad-application). The next step is to add Microsoft Graph Toolkit to your project. For the exact steps, see the [SharePoint Framework library for Microsoft Graph Toolkit](/graph/toolkit/get-started/mgt-spfx?WT.mc_id=m365-29707-wmastyka) documentation. > [!IMPORTANT] > If you use React in your SharePoint Framework project, you'll need to install both `@microsoft/mgt-spfx` and `@microsoft/mgt-react` packages in your project. You'll also need to adjust imports for the types that you load from the toolkit. For more information, see the [React section](/graph/toolkit/get-started/mgt-spfx?WT.mc_id=m365-29707-wmastyka#react) of the SharePoint Framework library for Microsoft Graph Toolkit documentation. -After you complete the configuration steps, you're ready to use Microsoft Graph Toolkit in your project. +After you complete the configuration steps, you can use Microsoft Graph Toolkit in your project. ## Known issues @@ -74,7 +73,7 @@ SharePoint Framework web parts and extensions that use Microsoft Graph Toolkit s > Failed to execute 'define' on 'CustomElementRegistry': the name "mgt-xyz" has already been used with this registry. -This error is caused by multiple SharePoint Framework components trying to instantiate their own copy of Microsoft Graph Toolkit. To avoid this issue, you should deploy the `mgt-spfx.sppkg` package to the SharePoint app catalog in your tenant and update all solutions that use Microsoft Graph Toolkit to use the `@microsoft/mgt-spfx` SharePoint package. For more information, see the [SharePoint Framework library for Microsoft Graph Toolkit](/graph/toolkit/get-started/mgt-spfx?WT.mc_id=m365-29707-wmastyka) documentation. +This error is caused by multiple SharePoint Framework components trying to instantiate their own copy of the Microsoft Graph Toolkit. To avoid this issue, you should deploy the `mgt-spfx.sppkg` package to the SharePoint app catalog in your tenant and update all solutions that use Microsoft Graph Toolkit to use the `@microsoft/mgt-spfx` SharePoint package. For more information, see the [SharePoint Framework library for Microsoft Graph Toolkit](/graph/toolkit/get-started/mgt-spfx?WT.mc_id=m365-29707-wmastyka) documentation. ### `AADSTS65001` error logged in the developer console diff --git a/docs/spfx/use-msgraph.md b/docs/spfx/use-msgraph.md index bfa44954c..ed92868a4 100644 --- a/docs/spfx/use-msgraph.md +++ b/docs/spfx/use-msgraph.md @@ -1,36 +1,37 @@ --- -title: Use the MSGraphClient to connect to Microsoft Graph -description: Use the MSGraphClient class to make calls to the Microsoft Graph REST API. -ms.date: 12/04/2020 -ms.prod: sharepoint -localization_priority: Priority +title: Use the MSGraphClientV3 to connect to Microsoft Graph +description: Use the MSGraphClientV3 class to make calls to the Microsoft Graph REST API. +ms.date: 08/29/2022 +ms.localizationpriority: high --- -# Use the MSGraphClient to connect to Microsoft Graph +# Use the MSGraphClientV3 to connect to Microsoft Graph -When building SharePoint Framework solutions, you can easily connect to the Microsoft Graph by using the **MSGraphClient**. +When building SharePoint Framework solutions, you can easily connect to the Microsoft Graph by using the **MSGraphClientV3**. ## MSGraphClient overview -**MSGraphClient** is a new HTTP client introduced in SharePoint Framework v1.6.0 that simplifies connecting to the Microsoft Graph inside SharePoint Framework solutions. **MSGraphClient** wraps the existing [Microsoft Graph JavaScript Client Library](https://www.npmjs.com/package/@microsoft/microsoft-graph-client), offering developers the same capabilities as when using the client library in other client-side solutions. +**MSGraphClientV3** is a new HTTP client introduced in SharePoint Framework v1.15.0 that simplifies connecting to the Microsoft Graph inside SharePoint Framework solutions. **MSGraphClientV3** wraps the [Microsoft Graph JavaScript Client Library v3](https://www.npmjs.com/package/@microsoft/microsoft-graph-client), offering developers the same capabilities as when using the client library in other client-side solutions. -While you could use the Microsoft Graph JavaScript Client Library in your solution directly, **MSGraphClient** handles authenticating against the Microsoft Graph for you, which allows you to focus on building your solution. +**MSGraphClientV3** replaces **MSGraphClient** which was introduced in SharePoint Framework v1.6.0. **MSGraphClient** wrapped the Microsoft Graph JavaScript Client Library v1. + +While you could use the Microsoft Graph JavaScript Client Library in your solution directly, **MSGraphClientV3** handles authenticating against the Microsoft Graph for you, which allows you to focus on building your solution. ## Use the MSGraphClient in your solution > [!NOTE] -> The **MSGraphClient** is available only in projects built using SharePoint Framework v1.6.0 and later. While the **MSGraphClient** is explained in this article by using a client-side web part, you can also use it in SharePoint Framework Extensions. +> The **MSGraphClientV3** is available only in projects built using SharePoint Framework v1.15.0 and later. While the **MSGraphClientV3** is explained in this article by using a client-side web part, you can also use it in SharePoint Framework Extensions. > [!NOTE] -> The single sign-on for the **MSGraphClient** is only available in SharePoint Online today. You can leverage the client for on premises developments but your users will be requested to sign in again within the webpart. +> The single sign-on for the **MSGraphClientV3** is only available in SharePoint Online today. You can leverage the client for on premises developments but your users will be requested to sign in again within the webpart. -1. To use the **MSGraphClient** in your SharePoint Framework solution, add the following `import` clause in your main web part file: +1. To use the **MSGraphClientV3** in your SharePoint Framework solution, add the following `import` clause in your main web part file: ```typescript - import { MSGraphClient } from '@microsoft/sp-http'; + import { MSGraphClientV3 } from '@microsoft/sp-http'; ``` -1. **MSGraphClient** is exposed through the **MSGraphClientFactory** available on the web part context. To get a reference to MSGraphClient, in your code add: +1. **MSGraphClientV3** is exposed through the **MSGraphClientFactory** available on the web part context. To get a reference to MSGraphClient, in your code add: ```typescript export default class HelloWorldWebPart extends BaseClientSideWebPart { @@ -38,8 +39,8 @@ While you could use the Microsoft Graph JavaScript Client Library in your soluti // ... this.context.msGraphClientFactory - .getClient() - .then((client: MSGraphClient): void => { + .getClient('3') + .then((client: MSGraphClientV3): void => { // use MSGraphClient here }); } @@ -48,7 +49,7 @@ While you could use the Microsoft Graph JavaScript Client Library in your soluti } ``` -1. After you have the reference to the **MSGraphClient** instance, start communicating with the Microsoft Graph by using its JavaScript Client Library syntax: +1. After you have the reference to the **MSGraphClientV3** instance, start communicating with the Microsoft Graph by using its JavaScript Client Library syntax: ```typescript export default class HelloWorldWebPart extends BaseClientSideWebPart { @@ -56,8 +57,8 @@ While you could use the Microsoft Graph JavaScript Client Library in your soluti // ... this.context.msGraphClientFactory - .getClient() - .then((client: MSGraphClient): void => { + .getClient('3') + .then((client: MSGraphClientV3): void => { // get information about the current user from the Microsoft Graph client .api('/me') @@ -95,12 +96,12 @@ When working with the Microsoft Graph and TypeScript, you can use the [Microsoft // ... this.context.msGraphClientFactory - .getClient() - .then((client: MSGraphClient): void => { + .getClient('3') + .then((client: MSGraphClientV3): void => { // get information about the current user from the Microsoft Graph client .api('/me') - .get((error, user: MicrosoftGraph.User, rawResponse?: any) => { + .get((error: any, user: MicrosoftGraph.User, rawResponse?: any) => { // handle the response }); }); diff --git a/docs/spfx/use-theme-colors-in-your-customizations.md b/docs/spfx/use-theme-colors-in-your-customizations.md index 7bd214a03..e8a47a7df 100644 --- a/docs/spfx/use-theme-colors-in-your-customizations.md +++ b/docs/spfx/use-theme-colors-in-your-customizations.md @@ -1,9 +1,8 @@ --- title: Use theme colors in your SharePoint Framework customizations description: Use theme colors so that your customizations look like a part of the site by referring to the theme colors of the context site in your SharePoint Framework solution. -ms.date: 02/26/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 06/13/2022 +ms.localizationpriority: high --- # Use theme colors in your SharePoint Framework customizations @@ -143,7 +142,7 @@ Occurrence of theme tokens within SharePoint UI may differ depending upon select ### Customizing theme colors -In order to customize theme colors, a custom theme should be created and added to a SharePoint tenant for selection on a target site or hub. See [SharePoint site theming](https://docs.microsoft.com/sharepoint/dev/declarative-customization/site-theming/sharepoint-site-theming-overview) for more information. +In order to customize theme colors, a custom theme should be created and added to a SharePoint tenant for selection on a target site or hub. See [SharePoint site theming](/sharepoint/dev/declarative-customization/site-theming/sharepoint-site-theming-overview) for more information. ## See also diff --git a/docs/spfx/using-teams-solutions-in-sharepoint.md b/docs/spfx/using-teams-solutions-in-sharepoint.md index a30b8819c..f561eec34 100644 --- a/docs/spfx/using-teams-solutions-in-sharepoint.md +++ b/docs/spfx/using-teams-solutions-in-sharepoint.md @@ -2,8 +2,7 @@ title: Hosting Microsoft Teams Tabs as a solution in SharePoint description: You can install and use your Microsoft Teams tabs also in SharePoint ms.date: 06/18/2020 -ms.prod: sharepoint -localization_priority: Normal +ms.localizationpriority: medium --- # Hosting Microsoft Teams Tabs as a solution in SharePoint diff --git a/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs-Entra.md b/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs-Entra.md new file mode 100644 index 000000000..b41dae766 --- /dev/null +++ b/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs-Entra.md @@ -0,0 +1,549 @@ +--- +title: Building Bot Powered Adaptive Card Extensions with Microsoft Entra ID and Single Sign-on (SSO) +description: Learn how to secure Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections with Microsoft Entra ID and single sign-on. +ms.date: 11/15/2024 +ms.localizationpriority: high +--- +# Building Bot Powered Adaptive Card Extensions with Microsoft Entra ID and Single Sign-on (SSO) + +Securing a Bot Powered Adaptive Card Extension (ACE) with Microsoft Entra ID and Single Sign-on (SSO) requires some configuration steps on Microsoft Azure and some custom logic in the code base. + +In this document, you find step-by-step guidance that will help you accomplish this task. + +## Understanding the sample scenario + +Let's assume that you want to create a Bot Powered ACE to write a welcome message for users, writing their name and the user principal name in a Card View. You want to authenticate users via OAuth with Microsoft Entra ID. In the following picture, you can see how the Adaptive Card Extension looks like in the Viva Connections desktop experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections desktop experience. There is a Card View showing a welcome message for authenticated users.](./images/Bot-Powered-ACE-Welcome-User-UI-Desktop-SSO.png) + +In the following picture, you can see what the Adaptive Card Extension looks like in the Viva Connections mobile experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections mobile experience. There is a Card View showing a welcome message for authenticated users.](./images/Bot-Powered-ACE-Welcome-User-UI-Mobile-SSO.png) + +From a developer point of view, you build the ACE once and you benefit from it in both desktop and mobile experiences. + +The whole source code of the .NET sample is available in the following GitHub repository: [Welcome User Bot Powered ACE SSO](https://github.com/pnp/viva-dev-bot-powered-aces/tree/main/samples/dotnet/WelcomeUserBotPoweredAce-SSO). + +## Developing a Secured Bot Powered ACE with Microsoft .NET and Microsoft Entra ID SSO + +First of all, you should create a Bot Powered ACE following the guidance provided in the article [Building your first Bot Powered Adaptive Card Extension](./Building-Your-First-Bot-Powered-ACE.md), stopping before the section [Implement the actual Bot Powered ACE](./Building-Your-First-Bot-Powered-ACE.md#implement-the-actual-bot-powered-ace). + +For the sake of simplicity, assume that the Bot Powered ACE project name is **WelcomeUserBotPoweredAce** and register the Azure Bot according to the guidance. + +## Configuring security for the Bot Powered ACE + +Before starting to develop the actual Bot Powered ACE, you need to enrich the configuration of the Azure Bot and of the Microsoft App behind the scenes of the Azure Bot. +To access the Microsoft App backing the Azure Bot, open the **Configuration** panel of the Azure Bot and select the **Manage Password** link. + +Now, select the **Authentication** panel of the Microsoft App, and under the **Platform configurations** section, select **Add a platform** and select to add a *Web* platform. Then configure the following value for the **Redirect URIs** setting field. + +```http +https://token.botframework.com/.auth/web/redirect +``` + +You should also enable **Implicit grant and hybrid flows** by selecting the options to issue **Access tokens** and **ID tokens**. Select the **Configure** button and your new Web platform is configured. + +![The panel to configure a Web platform for the Microsoft App. You can configure the "Redirect URIs" for the web app and enable the "Implicit grant and hybrid flows" with support for "Access tokens" and "ID tokens".](./images/Azure-Portal-Create-Azure-Bot-05.png) + +Now, select the **API permissions** panel and configure the app with the following delegated permissions: + +* email +* offline_access +* openid +* profile +* User.Read + +Select the **Grant admin consent for ...** button, to grant the permissions at the tenant level. + +![The panel to configure the "API permissions". There are few permissions already selected, including: email, offline_access, openid, profile, and User.Read. All of the permissions are granted at tenant level.](./images/Azure-Portal-Create-Azure-Bot-06.png) + +Now, move to the **Expose an API** panel and configure a unique URI for your application by selecting the **Add** link just beside the **Application ID URI** label. Here you need to configure a value for the **Application ID URI** that matches the following rule: + +```http +api://.ngrok.io/ +``` + +For example, if you plan to use the name *welcome-bot-powered-ace* with ngrok, and the Client ID of your application is *fff49e21-925f-4dc9-be03-2680c4783091* the **Application ID URI** should be: + +```http +api://welcome-bot-powered-ace.ngrok.io/fff49e21-925f-4dc9-be03-2680c4783091 +``` + +> [!NOTE] +> Mind the `api://` moniker at the beginning of the Application ID URI value, and be careful to not use `http://` or `https://` unless you want to use a verified domain of the organization or its subdomain. + +Now in the **Scopes defined by this API** section add a new scope by selecting the **Add a scope** button. Provide the following settings for the new scope: + +* Scope name: *access_as_user*. +* Who can consent?: Admins and users. +* Admin consent display name: Teams can access the user's profile. +* Admin consent description: Allows Teams to call the app's web APIs as the current user. +* User consent display name: Teams can access the user's profile and make requests on the user's behalf. +* User consent description: Enables Teams to call this app's APIs with the same rights as the user. +* State: Enabled. + +![The panel to add a new permission scope. There are options to configure the scope name, who can consent the scope, the admin consent display name and description, the user consent display name and description, and the state of the scope.](./images/Azure-Portal-Create-Azure-Bot-07.png) + +Lastly, in the **Authorized client applications** section, you need to configure the client ID of the **SharePoint Online Web Client Extensibility** application. You also need to authorize that client application to consume your Microsoft App, so that users shouldn't be asked to consent when the Viva Connections client calls your API. The client ID of the **SharePoint Online Web Client Extensibility** application is the following one: + +* 08e18876-6177-487e-b8b5-cf950c1e598c + +While adding it to the list of **Authorized client applications**, select the permission scope that you configured for the API. + +![The panel to add a new authorized client application. You can provide the client ID of the authorized client application and you can select the scopes that you want to authorize for that specific client application.](./images/Azure-Portal-Create-Azure-Bot-08.png) + +At the end of this stage, the **Expose an API** panel should look like in the following picture. + +![The "Expose an API" panel configured with a custom Application ID URI, a custom scope with name "access_as_user", and a couple of authorized client applications.](./images/Azure-Portal-Create-Azure-Bot-09.png) + +## Configuring the OAuth connection for the Azure Bot + +Then you need to configure an OAuth connection for the Azure Bot. To configure the OAuth connection, go back to the **Configuration** panel of the Azure Bot and select the **Add OAuth Connection Settings** button. + +![The configuration panel for an Azure Bot. It includes settings about Messaging Endpoint URL, the Microsoft App ID, the Application Insights keys, the Schema Transformation Version, and the OAuth Connection settings. The "Add OAuth Connection Settings" button is highlighted.](./images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-01.png) + +You're prompted with a panel to configure the name of the new OAuth connection and the service provider that you want to use. The name can be whatever text you like, but you need to save it in a safe place because you need it later. Let's name the connection **WelcomeUserBot-EntraID**. The service provider configuration field defines the Identity Provider to use for the actual OAuth connection. There are plenty of options. To rely on Microsoft Entra ID, select **Azure Active Directory v2**. + +After selecting the service provider, you have to configure it. For **Azure Active Directory v2** you have to provide: + +* **Client ID**: the client ID of the Microsoft App behind the scenes of your Azure Bot. It's the value that you get while registering the Azure Bot. +* **Client secret**: the client secret of the Microsoft App behind the scenes of your Azure Bot. It's the value that you get while registering the Azure Bot. +* **Token exchange URL**: the URL to retrieve an OAuth token for your Microsoft App. For a multitenant application, it should be like: `https://login.microsoftonline.com/common/oauth2/v2.0/token`. Notice the *common* part, which for a single-tenant application should be replaced with the actual tenant ID of the target tenant. +* **Tenant ID**: the tenant ID of the Microsoft App behind the scenes of your Azure Bot. For a multitenant application, it should be *common*. For a single-tenant application, it's the tenant ID of the target tenant. +* **Scopes**: space-separated list of delegated permission scopes that you want to have in the OAuth Access Token when the user signs in to your ACE. They must be configured and granted in the "API permissions" panel of the Microsoft App behind the scenes of your Azure Bot. + +Once configured the new OAuth connection, select the **Save** button, and eventually select also the **Test Connection** button to test the connection. The following picture shows the OAuth connection panel properly configured. + +![The configuration panel for a new OAuth connection of an Azure Bot. It includes settings about Name, Service Provider, Client id, Client secret, Token Exchange URL, Tenant ID, Scopes. There are also a "Save" and a "Cancel" button, as well as a "Delete" or a "Test Connection" button.](./images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-02.png) + +If you select the **Test Connection** button, you can get a preview of an OAuth Access Token for your Azure Bot for the current user. The following picture shows how the "Test Connection" functionality gives you access to the Access Token. + +![The page to "Test Connection". There is a textbox with an hidden access token value. You can select the "Show Token" button to see the actual text of the token. You can select the "Copy Token" button to copy the token value in the clipboard.](./images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-03.png) + +If you select the **Copy Token** button, you can then open the [https://jwt.ms](https://jwt.ms) website in a web browser, paste the token value, and have a look at its content for learning and debugging purposes only. + +> [!NOTE] +> If you inspect the claims of the token, you can see the `aud` (Audience, which is the Client ID of the Microsoft Graph) `app_displayname` (App display name), `iss` (Token issuer), `appid` (Client ID), `tid` (Tenant ID), `scp` (Permission scopes). You can also double-check that they refer to the application that you just configured. + +## Implementing security in your Bot + +Go back to the Visual Studio project that you created before. Open the **appsettings.json** file and add a new setting called **ConnectionName** and set its value to the name of the OAuth connection that you created. Here you can see what the settings file should look like. + +```JSON +{ + "MicrosoftAppType": "MultiTenant", + "MicrosoftAppId": "", + "MicrosoftAppPassword": "", + "MicrosoftAppTenantId": "", + "ConnectionName": "" +} +``` + +To have the latest types needed to support the security infrastructure of the Bot Powered ACE, upgrade the NuGet package with name **Microsoft.Bot.Builder.Integration.AspNet.Core** to version 4.22.9 or higher. + +Rename the **EmptyBot.cs** file into **WelcomeUserBot.cs**, change the base class from `ActivityHandler` to `SharePointActivityHandler`, and import the namespace `Microsoft.Bot.Builder.SharePoint`. + +Follow the instructions provided in the ["Implement the actual Bot Powered ACE"](./Building-Your-First-Bot-Powered-ACE.md#implement-the-actual-bot-powered-ace) section of the reference article ["Building your first Bot Powered Adaptive Card Extension"](./Building-Your-First-Bot-Powered-ACE.md) to implement the basic code of the Bot Powered ACE. Specifically, implement four Card Views: + +* Welcome: it's the Card View that shows the welcome message with user display name and user principal name of the currently authenticated user. +* Sign-In: it's the Card View to allow an end user to sign-in via Microsoft Entra ID. +* Signed-Out: it's the Card View to confirm when an authenticated user signed out. +* Error: it's the Card View to show an error message, in case an error occurs. + +### Implementing the welcome card view + +In the following code excerpt, you can see how the welcome Card View is defined in the constructor of the Bot. + +```CSharp +// Prepare ACE data for all Card Views +var aceData = new AceData() +{ + Title = "Welcome!", + CardSize = AceData.AceCardSize.Large, + DataVersion = "1.0", + Id = adaptiveCardExtensionId +}; + +// Home Card View (Primary Text Card View) +CardViewResponse homeCardViewResponse = new CardViewResponse(); +homeCardViewResponse.AceData = aceData; +homeCardViewResponse.CardViewParameters = CardViewParameters.PrimaryTextCardViewParameters( + new CardBarComponent() + { + Id = "HomeCardView", + }, + new CardTextComponent() + { + Text = "Welcome !" + }, + new CardTextComponent() + { + Text = "Your UPN is: " + }, + new List() + { + new CardButtonComponent() + { + Id = "SignOut", + Title = "Sign out", + Action = new SubmitAction() + } + + }); +homeCardViewResponse.ViewId = HomeCardView_ID; + +cardViews.TryAdd(homeCardViewResponse.ViewId, homeCardViewResponse); +``` + +As you can see, it's a Primary Text Card View, which simply renders a text with the current user display name in the header. There's also another text with the user principal name in the body. Additionally, there's a **Sign out** button that allows the user to sign out, when there's a current authenticated session. In scenarios like the one described in this article, where you configured single sign-on, the sign-out button doesn't make any sense. Whenever a user signs out, the SSO experience automatically signs the user in again. However, for the sake of better understanding the development model, in the sample associated with this article, you can find the sign out implementation. In a real solution, you shouldn't provide a sign out button and you shouldn't implement its logic. + +### Implementing the sign-in card view with single sign-on + +The Sign-In card view should be implemented as follows: + +```CSharp +// SignIn Card View (Sign-In Card View) +CardViewResponse signInCardViewResponse = new CardViewResponse(); +signInCardViewResponse.AceData = aceData; +signInCardViewResponse.CardViewParameters = CardViewParameters.SignInCardViewParameters( + new CardBarComponent() + { + Id = "SignInCardView", + }, + new CardTextComponent() + { + Text = "User's Sign in!" + }, + new CardTextComponent() + { + Text = "Please, sign in ..." + }, + new CardButtonComponent() +); +signInCardViewResponse.CardViewParameters.CardViewType = "signInSso"; +signInCardViewResponse.ViewId = SignInCardView_ID; + +cardViews.TryAdd(signInCardViewResponse.ViewId, signInCardViewResponse); +``` + +You need to use the `SignInCardViewParameters` factory method to create a Sign In Card View, which is designed to implement the sign in logic. The Sign In Card View looks like a Primary Text Card View, in fact, there are text components both in the header and in the body. By default, every Sign In Card View has a Sign in button that is provided out of the box in the Card View template. At the time of this writing, the footer requires you to also provide another button to support extra logic in the sign in flow. However, when you have SSO in place, you don't need to provide any another logic and you can provide an empty `CardButtonComponent`. +One last important thing to notice is the setting of the `CardViewType` property for the Card View object to value `signInSso`, which is the one required to configure the single sign-on behavior. + +### Implementing other card views + +In the following code excerpt you can see the SignedOut card view implementation, which defines a card that confirms to the user that the sign out was completed: + +```CSharp +// Signed out Card View (Basic Card View) +CardViewResponse signedOutCardViewResponse = new CardViewResponse(); +signedOutCardViewResponse.AceData = aceData; +signedOutCardViewResponse.CardViewParameters = CardViewParameters.BasicCardViewParameters( + new CardBarComponent() + { + Id = "SignedOutCardView", + }, + new CardTextComponent() + { + Text = "You are now signed out!" + }, + new List() + { + new CardButtonComponent() + { + Id = "OkSignedOut", + Title = "Ok", + Action = new SubmitAction() + { + Parameters = new Dictionary() + { + { "viewToNavigateTo", HomeCardView_ID } + } + } + } + }); +signedOutCardViewResponse.ViewId = SignedOutCardView_ID; + +cardViews.TryAdd(signedOutCardViewResponse.ViewId, signedOutCardViewResponse); +``` + +The Signed out Card View is a basic card view with a simple text message in the body and a button to go back to the home Card View. + +> [!NOTE] +> As already stated before, when you have single sign-on in place, you can still trigger the sign out logic. However, as soon as the user goes back to the home card view, the single sign-on logic is triggered and the user is authenticated again. + +In the sample solution, there's also an Error Card View, which for the sake of simplicity isn't illustrated in this article but is available in the [reference solution](https://github.com/pnp/viva-dev-bot-powered-aces/tree/main/samples/dotnet/WelcomeUserBotPoweredAce-SSO). + +### Implementing Bot Powered ACEs specific methods + +You also need to implement a couple of methods to handle the card view rendering and any action, like a button selection, in the UI of the card views. The following code excerpt shows how to implement both the `OnSharePointTaskGetCardViewAsync` and `OnSharePointTaskHandleActionAsync` methods. + +```CSharp +protected async override Task OnSharePointTaskGetCardViewAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) +{ + // Check to see if the user has already signed in + var (displayName, upn) = await GetAuthenticatedUser(magicCode: null, turnContext, cancellationToken); + if (displayName != null && upn != null) + { + var homeCardView = cardViews[HomeCardView_ID]; + if (homeCardView != null) + { + ((homeCardView.CardViewParameters.Header.ToList())[0] as CardTextComponent).Text = $"Welcome {displayName}!"; + ((homeCardView.CardViewParameters.Body.ToList())[0] as CardTextComponent).Text = $"Your UPN is: {upn}"; + return homeCardView; + } + } + else + { + var signInCardView = cardViews[SignInCardView_ID]; + if (signInCardView != null) + { + var signInResource = await GetSignInResource(turnContext, cancellationToken); + var signInLink = signInResource != null ? new Uri(signInResource.SignInLink) : new Uri(string.Empty); + + signInCardView.AceData.Properties = Newtonsoft.Json.Linq.JObject.FromObject(new Dictionary() { + { "uri", signInLink }, + { "connectionName", this._connectionName } + }); + return signInCardView; + } + } + + return cardViews[ErrorCardView_ID]; +} + +protected async override Task OnSharePointTaskHandleActionAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) +{ + if (turnContext != null) + { + if (cancellationToken.IsCancellationRequested) + { + cancellationToken.ThrowIfCancellationRequested(); + } + } + JObject actionParameters = aceRequest.Data as JObject; + + if (actionParameters != null) + { + var actionId = actionParameters["id"].ToString(); + if (actionId == "SignOut") + { + await SignOutUser(turnContext, cancellationToken); + + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[SignedOutCardView_ID] + }; + } + else if (actionId == "OkSignedOut") + { + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[SignInCardView_ID] + }; + } + else if (actionId == "OkError") + { + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[HomeCardView_ID] + }; + } + } + + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[ErrorCardView_ID] + }; +} +``` + +The `OnSharePointTaskGetCardViewAsync` method handles the rendering of the Welcome card view, rendering the display name and the user principal name of the currently authenticated user, if any. On the contrary, if there isn't a user's security context, it renders the Sign-in card view, configuring the name of the OAuth connection to use and retrieving the Sign-in URL from the infrastructural services provided by the Bot Framework via the `GetSignInResource` method. + +The `OnSharePointTaskHandleActionAsync` method handles the selection of all the buttons provided in the UI of the Bot Powered ACE. + +### Handling single sign-on dedicated logic + +To authenticate users with single sign-on, you need to override the `OnSignInInvokeAsync` method to handle the single sign-on request. + +```CSharp +protected override Task OnSignInInvokeAsync(ITurnContext turnContext, CancellationToken cancellationToken) +{ + SharePointSSOTokenExchangeMiddleware sso = new SharePointSSOTokenExchangeMiddleware(_storage, _connectionName); + return sso.OnTurnAsync(turnContext, cancellationToken); +} +``` + +The `SharePointSSOTokenExchangeMiddleware` type is defined in the **botbuilder** package and takes care of handling the single sign-on request and storing the user's token in a temporary storage. It also accepts the name of the OAuth connection configured for the Azure Bot. The storage can be any cache manager of your choice, as long as it implements the `IStorage` interface. Here you can see an example of an in-memory cache storage. + +```CSharp +public class InMemoryStorage : IStorage +{ + // Thread-safe dictionary for storing bot state in-memory + private readonly ConcurrentDictionary _memoryStorage = new ConcurrentDictionary(); + + /// + /// Reads state from the in-memory store. + /// + /// The keys of the states to read. + /// Cancellation token. + /// A dictionary of bot state objects. + public Task> ReadAsync(string[] keys, CancellationToken cancellationToken = default) + { + var storeItems = new Dictionary(); + + foreach (var key in keys) + { + // Try to get the object from the dictionary + if (_memoryStorage.TryGetValue(key, out var value)) + { + storeItems.Add(key, value); + } + } + + return Task.FromResult((IDictionary)storeItems); + } + + /// + /// Writes state to the in-memory store. + /// + /// Dictionary containing state objects to write. + /// Cancellation token. + public Task WriteAsync(IDictionary changes, CancellationToken cancellationToken = default) + { + foreach (var change in changes) + { + // Store the object in the dictionary + _memoryStorage.AddOrUpdate(change.Key, change.Value, (key, oldValue) => change.Value); + } + + return Task.CompletedTask; + } + + /// + /// Deletes state from the in-memory store. + /// + /// The keys of the states to delete. + /// Cancellation token. + public Task DeleteAsync(string[] keys, CancellationToken cancellationToken = default) + { + foreach (var key in keys) + { + // Remove the object from the dictionary + _memoryStorage.TryRemove(key, out _); + } + + return Task.CompletedTask; + } +} +``` + +If you're using dependency injection, you can configure the cache manager as a singleton service and retrieve the service instance in the constructor of the bot, like in the code sample associated with this article. + +### Implementing other security-related logic + +Once you support the single sign-on logic, you can rely on a set of utility methods to retrieve the current user's information. These methods retrieve the current authenticated user, and their token, and provide the sign-out logic, if there's a need. + +Here follows the internal logic that you should rely on to manage the access token and the current user's identity retrieval through the `GetAuthenticatedUser`, `GetUserToken`, and `GetSignInResource` methods. + +```CSharp +private async Task<(string displayName, string upn)> GetAuthenticatedUser(string magicCode, ITurnContext turnContext, CancellationToken cancellationToken) +{ + string displayName = null; + string upn = null; + + try + { + var response = await GetUserToken(magicCode, turnContext, cancellationToken).ConfigureAwait(false); + if (response != null && !string.IsNullOrEmpty(response.Token)) + { + var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(response.Token); + displayName = token.Claims.FirstOrDefault(c => c.Type == System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames.Name)?.Value; + upn = token.Claims.FirstOrDefault(c => c.Type == "upn")?.Value; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error while trying to retrieve current user's displayName and UPN!"); + } + + return (displayName, upn); +} + +private async Task GetUserToken(string magicCode, ITurnContext turnContext, CancellationToken cancellationToken) +{ + // Get the UserTokenClient service instance + var userTokenClient = turnContext.TurnState.Get(); + + // Assuming the bot is already configured for SSO and the user has been authenticated + return await userTokenClient.GetUserTokenAsync( + turnContext.Activity.From.Id, + _connectionName, // The name of your Azure AD connection + turnContext.Activity.ChannelId, + magicCode, + cancellationToken).ConfigureAwait(false); +} + +private async Task GetSignInResource(ITurnContext turnContext, CancellationToken cancellationToken) +{ + // Get the UserTokenClient service instance + var userTokenClient = turnContext.TurnState.Get(); + + // Retrieve the Sign In Resource from the UserTokenClient service instance + var signInResource = await userTokenClient.GetSignInResourceAsync(_connectionName, (Microsoft.Bot.Schema.Activity)turnContext.Activity, null, cancellationToken).ConfigureAwait(false); + return signInResource; +} +``` + +The `GetAuthenticatedUser` method accepts the magic code value and the Bot `TurnContext` instance. Internally it uses the `GetUserToken` method to retrieve the actual access token value and then uses the `JwtSecurityToken` class of `System.IdentityModel.Tokens.Jwt` to decode the token and get access to the user's display name and user principal name. + +> [!NOTE] +> Using the same technique and reading the **scp** claim (Scope) or any other claim of your interest, you can eventually implement custom authorization logic for your Bot Powered ACE. + +The `GetUserToken` method retrieves an instance of the `UserTokenClient` service and makes the actual request for the token using the `GetUserTokenAsync`, which accepts the following input arguments: + +* the ID of the sender (From) for the current Activity of the Bot instance +* the name of the OAuth connection defined in the configuration of the Azure Bot +* the ID of the Channel for the Bot instance +* the magic code value, which is null if there's single sign-on in place or there's an already cached user's token +* the cancellation token for the asynchronous request + +The result of the `GetUserTokenAsync` method is an instance of the `TokenResponse` type that includes a `Token` property with the actual value of the access token. +Once you have the access token and you extracted the display name and the user principal name, you can render them in the welcome card view. + +The `GetSignInResource` method relies on an instance of the `UserTokenClient` service and retrieves the URL to use for signing in the user invoking the `GetSignInResourceAsync` method. + +In the code excerpt, you can also see how the sign-out is handled, invoking the custom `SignOutUser` method, which is illustrated in the following code excerpt. + +```CSharp +private async Task SignOutUser(ITurnContext turnContext, CancellationToken cancellationToken) +{ + // Get the UserTokenClient service instance + var userTokenClient = turnContext.TurnState.Get(); + + // Sign out the current user + await userTokenClient.SignOutUserAsync( + turnContext.Activity.From.Id, + _connectionName, // The name of your Azure AD connection + turnContext.Activity.ChannelId, + cancellationToken).ConfigureAwait(false); +} +``` + +The method uses the `UserTokenClient` service to invoke the `SignOutUserAsync` method. + +## Configuring the manifest + +The implementation of the Bot Powered ACE is now complete and you just need to create a manifest file and deploy it into the target tenant SharePoint Online App Catalog. You can find step-by-step instructions about how to do that in the section [Define the **manifest.json** file for the solution](./Building-Your-First-Bot-Powered-ACE.md#define-the-manifestjson-file-for-the-solution) section of the reference article [Building your first Bot Powered Adaptive Card Extension](./Building-Your-First-Bot-Powered-ACE.md). + +To properly support authentication, you need to add a `webApplicationInfo` section to the **manifest.json** file, like illustrated in the following excerpt. + +```JSON + "webApplicationInfo": { + "id": "", + "resource": "api://.ngrok.io/" + }, +``` + +The `id` property is the actual Client ID of the Microsoft App behind the scenes of your Azure Bot. The `resource` property is the unique URI that you configured for that Microsoft App. + +You're now ready to package the solution, deploy it on the SharePoint Online App Catalog, and play with it. You can follow the instructions provided in section ["Run and test the solution"](./Building-Your-First-Bot-Powered-ACE.md#run-and-test-the-solution) of the reference article ["Building your first Bot Powered Adaptive Card Extension."](./Building-Your-First-Bot-Powered-ACE.md) diff --git a/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs-Magic-Code.md b/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs-Magic-Code.md new file mode 100644 index 000000000..cff81a7e6 --- /dev/null +++ b/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs-Magic-Code.md @@ -0,0 +1,612 @@ +--- +title: Building Bot Powered Adaptive Card Extensions with Magic Code authentication +description: Learn how to secure Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections using any identity provider and a magic code. +ms.date: 11/15/2024 +ms.localizationpriority: high +--- +# Building Bot Powered Adaptive Card Extensions with Magic Code authentication + +To secure a Bot Powered Adaptive Card Extension (ACE), you need some configuration steps on Microsoft Azure and some custom logic in the code base, depending on the authentication provider you want to use. You can configure a third-party Identity Provider or Microsoft Entra ID as the authentication provider. + +Being the Bot Powered ACEs based on the Azure Bot technology, also Authentication and Authorization use the same security architecture of regular Azure Bots. As such, when authenticating users with an Identity Provider, the Bot Framework relies on a magic code to complete the authentication process. + +In this article, you find step-by-step guidance that helps you build a solution that authenticates with a Microsoft Entra ID without single sign-on, but actually relying on the magic code. However, the same technique can be used to configure any third-party Identity Provider. + +## Understanding the sample scenario + +Let's assume that you want to create a Bot Powered ACE to write a welcome message for users, writing their name and the user principal name in a Card View. You want to authenticate users via OAuth with a third-party Identity Provider. For the sake of simplicity, in this article, we use Microsoft Entra ID without single sign-on, but it could be any other Identity Provider. + +When on a desktop environment and with Microsoft Entra ID, the magic code handling is supported automatically. As such, the end user sees a dance of dialogs on the screen, and the ACE authentication happens automatically. In fact, aside from selecting a **Sign-in** button, there isn't need to do any manual operation to complete the authentication flow. + +When using a third-party Identity Provider, the user needs to manually copy and paste the value of the magic code to complete the sign-in flow. + +In the following picture, you can see how the Adaptive Card Extension looks like in the Viva Connections desktop experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections desktop experience. There is a Card View showing a sign-in interface with a "Sign-in" button. There is also another Card View showing a welcome message for an authenticated users.](./images/Bot-Powered-ACE-Welcome-User-UI-Desktop.png) + +In the following picture, you can see how the Adaptive Card Extension looks like in the Viva Connections mobile experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections mobile experience. There is a Card View showing a sign-in interface with a "Sign-in" button. There is also another Card View showing a welcome message for an authenticated users.](./images/Bot-Powered-ACE-Welcome-User-UI-Mobile.png) + +In both scenarios (desktop and mobile), there are: + +- **Sign in** button to initiate the sign-in flow +- **Complete sign in** button to provide the magic code obtained by the Bot Framework and complete the authentication flow + +From a developer point of view, you build the ACE once and you benefit from it in both desktop and mobile experiences. + +The whole source code of the .NET sample is available in the following GitHub repository: [Welcome User Bot Powered ACE](https://github.com/pnp/viva-dev-bot-powered-aces/tree/main/samples/dotnet/WelcomeUserBotPoweredAce). + +## Developing a Secured Bot Powered ACE with Microsoft .NET and Magic Code + +First of all, you should create a Bot Powered ACE following the guidance provided in the article [Building your first Bot Powered Adaptive Card Extension](./Building-Your-First-Bot-Powered-ACE.md), stopping before the section [Implement the actual Bot Powered ACE](./Building-Your-First-Bot-Powered-ACE.md#implement-the-actual-bot-powered-ace). + +For the sake of simplicity, assume that the Bot Powered ACE project name is "WelcomeUserBotPoweredAce" and register the Azure Bot according to the guidance. + +## Configuring security for the Bot Powered ACE + +Before starting to develop the actual Bot Powered ACE, you need to enrich the configuration of the Azure Bot and of the Microsoft App behind the scenes of the Azure Bot. + +To access the Microsoft App backing the Azure Bot, open the **Configuration** panel of the Azure Bot and select the **Manage Password** link. + +Now, select the **Authentication** panel of the Microsoft App, and under the **Platform configurations** section, select on **Add a platform** and select to add a *Web* platform. Then configure the following value for the **Redirect URIs** setting field. + +```http +https://token.botframework.com/.auth/web/redirect +``` + +You should also enable **Implicit grant and hybrid flows** by selecting the options to issue **Access tokens** and **ID tokens**. Select the **Configure** button and your new Web platform is configured. + +![The panel to configure a Web platform for the Microsoft App. You can configure the "Redirect URIs" for the web app and enable the "Implicit grant and hybrid flows" with support for "Access tokens" and "ID tokens".](./images/Azure-Portal-Create-Azure-Bot-05.png) + +Now, select the **API permissions** panel and configure the app with the following delegated permissions: + +* email +* offline_access +* openid +* profile +* User.Read + +Select the **Grant admin consent for ...** button, in order to grant the permissions at the tenant level. + +![The panel to configure the "API permissions". There are few permissions already selected, including: email, offline_access, openid, profile, and User.Read. All of the permissions are granted at tenant level.](./images/Azure-Portal-Create-Azure-Bot-06.png) + +Now, move to the **Expose an API** panel and configure a unique URI for your application by selecting the **Add** link just beside the **Application ID URI** label. Here you need to configure a value for the **Application ID URI** that matches the following rule: + +```http +api://.ngrok.io/ +``` + +For example, if you plan to use the name *welcome-bot-powered-ace* with ngrok, and the Client ID of your application is *fff49e21-925f-4dc9-be03-2680c4783091* the **Application ID URI** should be: + +```http +api://welcome-bot-powered-ace.ngrok.io/fff49e21-925f-4dc9-be03-2680c4783091 +``` + +> [!NOTE] +> Mind the `api://` moniker at the beginning of the **Application ID URI** value, and be careful to not use `http://` or `https://` unless you want to use a verified domain of the organization or its subdomain. + +Now in the **Scopes defined by this API** section add a new scope by selecting the **Add a scope** button. Provide the following settings for the new scope: + +* Scope name: *access_as_user*. +* Who can consent?: Admins and users. +* Admin consent display name: Teams can access the user's profile. +* Admin consent description: Allows Teams to call the app's web APIs as the current user. +* User consent display name: Teams can access the user's profile and make requests on the user's behalf. +* User consent description: Enables Teams to call this app's APIs with the same rights as the user. +* State: Enabled. + +![The panel to add a new permission scope. There are options to configure the scope name, who can consent the scope, the admin consent display name and description, the user consent display name and description, and the state of the scope.](./images/Azure-Portal-Create-Azure-Bot-07.png) + +Lastly, in the **Authorized client applications** section, you need to configure the client ID of the **SharePoint Online Web Client Extensibility** application. You also need to authorize that client application to consume your Microsoft App, so that users shouldn't be asked to consent when the Viva Connections client calls your API. The client ID of the **SharePoint Online Web Client Extensibility** application is the following one: + +* 08e18876-6177-487e-b8b5-cf950c1e598c + +While adding it to the list of **Authorized client applications**, select the permission scope that you configured for the API. + +![The panel to add a new authorized client application. You can provide the client ID of the authorized client application and you can select the scopes that you want to authorize for that specific client application.](./images/Azure-Portal-Create-Azure-Bot-08.png) + +At the end of this stage, the **Expose an API** panel should look like in the following picture. + +![The "Expose an API" panel configured with a custom Application ID URI, a custom scope with name "access_as_user", and a couple of authorized client applications.](./images/Azure-Portal-Create-Azure-Bot-09.png) + +## Configuring the OAuth connection for the Azure Bot + +Then you need to configure an OAuth connection for the Azure Bot. To configure the OAuth connection, go back to the **Configuration** panel of the Azure Bot and select the **Add OAuth Connection Settings** button. + +![The configuration panel for an Azure Bot. It includes settings about Messaging Endpoint URL, the Microsoft App ID, the Application Insights keys, the Schema Transformation Version, and the OAuth Connection settings. The "Add OAuth Connection Settings" button is highlighted.](./images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-01.png) + +You're prompted with a panel to configure the name of the new OAuth connection and the service provider that you want to use. The name can be whatever text you like, but you need to save it in a safe place because you need it later. Let's name the connection **WelcomeUserBot-EntraID**. The service provider configuration field defines the Identity Provider to use for the actual OAuth connection. There are plenty of options. To rely on Microsoft Entra ID, choose **Azure Active Directory v2**. + +After selecting the service provider, you have to configure it. For **Azure Active Directory v2** you have to provide: + +* **Client ID**: the client ID of the Microsoft App behind the scenes of your Azure Bot. It's the value that you get while registering the Azure Bot. +* **Client secret**: the client secret of the Microsoft App behind the scenes of your Azure Bot. It's the value that you get while registering the Azure Bot. +* **Token exchange UR**L: the URL to retrieve an OAuth token for your Microsoft App. For a multitenant application, it should be like: `https://login.microsoftonline.com/common/oauth2/v2.0/token`. Notice the *common* part, which for a single-tenant application should be replaced with the actual tenant ID of the target tenant. +* **Tenant ID**: the tenant ID of the Microsoft App behind the scenes of your Azure Bot. For a multitenant application, it should be *common*. For a single-tenant application, it's the tenant ID of the target tenant. +* **Scopes**: space-separated list of delegated permission scopes that you want to have in the OAuth Access Token when the user signs in to your ACE. They must be configured and granted in the **API permissions** panel of the Microsoft App behind the scenes of your Azure Bot. + +Once configured the new OAuth connection, select the **Save** button, and eventually select also the "Test Connection" button to test the connection. The following picture shows the OAuth connection panel properly configured. + +![The configuration panel for a new OAuth connection of an Azure Bot. It includes settings about Name, Service Provider, Client id, Client secret, Token Exchange URL, Tenant ID, Scopes. There are also a "Save" and a "Cancel" button, as well as a "Delete" or a "Test Connection" button.](./images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-02.png) + +If you select the **Test Connection** button, you can get a preview of an OAuth Access Token for your Azure Bot for the current user. The following picture shows how the **Test Connection** functionality gives you access to the Access Token. + +![The page to "Test Connection". There is a textbox with an hidden access token value. You can select the "Show Token" button to see the actual text of the token. You can select the "Copy Token" button to copy the token value in the clipboard.](./images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-03.png) + +If you select the **Copy Token** button, you can then open the [https://jwt.ms](https://jwt.ms) website in a web browser, paste the token value, and have a look at its content for learning and debugging purposes only. + +> [!NOTE] +> If you inspect the claims of the token, you can see the `aud` (Audience, which is the Client ID of the Microsoft Graph) `app_displayname` (App display name), `iss` (Token issuer), `appid` (Client ID), `tid` (Tenant ID), `scp` (Permission scopes). You can also double-check that they refer to the application that you just configured. + +## Implementing security in your Bot + +Go back to the Visual Studio project that you created before. Open the **appsettings.json** file and add a new setting called **ConnectionName** and set its value to the name of the OAuth connection that you created. Here you can see what the settings file should look like. + +```JSON +{ + "MicrosoftAppType": "MultiTenant", + "MicrosoftAppId": "", + "MicrosoftAppPassword": "", + "MicrosoftAppTenantId": "", + "ConnectionName": "" +} +``` + +To have the latest types needed to support the security infrastructure of the Bot Powered ACE, upgrade the NuGet package with the name **Microsoft.Bot.Builder.Integration.AspNet.Core** to version 4.22.9 or higher. + +Rename the **EmptyBot.cs** file into **WelcomeUserBot.cs**, change the base class from `ActivityHandler` to `SharePointActivityHandler`, and import the namespace `Microsoft.Bot.Builder.SharePoint`. + +Follow the instructions provided in the [Implement the actual Bot Powered ACE](./Building-Your-First-Bot-Powered-ACE.md#implement-the-actual-bot-powered-ace) section of the reference article [Building your first Bot Powered Adaptive Card Extension](./Building-Your-First-Bot-Powered-ACE.md) to implement the basic code of the Bot Powered ACE. Specifically, implement four Card Views: + +* **Welcome**: it's the Card View that shows the welcome message with the user display name and user principal name of the currently authenticated user. +* **Sign-In**: it's the Card View to allow an end user to sign-in via Microsoft Entra ID. +* **Signed-Out**: it's the Card View to confirm when an authenticated user signed out. +* **Error**: it's the Card View to show an error message, in case an error occurs. + +### Implementing the welcome card view + +In the following code excerpt, you can see how the welcome Card View is defined in the constructor of the Bot. + +```CSharp +// Prepare ACE data for all Card Views +var aceData = new AceData() +{ + Title = "Welcome!", + CardSize = AceData.AceCardSize.Large, + DataVersion = "1.0", + Id = adaptiveCardExtensionId +}; + +// Home Card View (Primary Text Card View) +CardViewResponse homeCardViewResponse = new CardViewResponse(); +homeCardViewResponse.AceData = aceData; +homeCardViewResponse.CardViewParameters = CardViewParameters.PrimaryTextCardViewParameters( + new CardBarComponent() + { + Id = "HomeCardView", + }, + new CardTextComponent() + { + Text = "Welcome !" + }, + new CardTextComponent() + { + Text = "Your UPN is: " + }, + new List() + { + new CardButtonComponent() + { + Id = "SignOut", + Title = "Sign out", + Action = new SubmitAction() + } + + }); +homeCardViewResponse.ViewId = HomeCardView_ID; + +cardViews.TryAdd(homeCardViewResponse.ViewId, homeCardViewResponse); +``` + +As you can see, it's a Primary Text Card View, which simply renders a text with the current user display name in the header. There's also another text with the user principal name in the body. Additionally, there's a **Sign out** button that allows the user to sign out when there's a current authenticated session. + +### Implementing sign-in card view with automatic magic code handling + +To support Microsoft Entra ID (Azure Active Directory v2) authentication with magic code automatic handling, you need to implement the Sign-In card as follows: + +```CSharp +// SignIn Card View (Sign-In Card View) +CardViewResponse signInCardViewResponse = new CardViewResponse(); +signInCardViewResponse.AceData = aceData; +signInCardViewResponse.CardViewParameters = CardViewParameters.SignInCardViewParameters( + new CardBarComponent() + { + Id = "SignInCardView", + }, + new CardTextComponent() + { + Text = "User's Sign in!" + }, + new CardTextComponent() + { + Text = "Please, sign in ..." + }, + new CardButtonComponent() + { + Id = "CompleteSignInButton", + Title = "Complete sign in", + Action = new QuickViewAction() + { + Parameters = new QuickViewActionParameters() + { + View = SignInQuickView_ID + } + } + } +); +signInCardViewResponse.CardViewParameters.CardViewType = "signIn"; +signInCardViewResponse.ViewId = SignInCardView_ID; + +cardViews.TryAdd(signInCardViewResponse.ViewId, signInCardViewResponse); +``` + +You need to use the `SignInCardViewParameters` factory method to create a Sign In Card View, which is designed to implement the sign-in logic. The Sign In Card View looks like a Primary Text Card View, in fact, there are text components both in the header and in the body. However, the footer requires you to provide a button to implement extra logic to handle the completion of the sign-in flow. By default, every Sign In Card View has a Sign in button that is provided out of the box in the Card View template. The extra button in the Card View is for the "Complete sign-in" logic. You can find further details in the flow diagram illustrated in [Understanding the Bot Powered ACE authentication flow](./AuthN-and-AuthZ-in-Bot-Powered-ACEs.md#understanding-the-bot-powered-ace-authentication-options). + +In the sample implementation, when the user selects the **Complete sign in** button a custom Quick View is rendered to collect the magic code and process it to acquire the access token. + +One last important thing to notice is the setting of the `CardViewType` property for the Card View object to the value `signIn`, which is the value required to configure the automatic magic code handling without single sign-on, in case you use Microsoft Entra ID. + +### Implementing other card views + +In the following code excerpt you can see the SignedOut card implementation, which defines a card that confirms to the user that the sign-out was completed: + +```CSharp +// Signed out Card View (Basic Card View) +CardViewResponse signedOutCardViewResponse = new CardViewResponse(); +signedOutCardViewResponse.AceData = aceData; +signedOutCardViewResponse.CardViewParameters = CardViewParameters.BasicCardViewParameters( + new CardBarComponent() + { + Id = "SignedOutCardView", + }, + new CardTextComponent() + { + Text = "You are now signed out!" + }, + new List() + { + new CardButtonComponent() + { + Id = "OkSignedOut", + Title = "Ok", + Action = new SubmitAction() + { + Parameters = new Dictionary() + { + { "viewToNavigateTo", HomeCardView_ID } + } + } + } + }); +signedOutCardViewResponse.ViewId = SignedOutCardView_ID; + +cardViews.TryAdd(signedOutCardViewResponse.ViewId, signedOutCardViewResponse); +``` + +The Signed out Card View is a basic card view with a simple text message in the body and a button to go back to the home Card View. + +In the sample solution, there's also an Error Card View, which for the sake of simplicity isn't illustrated in this article but is available in the [reference solution](https://github.com/pnp/viva-dev-bot-powered-aces/tree/main/samples/dotnet/WelcomeUserBotPoweredAce). + +### Implementing magic code handling the quick view + +Here follows the definition of the Quick View used to implement the **Complete sign in** logic. + +```CSharp +// Complete Sign In Quick View +QuickViewResponse signInQuickViewResponse = new QuickViewResponse(); +signInQuickViewResponse.Title = "Sign In"; +signInQuickViewResponse.Template = new AdaptiveCard("1.5"); + +AdaptiveContainer signInContainer = new AdaptiveContainer(); +signInContainer.Separator = true; + +AdaptiveTextBlock signInTitleText = new AdaptiveTextBlock +{ + Text = "Complete Sign In", + Color = AdaptiveTextColor.Dark, + Weight = AdaptiveTextWeight.Bolder, + Size = AdaptiveTextSize.Medium, + Wrap = true, + MaxLines = 1, + Spacing = AdaptiveSpacing.None +}; +signInContainer.Items.Add(signInTitleText); + +AdaptiveTextBlock signInDescriptionText = new AdaptiveTextBlock +{ + Text = "Input the magic code from Microsoft Entra ID to complete sign in.", + Color = AdaptiveTextColor.Dark, + Size = AdaptiveTextSize.Default, + Wrap = true, + MaxLines = 6, + Spacing = AdaptiveSpacing.None +}; +signInContainer.Items.Add(signInDescriptionText); + +AdaptiveNumberInput signInMagicCodeInputField = new AdaptiveNumberInput +{ + Placeholder = "Enter Magic Code", + Id = "magicCode" +}; +signInContainer.Items.Add(signInMagicCodeInputField); + +AdaptiveSubmitAction signInSubmitAction = new AdaptiveSubmitAction +{ + Title = "Submit", + Id = "SubmitMagicCode" +}; +signInQuickViewResponse.Template.Actions.Add(signInSubmitAction); + +signInQuickViewResponse.Template.Body.Add(signInContainer); +signInQuickViewResponse.ViewId = SignInQuickView_ID; + +quickViews.TryAdd(signInQuickViewResponse.ViewId, signInQuickViewResponse); +``` + +It's a Quick View with a number input field with ID **magicCode** and a submit button with ID **SubmitMagicCode**. The following picture shows the Quick View in action. + +![The UI of the sample Bot Powered ACE in the Viva Connections desktop experience when the user selects the "Complete sign in" button. There is a text field to provide the magic code value and there is a button to submit the magic code.](./images/Bot-Powered-ACE-Welcome-Complete-Sign-In.png) + +> [!IMPORTANT] +> Being the "Complete sign in" user experience developed by you, it is completely customizable. So the layout, text messages, buttons, etc. are up to you and you can freely design them. + +## Handling the magic code + +Once you have the magic code, either automatically with Microsoft Entra ID or manually with any other Identity Provider, you need to process its value to acquire an actual access token. Depending on the sign-in flow, you can handle the magic code while rendering a Card View in the `OnSharePointTaskGetCardViewAsync` method, or the `OnSharePointTaskHandleActionAsync` method when the user submits the magic code via the **Complete sign in** manual experience. + +### Automatically handling the magic code + +In the following code excerpt, you can see how to process the magic code automatically submitted by the Microsoft Entra ID experience, when rendering a card view. + +```CSharp +protected async override Task OnSharePointTaskGetCardViewAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) +{ + JObject aceData = aceRequest.Data as JObject; + string magicCode = null; + if (aceData["magicCode"] != null) + { + magicCode = aceData["magicCode"].ToString(); + } + // Check to see if the user has already signed in + var (displayName, upn) = await GetAuthenticatedUser(magicCode, turnContext, cancellationToken); + if (displayName != null && upn != null) + { + var homeCardView = cardViews[HomeCardView_ID]; + if (homeCardView != null) + { + ((homeCardView.CardViewParameters.Header.ToList())[0] as CardTextComponent).Text = $"Welcome {displayName}!"; + ((homeCardView.CardViewParameters.Body.ToList())[0] as CardTextComponent).Text = $"Your UPN is: {upn}"; + return homeCardView; + } + } + else + { + var signInCardView = cardViews[SignInCardView_ID]; + if (signInCardView != null) + { + var signInResource = await GetSignInResource(turnContext, cancellationToken); + var signInLink = signInResource != null ? new Uri(signInResource.SignInLink) : new Uri(string.Empty); + + signInCardView.AceData.Properties = Newtonsoft.Json.Linq.JObject.FromObject(new Dictionary() { + { "uri", signInLink }, + { "connectionName", this._connectionName } + }); + return signInCardView; + } + } + + return cardViews[ErrorCardView_ID]; +} +``` + +You can retrieve the value of the magic code from the object of type `AceRequest` provided to the `OnSharePointTaskGetCardViewAsync` method. The magic code value is a dictionary value of the property of type `JObject` with name `Data`. Once you have the magic code value, you need to provide it to an infrastructural service of type `UserTokenClient`, which is available via dependency injection in the Bot logic. + +To properly handle the user token, which is a JWT (JSON Web Token) object, you can use the `System.IdentityModel.Tokens.Jwt` NuGet package. As such, add the package to your project and implement the following infrastructural methods. + +Here follows the internal logic that you should rely on to manage the access token and the current user's identity retrieval. + +```CSharp +private async Task<(string displayName, string upn)> GetAuthenticatedUser(string magicCode, ITurnContext turnContext, CancellationToken cancellationToken) +{ + string displayName = null; + string upn = null; + + try + { + var response = await GetUserToken(magicCode, turnContext, cancellationToken).ConfigureAwait(false); + if (response != null && !string.IsNullOrEmpty(response.Token)) + { + var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(response.Token); + displayName = token.Claims.FirstOrDefault(c => c.Type == System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames.Name)?.Value; + upn = token.Claims.FirstOrDefault(c => c.Type == "upn")?.Value; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error while trying to retrieve current user's displayName and UPN!"); + } + + return (displayName, upn); +} + +private async Task GetUserToken(string magicCode, ITurnContext turnContext, CancellationToken cancellationToken) +{ + // Get the UserTokenClient service instance + var userTokenClient = turnContext.TurnState.Get(); + + // Assuming the bot is already configured for SSO and the user has been authenticated + return await userTokenClient.GetUserTokenAsync( + turnContext.Activity.From.Id, + _connectionName, // The name of your Azure AD connection + turnContext.Activity.ChannelId, + magicCode, + cancellationToken).ConfigureAwait(false); +} +``` + +The `GetAuthenticatedUser` method accepts the magic code value and the Bot `TurnContext` instance. Internally, it uses the `GetUserToken` method to retrieve the actual access token value and then uses the `JwtSecurityToken` class of `System.IdentityModel.Tokens.Jwt` to decode the token and get access to the user's display name and user principal name. + +> [!NOTE] +> Using the same technique and reading the **scp** claim (Scope) or any other claim of your interest, you can eventually implement custom authorization logic for your Bot Powered ACE. + +The `GetUserToken` method retrieves an instance of the `UserTokenClient` service and makes the actual request for the token using the `GetUserTokenAsync`, which accepts the following input arguments: + +* the ID of the sender (From) for the current Activity of the Bot instance +* the name of the OAuth connection defined in the configuration of the Azure Bot +* the ID of the Channel for the Bot instance +* the magic code value, which can be null if there's an already cached user's token +* the cancellation token for the asynchronous request + +The result of the `GetUserTokenAsync` method is an instance of the `TokenResponse` type that includes a `Token` property with the actual value of the access token. +Once you have the access token and you extracted the display name and the user principal name, you can render them in the welcome Card View. + +In case there's no magic code value in the request object there could be two different scenarios: + +* the user is already signed in: the backend infrastructure of the Azure Bot automatically provides a token for the current user, without the need to provide the magic code +* the user isn't yet signed in: the Bot Powered ACE needs to render the Sign In Card View to invite the user to sign in + +In the latter scenario, the Sign In Card View needs to be configured with a couple of properties to instruct the Bot infrastructure about how to handle the sign-in flow. Specifically, you need to provide two custom properties through the `AceData.Properties` of the card. + +```CSharp +var signInResource = await GetSignInResource(turnContext, cancellationToken); +var signInLink = signInResource != null ? new Uri(signInResource.SignInLink) : new Uri(string.Empty); + +signInCardView.AceData.Properties = Newtonsoft.Json.Linq.JObject.FromObject(new Dictionary() { + { "uri", signInLink }, + { "connectionName", this._connectionName } +}); +return signInCardView; +``` + +The **uri** property represents the URL to trigger the sign-in flow and needs to be retrieved using the `UserTokenClient` service. Here you can see how to do that with the custom method `GetSignInResource`. + +```CSharp +private async Task GetSignInResource(ITurnContext turnContext, CancellationToken cancellationToken) +{ + // Get the UserTokenClient service instance + var userTokenClient = turnContext.TurnState.Get(); + + // Retrieve the Sign In Resource from the UserTokenClient service instance + var signInResource = await userTokenClient.GetSignInResourceAsync(_connectionName, (Microsoft.Bot.Schema.Activity)turnContext.Activity, null, cancellationToken).ConfigureAwait(false); + return signInResource; +} +``` + +While the **connectionName** property contains the name of the OAuth connection configured for the Azure Bot. + +### Manually handling the magic code with the "Complete sign in" custom logic + +In case you need to manually handle the magic code, you need to implement some custom logic in the `OnSharePointTaskHandleActionAsync` method. Here is a code excerpt of the method: + +```CSharp +protected async override Task OnSharePointTaskHandleActionAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) +{ + if (turnContext != null) + { + if (cancellationToken.IsCancellationRequested) + { + cancellationToken.ThrowIfCancellationRequested(); + } + } + JObject actionParameters = aceRequest.Data as JObject; + + if (actionParameters != null) + { + var actionId = actionParameters["id"].ToString(); + if (actionId == "SubmitMagicCode") + { + var magicCode = actionParameters["data"]["magicCode"].ToString(); + var (displayName, upn) = await GetAuthenticatedUser(magicCode, turnContext, cancellationToken); + + var homeCardView = cardViews[HomeCardView_ID]; + if (homeCardView != null && displayName != null && upn != null) + { + ((homeCardView.CardViewParameters.Header.ToList())[0] as CardTextComponent).Text = $"Welcome {displayName}!"; + ((homeCardView.CardViewParameters.Body.ToList())[0] as CardTextComponent).Text = $"Your UPN is: {upn}"; + + return new CardViewHandleActionResponse + { + RenderArguments = homeCardView + }; + } + } + else if (actionId == "SignOut") + { + await SignOutUser(turnContext, cancellationToken); + + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[SignedOutCardView_ID] + }; + } + else if (actionId == "OkSignedOut") + { + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[SignInCardView_ID] + }; + } + else if (actionId == "OkError") + { + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[HomeCardView_ID] + }; + } + } + + return new CardViewHandleActionResponse + { + RenderArguments = cardViews[ErrorCardView_ID] + }; +} +``` + +The key part of the method is still the processing of the object of type `AceRequest`. If the user selects the **Submit** button in the "Complete sign in" Quick View, you can extract the magic code value from the `Data` property of the request and then you can go through the same process as before, invoking the `GetAuthenticatedUser` method. + +In the code excerpt, you can also see how the sign-out is handled, invoking the custom `SignOutUser` method, which is illustrated in the following code excerpt. + +```CSharp +private async Task SignOutUser(ITurnContext turnContext, CancellationToken cancellationToken) +{ + // Get the UserTokenClient service instance + var userTokenClient = turnContext.TurnState.Get(); + + // Sign out the current user + await userTokenClient.SignOutUserAsync( + turnContext.Activity.From.Id, + _connectionName, // The name of your Azure AD connection + turnContext.Activity.ChannelId, + cancellationToken).ConfigureAwait(false); +} +``` + +The method uses the `UserTokenClient` service to invoke the `SignOutUserAsync` method. + +## Configuring the manifest + +The implementation of the Bot Powered ACE is now complete and you just need to create a manifest file and deploy it into the target tenant SharePoint Online App Catalog. You can find step-by-step instructions about how to do that in the section [Define the **manifest.json** file for the solution](./Building-Your-First-Bot-Powered-ACE.md#define-the-manifestjson-file-for-the-solution) section of the reference article [Building your first Bot Powered Adaptive Card Extension](./Building-Your-First-Bot-Powered-ACE.md). + +To properly support authentication, you need to add a `webApplicationInfo` section to the **manifest.json** file, like illustrated in the following excerpt. + +```JSON + "webApplicationInfo": { + "id": "", + "resource": "api://.ngrok.io/" + }, +``` + +The `id` property is the actual Client ID of the Microsoft App behind the scenes of your Azure Bot. The `resource` property is the unique URI that you configured for that Microsoft App. + +You're now ready to package the solution, deploy it on the SharePoint Online App Catalog, and play with it. You can follow the instructions provided in section ["Run and test the solution](./Building-Your-First-Bot-Powered-ACE.md#run-and-test-the-solution) of the reference article [Building your first Bot Powered Adaptive Card Extension](./Building-Your-First-Bot-Powered-ACE.md). diff --git a/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs.md b/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs.md new file mode 100644 index 000000000..e1073ca64 --- /dev/null +++ b/docs/spfx/viva/bot-powered/AuthN-and-AuthZ-in-Bot-Powered-ACEs.md @@ -0,0 +1,55 @@ +--- +title: Authentication and Authorization in Bot Powered Adaptive Card Extensions +description: Learn how to secure Bot Powered ACEs for Microsoft Viva Connections. +ms.date: 11/06/2024 +ms.localizationpriority: high +--- +# Authentication and Authorization in Bot Powered Adaptive Card Extensions + +Bot Powered Adaptive Card Extensions (ACEs) often require a security context. In fact, whenever you need to identify the consumer tenant and/or the user consuming your ACE you need to rely on Authentication. Whenever you need to enable functionalities based on the current user's profile, you need to rely on Authorization. +Being the Bot Powered ACEs based on the Azure Bot technology, also Authentication and Authorization use the same security architecture of regular Azure Bots. +To secure a Bot Powered ACE, there are some configuration steps that you need to accomplish. You also need to write some code in your implementation to handle the sign-in and sign out flows. In this article, you learn about the architecture of Bot Powered ACEs from a security point of view. + +## Understanding the Bot Powered ACE authentication options + +Before digging into the actual development of the authentication logic in the Bot Powered ACEs, it's important to understand how the authentication flow works. + +In fact, you can support different scenarios: +- [Microsoft Entra ID Single Sign-on (SSO)](#microsoft-entra-id-single-sign-on-sso) +- [Other OAuth Identity Providers with Bot Framework magic code](#other-oauth-identity-providers-with-bot-framework-magic-code) + +The following diagram explains how the authentication flow works. + +![The flow diagram explaining how the authentication process works in Bot Powered ACEs depending on the different types of OAuth connections configured.](./images/Bot-Powered-ACEs-SignIn-Flow-Diagram.png) + +In the following sections, you can find additional information about each of the available options. + +### Microsoft Entra ID Single Sign-on (SSO) + +If you choose to support Microsoft Entra ID (previously known as Azure Active Directory v2) single sign-on, the user's authentication is automatic and transparent to the user. Your code automatically gets the security context and you can easily access information about who the current user is. You can also retrieve an access token to consume Microsoft Graph or any other third party APIs on behalf of the current user. Indeed, in order to get an access token the Microsoft App behind the scenes of your Bot Powered ACE needs to be granted permissions accordingly. + +To support Microsoft Entra ID SSO, there are some configuration requirements that you need to accomplish and you need to provide specific logic in the code of the Bot Powered ACE. You can find detailed explanation of this scenario reading the article ["Building Bot Powered Adaptive Card Extensions with Microsoft Entra ID and Single Sign-on."](./AuthN-and-AuthZ-in-Bot-Powered-ACEs-Entra.md) + +If your code has single sign-on logic but the application isn't set up correctly in Microsoft Azure, the Bot Powered ACE doesn't show up. If that is the case, users see an error when adding the Bot Powered ACE to the dashboard. + +### Other OAuth Identity Providers with Bot Framework magic code + +Another option that you have is to rely on external OAuth Identity Providers, which can still be Microsoft Entra ID or any other third party Identity Provider. For example, the third party Identity Provider can be: GitHub, Facebook, Live, Google, etc. If that is the case, the authentication requires you to manually handle a magic code value provided by the user during the authentication phase, based on how the bot framework authentication works. + +In this scenario, when the user signs in there's a popup dialog (both on desktop and on mobile) taking care of the actual authentication. The dialog allows the user to authenticate against the target Identity Provider. Then, the bot framework returns a magic code (a sequence of numbers), which you can then use in your own Bot code to acquire a token through an OAuth connection. The user needs to copy the value of the magic code and provide it manually to your ACE. It's up to you to provide a custom button to do so. When the user selects the button, you can show a custom UI and collect the magic code in the logic. Once you have the magic code, you can acquire an actual access token. At the time of this writing, you need to manually define the UI to collect the magic code value. In fact, there isn't any native component, Card View template, or Quick View template to do that. + +When the Identity Provider is Microsoft Entra ID and the user is on a desktop environment, the flow is handled automatically. In this scenario, you just need to use the magic code in your custom logic to get a token. However, there are situations where the automatic handling of the magic code isn't supported. For example, on smartphone and tablet devices, or when the browser doesn't support cookies, etc. there's no automatic handling of the magic code. In the scenarios where there isn't automatic authentication for Microsoft Entra ID, the user still needs to copy the value of the magic code and provide it manually to your ACE. + +You can find implementation details about this scenario reading the article ["Building Bot Powered Adaptive Card Extensions with Magic Code authentication."](./AuthN-and-AuthZ-in-Bot-Powered-ACEs-Magic-Code.md) + +## Important things to know + +There are some architectural things that are worth being aware of, when developing custom Bot Powered ACEs with authentication and authorization: + +1. If you rely on single sign-on for all of your Bot Powered ACEs, all of the ACEs automatically authenticate the user when opening the dashboard both on desktop and mobile devices (smartphone or tablet). +1. If you have multiple instances of the same card in a Viva Connections Dashboard, when a user signs in through one of those instances, the security context is shared across all of the instances. Moreover, the user is authenticated in all of the devices and all of the experiences (for example desktop and mobile). However, you need to refresh the page to let the other instances know that there's a security context. In fact, Bot Powered ACEs are a **pull** technology and currently isn't possible to notify card instances about changes of the security context. +1. For the same reason as before, also when a user signs out, all the instances of the same card loose the security context, but you need to refresh the page to make the other instances aware of the new security context. +1. When you have Microsoft Entra ID authentication with single sign-on configured for an ACE, it isn't possible to sign out the current user, because whenever the user signs out then the automatic authentication logic signs the user in again. +1. If you have different Bot Powered ACEs in the same dashboard with support for authentication but without single sign-on, users need to sign in and sign out individually on each of them. In fact, the security context is shared only across ACEs of the same type. +1. As already stated in the article, the experience to collect the magic code value is mandatory, when you rely on magic code, and is required for Microsoft Entra ID authentication, too. In fact, if the user's browser blocks cookies, the end user needs to manually copy the magic code value in the clipboard and provide it to the ACE custom logic. +1. When you rely on single sign-on, on the contrary, you don't need to implement any experience to collect the magic code value. diff --git a/docs/spfx/viva/bot-powered/Building-Your-First-Bot-Powered-ACE-TTK-TS.md b/docs/spfx/viva/bot-powered/Building-Your-First-Bot-Powered-ACE-TTK-TS.md new file mode 100644 index 000000000..2e5b3fcd6 --- /dev/null +++ b/docs/spfx/viva/bot-powered/Building-Your-First-Bot-Powered-ACE-TTK-TS.md @@ -0,0 +1,543 @@ +--- +title: Building your first Bot Powered Adaptive Card Extension with Microsoft Teams Toolkit and TypeScript +description: Learn how to build your first Bot Powered Adaptive Card Extension (ACE) using the Bot Framework with Microsoft Teams Toolkit and TypeScript. +ms.date: 11/15/2024 +ms.localizationpriority: high +--- +# Building your first Bot Powered Adaptive Card Extension with Microsoft Teams Toolkit and TypeScript + +Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections enable extending the Microsoft Viva Connections Dashboard using the Bot development model. + +From a development point of view, a Bot Powered ACE behaves like a regular client-side ACE built with SharePoint Framework (SPFx). As such, you can render Card Views, Quick Views, you can provide properties configurable via a Property Pane, and you can implement specific behaviors to handle actions in the user interface of the ACE. You can learn more about the basics of client-side Adaptive Card Extensions for Microsoft Viva Connections by reading the tutorial [Build your first SharePoint Adaptive Card Extension](../get-started/build-first-sharepoint-adaptive-card-extension.md). + +You can build Bot Powered ACEs either using C# and .NET or using TypeScript and Node.js. In this tutorial, you learn how to build a basic Bot Powered ACE using the Microsoft Teams Toolkit in Visual Studio Code and TypeScript, with a step-by-step approach. + +You can learn more about the architecture of the Bot Powered ACEs by reading the article [Understanding Bot Powered Adaptive Card Extensions](./Understanding-Bot-Powered-ACEs.md). + +## Developing a Bot Powered ACE with Microsoft Teams Toolkit + +In this tutorial, you're going to build a basic Bot Powered ACE to collect the user's feedback via a Card View with a textbox and a submission button. In the following picture, you can see how the Adaptive Card Extension looks like in the Viva Connections desktop experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections desktop experience. There is a Card View to collect user's feedback and a submit button. There is also the same Card View with the textbox filled in with a sample value "I like Bot Powered ACEs". Then, there is a Card View confirming the collection of the feedback. Lastly, there is a Quick View with a generic message for the user.](./images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop.png) + +In the following picture, you can see how the Adaptive Card Extension looks like in the Viva Connections mobile experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections mobile experience. There is a Card View to collect user's feedback and a submit button. There is also the same Card View with the textbox filled in with a sample value "I like Bot ...". Then, there is a Card View confirming the collection of the feedback. Lastly, there is a Quick View with a generic message for the user.](./images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile.png) + +From a developer point of view, you build the ACE once and you benefit from it in both desktop and mobile experiences. + +### Prerequirements + +First of all, in order to develop a Bot Powered ACE with Microsoft Teams Toolkit and TypeScript, you need to have the following tools and packages installed on your development machine: + +* Microsoft Visual Studio Code +* Microsoft Teams Toolkit version 5.10.0 or higher + +You also need to have an active and valid Microsoft Azure subscription to host the Azure Bot. + +## Creating the Bot solution in Visual Studio Code with Microsoft Teams Toolkit + +Start Visual Studio Code and select the Microsoft Teams Toolkit icon on the command bar. Select the **Create a New App** button to start scaffolding the solution, as illustrated in the following screenshot: + +![The UI of Microsoft Visual Code with the Microsoft Teams Toolkit activated. On the left side there is the "Create a New App" button highlighted](./images/Visual-Studio-Code-TTK-New-Project-01.png). + +Select the option **Bot** and then **Basic Bot**, to create a basic scaffolding of a Bot with the Bot Framework for JavaScript. + +![The UI of Microsoft Visual Code with the Microsoft Teams Toolkit activated, when creating a new Bot. There is a list of project templates with the 'Bot' option highlighted](./images/Visual-Studio-Code-TTK-New-Project-02.png) + +Select to use **TypeScript** as the language for the Bot and select a target folder to store the source code of the solution. Provide a name for the solution, for example, **collect-feedback-ts**. The new solution gets scaffolded and Visual Studio Code opens a new window targeting the project folder. In case Visual Studio asks you to trust the folder, select the option **Yes, I trust the authors**. + +![The UI of Microsoft Visual Code with the new project scaffolded by the Microsoft Teams Toolkit and a dialog prompt asking the user to trust the source folder of the solution](./images/Visual-Studio-Code-TTK-New-Project-03.png) + +It's important to understand the structure of the project created by the Microsoft Teams Toolkit. Here are the main elements: + +- **appPackage** folder: contains the **manifest.json** file and a couple of icons for the Microsoft 365 application. +- **env** folder: contains the configuration files for all the environments supported by the solution. Using the Microsoft Teams Toolkit you can create and manage the environments. +- **infra** folder: contains a set of Bicep files used to provision on Microsoft Azure the resources and services used to host the actual solution for the Bot. +- **index.ts**: the main entry point of the Bot solution. Here, the Bot gets created and the HTTP server listens for API messages targeting the Bot. +- **teamsBot.ts**: implements the actual logic of the Bot. + +![The outline of the project in Visual Studio Code. There is a folder 'AppPackage' with the Microsoft 365 application package files. There is a folder 'env' with all the environment setting files. There is a folder 'infra' with the Bicep files to provision the resources needed to host and run the solution. There is the root folder of the solution with all the actual source code and setting files](./images/Visual-Studio-Code-TTK-New-Project-Outline.png). + +First of all, rename the **teamsBot.ts** file into **collectFeedbackBot.ts**. Accept to update the imports in code, and to rename the class `TeamsBot` into `CollectFeedbackBot` using the "Rename Symbol" functionality of Visual Studio Code. + +Then, upgrade the package with name **botbuilder** to version 4.23.1 or higher. You can use the npm command line tool using the following command: + +```console +npm i botbuilder --save +``` + +Install also all the other packages needed by the solution using the following command: + +```console +npm i +``` + +Once all the packages are installed, you can proceed with the actual implementation of the Bot Powered ACE. + +## Update the Bot code to support Bot Powered ACEs + +Open the bot source code file (**collectFeedbackBot.ts**) and replace the base class `TeamsActivityHandler` with the base class `SharePointActivityHandler`. Empty the content of the constructor and remove any other code. Add a set of overrides for all the methods with name starting with `onSharePointTask*` and so far leave them with the default implementation. + +Update the import of types accordingly to the new methods declarations, at the top of the source code file. + +Here follows the resulting class implementation. + +```TypeScript +import { + SharePointActivityHandler, TurnContext, AceRequest, AceData, + CardViewResponse, QuickViewResponse, HandleActionResponse, CardViewHandleActionResponse, + GetPropertyPaneConfigurationResponse, SetPropertyPaneConfigurationResponse, + ImageCardView +} from "botbuilder"; +import * as AdaptiveCards from "adaptivecards"; + +export class CollectFeedbackBot extends SharePointActivityHandler { + + constructor() { + super(); + } + + protected override onSharePointTaskGetCardViewAsync(_context: TurnContext, _aceRequest: AceRequest): Promise { + return Promise.resolve(null); + } + + protected override onSharePointTaskGetQuickViewAsync(_context: TurnContext, _aceRequest: AceRequest): Promise { + return Promise.resolve(null); + } + + protected override onSharePointTaskGetPropertyPaneConfigurationAsync(_context: TurnContext, _aceRequest: AceRequest): Promise + { + return Promise.resolve(null); + } + + protected override onSharePointTaskSetPropertyPaneConfigurationAsync(_context: TurnContext, _aceRequest: AceRequest): Promise + { + return Promise.resolve(null); + } + + protected override onSharePointTaskHandleActionAsync(_context: TurnContext, _aceRequest: AceRequest): Promise { + return Promise.resolve(null); + } +} +``` + +Here follows a brief explanation of the overridable methods: + +* `onSharePointTaskGetCardViewAsync`: handles the rendering of a Card View, returning a `CardViewResponse` instance. +* `onSharePointTaskGetQuickViewAsync`: handles the rendering of a Quick View, returning a `QuickViewResponse` instance. +* `onSharePointTaskGetPropertyPaneConfigurationAsync`: allows rendering the Property Pane of the ACE, returning a `GetPropertyPaneConfigurationResponse` instance. +* `onSharePointTaskSetPropertyPaneConfigurationAsync`: allows saving the settings configured using the Property Pane of the ACE, returning a `HandleActionResponse` instance. +* `onSharePointTaskHandleActionAsync`: handles a custom action in the ACE like the select on a button in a Card View or any custom action in the UI of a Quick View, returning a `HandleActionResponse` instance. + +> [!NOTE] +> You can dig into the details of how Bot Powered ACEs work by reading the article [Understanding Bot Powered Adaptive Card Extensions](./Understanding-Bot-Powered-ACEs.md). + +To implement the Collect Feedback ACE, you can only focus on `onSharePointTaskGetCardViewAsync` and `onSharePointTaskGetQuickViewAsync` to render the Card Views and the Quick View, as well as on the `onSharePointTaskHandleActionAsync` to handle the actual submission of the feedback. So far, you can remove the two methods for handling the property pane, which is covered in another article. You can now also remove the import of types `GetPropertyPaneConfigurationResponse` and `SetPropertyPaneConfigurationResponse`. + +Every Bot Powered ACE has a unique ID, which is a string that identifies uniquely the ACE instance in the Viva Connections Dashboard. For that unique ID you can, for example, use a `Guid` value converted into a string or a unique string value. You can define such a value as a private readonly string variable in the Bot class definition. + +Add to the Bot class definition also a few strings to define the IDs of the card views rendered by the ACE and a dictionary of items of type `CardViewResponse` to hold all the different card view definitions. Here follows the updated definition of the **collectFeedbackBot.ts** class. + +```TypeScript +export class CollectFeedbackBot extends SharePointActivityHandler { + + private readonly _botId: string = 'CollectFeedbackBot'; + private _cardViews: { [key: string]: CardViewResponse } = {}; + + private COLLECT_FEEDBACK_CARD_VIEW_ID: string = 'GET_FEEDBACK_CARD_VIEW'; + private OK_FEEDBACK_CARD_VIEW_ID: string = 'OK_FEEDBACK_CARD_VIEW'; + private SHOW_FEEDBACK_QUICK_VIEW_ID: string = 'FEEDBACK_QUICK_VIEW'; + + // The remainder part of the class is omitted for the sake of simplicity... +} +``` + +### Rendering Card Views + +Every `CardViewResponse` instance is made of a property named `aceData` that defines some aesthetic settings like the size of the card, its icon, the title, and the description. It also defines the unique ID of the card and a JSON object to represent some custom `properties`, if there's need. Every `CardViewResponse` provides a `viewId` string property, which declares a unique ID to identify the specific Card View instance for the ACE and which is mandatory to assign a value to. There's also an event with the name `onCardSelection`, which can be used to handle custom actions when the user selects the Card View. + +Moreover, the `CardViewResponse` instance provides a property named `cardViewParameters` that defines the actual outline of the Card View. The content of the `cardViewParameters` property defines the structure of the components model used to render the card. The **botbuilder** package defines a set of functions to define different flavors of Card Views: + +* `BasicCardView`: factory method to create a Basic Text Card View. +* `PrimaryTextCardView`: factory method to create a Primary Text Card View. +* `ImageCardView`: factory method to create an Image Card View. +* `TextInputCardView`: factory method to create a Text Input Card View. +* `SearchCardView`: factory method to create a Search Card View. +* `SignInCardView`: factory method to create a Sign-in Card View. + +For instance, in order to create the Card View to collect user's feedback you can use the `TextInputCardView` factory method and define the components that make up the Card View. Furthermore, the Card View to confirm that the feedback was collected can be created using the `ImageCardView` method. It's a common habit to define the Card Views, and the Quick Views as well, in the constructor of the Bot, storing them in a static dictionary, where the item key is the `viewId` of the card. Then, based on the requested Card View, you can return the corresponding item of the dictionary as the result of the `onSharePointTaskGetCardViewAsync` method. + +Here follows a sample implementation of the Bot constructor, defining all the card views needed by the actual implementation. + +```TypeScript +constructor() { + super(); + + // Prepare the ACE data for all the card views and quick views. + const aceData: AceData = { + id: this._botId, + title: 'Your feedback matters!', + description: 'Please provide your feedback below.', + cardSize: 'Large', + iconProperty: 'Feedback', + properties: {}, + dataVersion: '1.0', + }; + + // Collect Feedback Card View (Input Text Card View manual) + const feedbackCardView: CardViewResponse = { + aceData: aceData, + cardViewParameters: { + cardViewType: 'textInput', + cardBar: [ + { + componentName: 'cardBar', + title: 'Feedback' + } + ], + header: [ + { + componentName: 'text', + text: 'Please provide your feedback below.' + } + ], + body: [ + { + componentName: 'textInput', + id: 'feedbackValue', + placeholder: 'Your feedback ...' + } + ], + footer: [ + { + componentName: 'cardButton', + id: 'SendFeedback', + title: 'Submit', + action: { + type: 'Submit', + parameters: { + viewToNavigateTo: this.OK_FEEDBACK_CARD_VIEW_ID + } + } + } + ], + image: { + url: `https://${process.env.BOT_DOMAIN}/assets/Collect-Feedback.png`, + altText: 'Feedback' + } + }, + viewId: this.COLLECT_FEEDBACK_CARD_VIEW_ID, + onCardSelection: { + type: 'QuickView', + parameters: { + view: this.SHOW_FEEDBACK_QUICK_VIEW_ID + } + } + }; + this._cardViews[this.COLLECT_FEEDBACK_CARD_VIEW_ID] = feedbackCardView; + + // OK Feedback Card View (Image Card View) + const okFeedbackCardViewResponse: CardViewResponse = { + aceData: aceData, + cardViewParameters: ImageCardView( + { + componentName: 'cardBar', + title: 'Feedback Collected' + }, + { + componentName: 'text', + text: 'Here is your feedback \'\' collected on \'\'' + }, + { + url: `https://${process.env.BOT_DOMAIN}/assets/Ok-Feedback.png`, + altText: "Feedback collected" + }, + [ + { + componentName: 'cardButton', + title: 'Ok', + id: 'OkButton', + action: { + type: 'Submit', + parameters: { + viewToNavigateTo: this.COLLECT_FEEDBACK_CARD_VIEW_ID + } + } + } + ] + ), + viewId: this.COLLECT_FEEDBACK_CARD_VIEW_ID, + onCardSelection: { + type: 'QuickView', + parameters: { + view: this.SHOW_FEEDBACK_QUICK_VIEW_ID + } + } + }; + this._cardViews[this.OK_FEEDBACK_CARD_VIEW_ID] = okFeedbackCardViewResponse; +} +``` + +In the following picture, you can see a diagram that explains the structure of a component-based Card View rendered in "Large" format. + +![A diagram with the structure of a component based Card View in "Large" format. The shape of the Card View is divided into two main sections, the left one is made of a CardBarComponent, a CardTextComponent, a component that varies depending on the kind of Card View template selected, and a CardViewActionsFooterParameters that can be made of one, two, or zero instances of CardButtonComponent, to provide zero, one, or two buttons. On the right section there can be an instance of CardImage to render an image, if any, depending on the kind of Card View template selected.](./images/ACE-Component-Based-Structure-TS.png) + +A component-based Card View in "Large" format does have a shape divided into two main sections, the left one is made of a `CardBarComponent`, a `CardTextComponent`, a component that varies depending on the kind of Card View template selected, and a `CardViewActionsFooterParameters` that is made of a list of `BaseCardComponent` objects to provide zero, one, or two buttons. On the right section, there can be an instance of `CardImage` to render an image, if any, depending on the kind of Card View template selected + +For example, the `TextInputCardViewParameters` instance is made of the following components: + +* `CardBarComponent`: defines the top bar of the Card View, including the icon and the title. +* `CardTextComponent`: defines a text component with some informative text for the user. +* `CardTextInputComponent`: defines the input text field to collect feedback. Here, the `Id` property is fundamental because you need it later to retrieve the value of the textbox. +* `CardViewActionsFooterParameters`: defines a list of zero, one, or two action buttons. Each action button does have an `Id` property that is fundamental to identify the button pressed by the user. A button can also have a set of custom properties, which are provided to the Bot upon submission of the form. +* `CardImage`: defines an image that is rendered in the right side of the Card View. + +In the code excerpt, the images used to render the Card Views are downloaded from the website hosted in the Bot project. To do so, create a new folder named **assets** in the root folder of the solution. In that folder, you should upload the image files that you find in the **Media** folder that you can find in the [samples folder of the reference GitHub repository](https://github.com/SharePoint/sp-dev-docs/tree/main/assets/bot-powered/Media). Moreover, to enable the Bot serving images and not only the API messages defined by the Bot Framework, you need to modify the **index.ts** file adding it at the end of the following excerpt. + +```TypeScript +// Listen for assets requests +server.get("/assets/*", restify.plugins.serveStatic({ directory: "../" })); +``` + +### Serving Card Views requests + +To serve the card views, you need to implement the `onSharePointTaskGetCardViewAsync` method so that it returns the instance of the card view to collect feedback that you created in the constructor. Here follows the method implementation. + +```TypeScript +protected override onSharePointTaskGetCardViewAsync(_context: TurnContext, _aceRequest: AceRequest): Promise { + return Promise.resolve(this._cardViews[this.COLLECT_FEEDBACK_CARD_VIEW_ID]); +} +``` + +### Handling user's tasks and actions + +When the user selects the submit action in a Card View, the `onSharePointTaskHandleActionAsync` method is triggered and you can handle the submission event. In the following code excerpt, you can see how the ACE collects the feedback submission. + +```TypeScript +protected override onSharePointTaskHandleActionAsync(_context: TurnContext, _aceRequest: AceRequest): Promise { + + const requestData = _aceRequest.data; + + if (requestData.type === 'Submit' && requestData.id === 'SendFeedback') { + + const viewToNavigateTo = requestData.data.viewToNavigateTo; + const feedbackValue = requestData.data.feedbackValue; + const dateTimeFeedback = new Date(); + + const nextCard = this._cardViews[viewToNavigateTo]; + const textContent = `Here is your feedback '${feedbackValue}' collected on '${dateTimeFeedback.toLocaleString()}'`; + nextCard.cardViewParameters.header[0].text = textContent; + + const response: CardViewHandleActionResponse = { + responseType: 'Card', + renderArguments: nextCard, + }; + + return Promise.resolve(response); + + } else if (requestData.type === 'Submit' && requestData.id === 'OkButton') { + + const viewToNavigateTo = requestData.data.viewToNavigateTo; + + const response: CardViewHandleActionResponse = { + responseType: 'Card', + renderArguments: this._cardViews[viewToNavigateTo], + }; + + return Promise.resolve(response); + } +} +``` + +Inside the input argument of type `AceRequest`, there's all the needed information to properly handle the user's action. For example, there's the `data` property that contains a dictionary of properties to understand the type of action and the `Id` of the source component for the action. + +In the code excerpt, when the action type is **Submit** and the `Id` of the action is **SendFeedback**, it means that the user selected the submit button defined in the `TextInputCardViewParameters` instance, which is the one to collect the feedback. The actual value of the feedback is available in the data field with name equal to the `Id` of the textbox defined in the `CardTextInputComponent` component instance. The handling of the feedback is up to you. In the code excerpt, the sample configures an instance of the second Card View defined in the constructor, and then instructs the ACE to render the new Card View via the `CardViewHandleActionResponse` return value. + +### Rendering Quick Views + +While the Card Views are rendered based on a set of predefined component based templates, the Quick Views are rendered based on an Adaptive Card definition. The Adaptive Card can be defined either using a declarative and code-based approach or reading a JSON file with an Adaptive Card definition. + +Here follows a sample implementation of the `onSharePointTaskGetQuickViewAsync` method, rendering a Quick View using a code-based and declarative model. + +```TypeScript +protected override onSharePointTaskGetQuickViewAsync(_context: TurnContext, _aceRequest: AceRequest): Promise { + + // Prepare the AdaptiveCard for the Quick View + const card = new AdaptiveCards.AdaptiveCard(); + card.version = new AdaptiveCards.Version(1, 5); + const cardPayload = { + type: 'AdaptiveCard', + $schema: "http://adaptivecards.io/schemas/adaptive-card.json", + body: [ + { + type: 'TextBlock', + text: 'Thanks for your feedback!', + weight: 'Bolder', + size: 'Large', + wrap: true, + maxLines: 1, + spacing: 'None', + color: 'Dark' + }, + { + type: 'TextBlock', + text: 'We truly appreciate your effort in providing valuable feedback to us. Thanks!', + weight: 'Normal', + size: 'Medium', + wrap: true, + maxLines: 3, + spacing: 'None', + color: 'Dark' + } + ] + }; + card.parse(cardPayload); + + // Add the Feedback QuickViews + const feedbackQuickViewResponse: QuickViewResponse = { + viewId: this.SHOW_FEEDBACK_QUICK_VIEW_ID, + title: 'Your feedback', + template: card, + data: {}, + externalLink: null, + focusParameters: null + }; + + return Promise.resolve(feedbackQuickViewResponse); +} +``` + +The code relies on the `AdaptiveCard` type defined in the `adaptivecards` package and builds the content of the Adaptive Card nesting various blocks of content into a hierarchy of elements. In the code excerpt, the body of the Adaptive Card is made of two `TextBlock` instances. + +## Define the **manifest.json** file for the solution + +Now that the Bot Powered ACE is fully implemented, you need to update the manifest of the Microsoft 365 app to define the ACE. + +Open the **manifest.json** file defined in the **appPackage** folder. Right after the `bots` section, add the following excerpt. + +```JSON +"dashboardCards": [ + { + "id": "${{BOT_ID}}", + "pickerGroupId": "8cd406cc-7a66-42b5-bda5-9576abe7a818", + "displayName": "Collect Feedaback TTK", + "description": "Bot Powered ACE to collect user's feedback", + "icon": { + "officeUIFabricIconName": "Feedback" + }, + "contentSource": { + "sourceType": "bot", + "botConfiguration": { + "botId": "${{BOT_ID}}" + } + }, + "defaultSize": "medium" + } +], +``` + +The `dashboardCards` section defines the actual settings for your Bot Powered ACEs. In particular, through this section you can configure the `id` of the Microsoft App backing your Azure Bot, which is the ID of your Bot, the `displayName` and `description` of the ACE, as well as the `icon` as a Fluent UI Icon, the Bot that handles the requests and that must be configured in the `bots` section of the **manifest.json**, and last but not least the `defaultSize` for your ACE in the Viva Connections Dashboard. + +Then, update the `validDomains` section according to the following excerpt. + +```JSON +"validDomains": [ + "${{BOT_DOMAIN}}" +] +``` + +The setting includes the domain of the bot in the list of valid domains so that any resource published by the Bot web application is trusted by Microsoft 365. + +## Provision, deploy, and publish the solution + +Before being able to run and test the Bot Powered ACE, you need to provision resources in Microsoft Azure, deploy the solution in the Teams Developer Portal, and publish it. + +The Microsoft Teams Toolkit takes care of provisioning, deploying, and publishing the Bot solution for you. + +You need to go through the following stages: + +- **Provision:** creates an app in Microsoft Entra ID, provisions a Web App in Microsoft Azure, and provisions the Azure Bot. Validates and packages the **manifest.json** file and the icons into a ZIP package and uploads it into the Teams Developer Portal. +- **Deploy:** installs all the npm dependencies, builds the solution, and deploys the solution on the Web App on Microsoft Azure. +- **Publish:** Validates and packages the **manifest.json** file and the icons into a ZIP package and updates the generated package into the Teams Developer Portal. + +You can find the above actions in the "Lifecycle" section of the Microsoft Teams Toolkit extension, as illustrated in the following screenshot. + +![The interface of the Microsoft Teams Toolkit to manage the lifecycle of a solution. There are commands to provision, deploy, and publish the solution.](./images/Visual-Studio-Code-TTK-Lifecycle.png) + +However, before running the lifecycle actions, you need to slightly update the provisioning templates to support another configuration setting, needed to support the publishing of custom images with the Bot web application. Open the **azure.parameters.json** file in the **infra** folder and add one item with the name `botDomain` to the list of parameters. Here follows what the updated **azure.parameters.json** file should look like. + +```JSON +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceBaseName": { + "value": "bot${{RESOURCE_SUFFIX}}" + }, + "webAppSKU": { + "value": "B1" + }, + "botDomain": { + "value": "${{BOT_DOMAIN}}" + }, + "botDisplayName": { + "value": "collect-feedback-ts" + } + } +} +``` + +Now, open the **azure.bicep** file in the **infra** folder and update its content to support the new parameter and to use it in the settings of the provisioned web app in Microsoft Azure. +At the top of the file, where there's the list of input parameters, add a parameter with name `botDomain` and type `string`, right after the `webAppSKU` parameter. + +```Bicep +param botDomain string +``` + +Then, in the list `appSettings` for the `webApp` resource, add a new setting like the following one. + +```Bicep +{ + name: 'BOT_DOMAIN' + value: botDomain +} +``` + +Now, you can select the **Provision** action in the **Lifecycle** of the application. Once the provisioning is successfully completed, you can select **Deploy**. Once deployment is completed, select **Publish**. Wait up to 24 hours and the new Bot Powered ACE shows up in the Microsoft Viva Connections Dashboard. + +## Configure the Bot in Azure + +While waiting for the ACE to become available in the Dashboard, you need to slightly update the configuration of the Azure Bot. Open a web browser and navigate to the [Azure Management Portal](https://portal.azure.com/). From the Azure Management Portal home page, select "Azure Bot" and choose the Bot that you provisioned with the Microsoft Teams Toolkit. + +Open the **Configuration** panel of the Bot. Notice that the Microsoft Teams Toolkit configured the Bot to run with a **User-Assigned Managed Identity**. Here you can see what the available options are: + +- **User-Assigned Managed Identity**: if your Bot app doesn't need to access resources outside of its home tenant and if your Bot app is hosted on an Azure resource that supports Managed Identities. +- **Single Tenant**: if your Bot app doesn't need to access resources outside of its home tenant, but your Bot app isn't hosted on an Azure resource that supports Managed Identities. +- **Multi-Tenant**: if your Bot app needs to access resources outside of its home tenant or serves multiple tenants. + +Notice also that the "Messaging endpoint" URL for your Bot targets the URL of the Web App provisioned on Microsoft Azure by the Microsoft Teams Toolkit. + +![The configuration panel for an Azure Bot. It includes settings about Messaging Endpoint URL, the Microsoft App ID, the Application Insights keys, the Schema Transformation Version, and the OAuth Connection settings.](./images/Azure-Portal-Create-Azure-Bot-TTK-01.png) + +### Configuring the Microsoft 365 Channel + +You can now select the panel **Channels** in the Azure Bot to configure a new channel for Microsoft 365. In the **Available Channels** section of the page, you need to select the channel with the name **Microsoft 365** to enable it. + +![The panel to configure channels for the Azure Bot. There are two pre-selected channels: "Direct Line" and "Web Chat". There is a list of "Available Channels", including the "Microsoft 365" channel.](./images/Azure-Portal-Create-Azure-Bot-10-TTK.png) + +A new page shows up, explaining the purpose of the **Microsoft 365** channel. Select the **Apply** button to enable the new channel and go back to the list of channels configured for your Azure Bot. + +![The panel to configure the "Microsoft 365" channel in the list of channels supported by the Azure Bot. There is a description of the purpose of the channel and an "Apply" button to add the channel to the list of channels supported by the Azure Bot.](./images/Azure-Portal-Create-Azure-Bot-11.png) + +Right after that, your Azure Bot is fully configured and ready to be used. + +![The panel to configure channels for the Azure Bot. There are now three pre-selected channels: "Direct Line", "Web Chat", and "Microsoft 365.](./images/Azure-Portal-Create-Azure-Bot-12-TTK.png) + +You're now ready to run and test your Bot Powered ACE built with Microsoft Teams Toolkit and TypeScript. + +## Additional readings + +Now that you have built your first Bot Powered ACE with Microsoft Teams Toolkit and TypeScript, you are ready to dig into additional details by reading the following article(s). + +* [Authentication and Authorization in Bot Powered Adaptive Card Extensions](./AuthN-and-AuthZ-in-Bot-Powered-ACEs.md) diff --git a/docs/spfx/viva/bot-powered/Building-Your-First-Bot-Powered-ACE.md b/docs/spfx/viva/bot-powered/Building-Your-First-Bot-Powered-ACE.md new file mode 100644 index 000000000..9bc4e0175 --- /dev/null +++ b/docs/spfx/viva/bot-powered/Building-Your-First-Bot-Powered-ACE.md @@ -0,0 +1,645 @@ +--- +title: Building your first Bot Powered Adaptive Card Extension with .NET +description: Learn how to build your first Bot Powered Adaptive Card Extension using the Bot Framework for Microsoft .NET. +ms.date: 11/15/2024 +ms.localizationpriority: high +--- +# Building your first Bot Powered Adaptive Card Extension with .NET + +Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections enable extending the Microsoft Viva Connections Dashboard using the Bot development model. + +From a development point of view, a Bot Powered ACE behaves like a regular client-side ACE built with SharePoint Framework (SPFx). As such, you can render Card Views, Quick Views, you can provide properties configurable via a Property Pane, and you can implement specific behaviors to handle actions in the user interface of the ACE. You can learn more about the basics of client-side Adaptive Card Extensions for Microsoft Viva Connections by reading the tutorial [Build your first SharePoint Adaptive Card Extension](../get-started/build-first-sharepoint-adaptive-card-extension.md). + +You can build Bot Powered ACEs either using C# and .NET or using TypeScript and Node.js. In this tutorial, you learn how to build a basic Bot Powered ACE using C# with a step-by-step approach. + +You can learn more about the architecture of the Bot Powered ACEs by reading the article [Understanding Bot Powered Adaptive Card Extensions](./Understanding-Bot-Powered-ACEs.md). + +> [!TIP] +> You can also follow these steps by watching this video on the Microsoft 365 & Power Platform Community YouTube Channel. + +> [!Video https://www.youtube.com/embed/JgyyJi0SWDs] + +## Developing a Bot Powered ACE with Microsoft .NET + +In this tutorial, you're going to build a basic Bot Powered ACE to collect user feedback via a Card View with a textbox and a submission button. In the following picture, you can see how the Adaptive Card Extension looks like in the Viva Connections desktop experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections desktop experience. There is a Card View to collect user feedback and a submit button. There is also the same Card View with the textbox filled in with a sample value "I like Bot Powered ACEs". Then, there is a Card View confirming the collection of the feedback. Lastly, there is a Quick View with a generic message for the user.](./images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop.png) + +In the following picture, you can see how the Adaptive Card Extension looks like in the Viva Connections mobile experience. + +![The UI of the sample Bot Powered ACE in the Viva Connections mobile experience. There is a Card View to collect user's feedback and a submit button. There is also the same Card View with the textbox filled in with a sample value "I like Bot ...". Then, there is a Card View confirming the collection of the feedback. Lastly, there is a Quick View with a generic message for the user.](./images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile.png) + +From a developer point of view, you build the ACE once and you benefit from it in both desktop and mobile experiences. + +### Prerequirements + +First of all, to develop a Bot Powered ACE with C# and .NET, you need to have the following tools and frameworks installed on your development machine: + +* Microsoft .NET 6.0 or higher versions +* Microsoft Visual Studio 2022 +* Bot Builder Extensions for Microsoft Visual Studio 2022 +* Optionally, the Bot Framework Emulator + +You also need to have an active and valid Microsoft Azure subscription to host the Azure Bot. + +Last but not least, for local testing and debugging, you also need a reverse proxy tool like ngrok, Localtunnel, Serveo, YARP, etc. In this tutorial, we're going to use ngrok. + +## Creating the Bot solution in Visual Studio 2022 + +Once you installed the Bot Builder Extensions for Microsoft Visual Studio 2022, start Visual Studio and choose to create a new project of type **Empty Bot (Bot Framework v4 - .NET Core 3.1)** as illustrated in the following screenshot. + +![The UI of Microsoft Visual Studio 2022 to create a new project of type "Empty Bot (Bot Framework v4 - .NET Core 3.1)"](./images/Visual-Studio-Bot-Builder-Extension-Project.png) + +Give a name to your project (for example, "CollectFeedbackBotPoweredAce") and choose a folder to store the project files and the related solution. Despite the name of the project template, the resulting project is a .NET 6.0 one. + +Then, the first thing to do is to upgrade the NuGet package with name **Microsoft.Bot.Builder.Integration.AspNet.Core** to version 4.21.2 or higher. You can do it using the user interface of Visual Studio, right-clicking on the project and choosing "Manage NuGet packages ..." as you see in the following image. + +![The UI of Microsoft Visual Studio 2022 when upgrading the version of the NuGet package "Microsoft.Bot.Builder.Integration.AspNet.Core" to version 4.21.2 or higher.](./images/Visual-Studio-NuGet-Bot-Builder-SDK-Version.png) + +You can also use the .NET CLI and run the following command in the Package Manager Console, to update the package to the latest release. + +```console +dotnet add package Microsoft.Bot.Builder.Integration.AspNet.Core +``` + +In the automatically scaffolded solution, you find a bunch of autogenerated files. The files that matter to create a Bot Powered ACE are the following ones: + +* **Startup.cs**: configure services via Dependency Injection. +* **EmptyBot.cs**: the actual Bot implementation, where you write the real code of your Bot Powered ACE. +* **appsettings.json**: here you can configure the settings of your Bot Powered ACE, including the parameters of the Azure Bot. + +## Registering the Bot in Azure + +Before proceeding with the implementation of the Bot Powered ACE, you need to register a Bot in Microsoft Azure. + +Open a web browser and navigate to the [Azure Management Portal](https://portal.azure.com/). From the Azure Management Portal home page, select **Create a resource** and choose to create an **Azure Bot** service. + +![The interface of the Azure Management Portal when creating a new service instance of type Azure Bot.](./images/Azure-Portal-Create-Azure-Bot-01.png) + +Provide a handle for your Bot, which must be compliant with the following rules: + +* String between 4 and 42 characters long +* Supported characters are: a-z, A-Z, 0-9, - and _ +* Must start with a letter or digit +* It has to be unique + +The Bot handle becomes the display name of the Bot. However, you can change the display name later, while the Bot Handle is immutable, once registered. + +Choose a target subscription and resource group, and a data residency policy. From a pricing point of view, while you're developing and testing with Bot Powered ACEs, you can select the **F0 - Free** pricing tier. Once you're ready to release your Bot in production, you can upgrade the pricing tier to **S1 - Standard**. + +A Microsoft App ID is required to register an Azure Bot. Depending on your solution, you can select a different type of application through the **Type of App** option. You can choose any of the following options: + +* **User-Assigned Managed Identity**: if your Bot app doesn't need to access resources outside of its home tenant and if your Bot app is hosted on an Azure resource that supports Managed Identities. +* **Single Tenant**: if your Bot app doesn't need to access resources outside of its home tenant, but your Bot app isn't hosted on an Azure resource that supports Managed Identities. +* **Multi-Tenant**: if your Bot app needs to access resources outside of its home tenant or serves multiple tenants. + +Choose **Multi-Tenant** to follow the steps of this tutorial. + +You can also choose whether to create a new Microsoft Entra ID app or reuse an existing one. + +In the following screenshot, you can see all the available configuration options. + +![The page to register a new Azure Bot. It includes settings about the Bot handle, the target subscription and resource group, the pricing tier, and the Microsoft App ID settings.](./images/Azure-Portal-Create-Azure-Bot-02.png) + +Once you're done with the settings, select the **Review + create** button, review the selected settings, and register your Azure Bot by selecting the **Create** button. + +### Configure the Bot in Azure + +Once the Azure Bot is registered, select the **Go to resource** button, or open the Azure Bot configuration from the Azure Management Portal. + +#### Messaging endpoint URL configuration + +Open the **Configuration** panel of the Azure Bot and configure the **Messaging endpoint** URL for your Bot. + +In this configuration field, you should provide the base URL of your Bot. For example, if you're planning to use _ngrok_ to run the Bot locally, for testing and debugging purposes, the URL should be something like the following one: + +```http +https://.ngrok.io/api/messages +``` + +For instance, if you plan to use the name *my-bot-powered-ace* with ngrok, the **Messaging endpoint** URL should be + +```http +https://my-bot-powered-ace.ngrok.io/api/messages +``` + +... and the command to run ngrok on your local machine as a reverse proxy for the Bot should be: + +```console +ngrok http --host-header=localhost --hostname=my-bot-powered-ace.ngrok.io 3978 +``` + +Select **Apply** when you're done configuring the **Messaging endpoint** URL. + +![The configuration panel for an Azure Bot. It includes settings about Messaging Endpoint URL, the Microsoft App ID, the Application Insights keys, the Schema Transformation Version, and the OAuth Connection settings.](./images/Azure-Portal-Create-Azure-Bot-03.png) + +Once you configured the URL for your Bot, you need to configure a few more settings from the **Configuration** panel. Select the **Manage Password** link, next to the **Microsoft App ID** setting. + +#### Microsoft App configuration + +You're brought to the **Certificates & secrets** configuration page of the Microsoft App registered in Microsoft Entra ID for your Bot. From within this page, you can configure a new client secret. Copy the value of the new client secret in a safe place, you're going to reuse it later in this tutorial. + +Now, select the **Overview** panel and save in a safe place, together with the client secret, the values of the following settings: + +* Application (client) ID +* Directory (tenant) ID + +![The "Overview" panel of the Microsoft App. It includes information about the Display Name, the Application ID, the Directory ID, etc.](./images/Azure-Portal-Create-Azure-Bot-04.png) + +#### Configuring the Microsoft 365 Channel + +You can now go back to the configuration of your Azure Bot and select the panel **Channels** to configure a new channel for Microsoft 365. In the **Available Channels** section of the page, you need to select the channel named **Microsoft 365** to enable it. + +![The panel to configure channels for the Azure Bot. There are two pre-selected channels: "Direct Line" and "Web Chat". There is a list of "Available Channels", including the "Microsoft 365" channel.](./images/Azure-Portal-Create-Azure-Bot-10.png) + +A new page shows up, explaining the purpose of the **Microsoft 365** channel. Select the **Apply** button to enable the new channel and go back to the list of channels configured for your Azure Bot. + +![The panel to configure the "Microsoft 365" channel in the list of channels supported by the Azure Bot. There is a description of the purpose of the channel and an "Apply" button to add the channel to the list of channels supported by the Azure Bot.](./images/Azure-Portal-Create-Azure-Bot-11.png) + +Right after that, your Azure Bot is fully configured and ready to be used. + +![The panel to configure channels for the Azure Bot. There are now three pre-selected channels: "Direct Line", "Web Chat", and "Microsoft 365.](./images/Azure-Portal-Create-Azure-Bot-12.png) + +> [!IMPORTANT] +> If you are using ngrok and you have a free license, you will have to rely on a dynamic URL for your local development environment, rather than on a fixed and named URL. As such, whenever you will start ngrok you will get a new URL that you will have to configure in all the places where you have been instructed to configure the URL in this tutorial. Specifically, you will have to re-configure the URL in the "Messaging endpoint URL" of the Azure Bot. Then wait a few seconds before running the Bot, to allow the new URL to synchronize across the Microsoft Azure services. + +### Configure the project according to the Azure Bot settings + +Go back to Visual Studio and open the **appsettings.json** file to configure the settings for the Azure Bot. Here follows a code excerpt of the settings file, where you can see how to configure the Azure Bot parameters. + +```JSON +{ + "MicrosoftAppType": "MultiTenant", + "MicrosoftAppId": "", + "MicrosoftAppPassword": "", + "MicrosoftAppTenantId": "" +} +``` + +Replace the content of the above placeholders with the actual values that you stored before. + +> [!NOTE] +> You can also consider using the user's secrets functionality of Visual Studio to store the secrets securely and avoid to accidentally share them with unauthorized people. + +## Implement the actual Bot Powered ACE + +Rename the **EmptyBot.cs** file with name **CollectFeedbackBot.cs**, open it, and replace the base class from `ActivityHandler` to `SharePointActivityHandler` and empty the content of the class itself. You also need to import the namespace `Microsoft.Bot.Builder.SharePoint`. Then, add a set of overrides for all the methods with name starting with `OnSharePointTask*`. + +Here follows the resulting class implementation. + +```CSharp +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.SharePoint; +using Microsoft.Bot.Schema; +using Microsoft.Bot.Schema.SharePoint; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CollectFeedbackBotPoweredAce +{ + public class CollectFeedbackBot : SharePointActivityHandler + { + protected override Task OnSharePointTaskGetCardViewAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) + { + return base.OnSharePointTaskGetCardViewAsync(turnContext, aceRequest, cancellationToken); + } + + protected override Task OnSharePointTaskGetQuickViewAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) + { + return base.OnSharePointTaskGetQuickViewAsync(turnContext, aceRequest, cancellationToken); + } + + protected override Task OnSharePointTaskGetPropertyPaneConfigurationAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) + { + return base.OnSharePointTaskGetPropertyPaneConfigurationAsync(turnContext, aceRequest, cancellationToken); + } + + protected override Task OnSharePointTaskSetPropertyPaneConfigurationAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) + { + return base.OnSharePointTaskSetPropertyPaneConfigurationAsync(turnContext, aceRequest, cancellationToken); + } + + protected override Task OnSharePointTaskHandleActionAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) + { + return base.OnSharePointTaskHandleActionAsync(turnContext, aceRequest, cancellationToken); + } + } +} +``` + +Here follows a brief explanation of the overridable methods: + +* `OnSharePointTaskGetCardViewAsync`: handles the rendering of a Card View. +* `OnSharePointTaskGetQuickViewAsync`: handles the rendering of a Quick View. +* `OnSharePointTaskGetPropertyPaneConfigurationAsync`: allows rendering the Property Pane of the ACE. +* `OnSharePointTaskSetPropertyPaneConfigurationAsync`: allows saving the settings configured using the Property Pane of the ACE. +* `OnSharePointTaskHandleActionAsync`: handles a custom action in the ACE like the select on a button in a Card View or any custom action in the UI of a Quick View. + +> [!NOTE] +> You can dig into the details of how Bot Powered ACEs work by reading the article [Understanding Bot Powered Adaptive Card Extensions](./Understanding-Bot-Powered-ACEs.md). + +To implement the Collect Feedback ACE, you can only focus on `OnSharePointTaskGetCardViewAsync` and `OnSharePointTaskGetQuickViewAsync` to render the Card Views and the Quick View, as well as on the `OnSharePointTaskHandleActionAsync` to handle the actual submission of the feedback. So far, you can remove the two methods for handling the property pane, which is covered in another article. + +Every Bot Powered ACE does have a unique ID, which is a string that identifies uniquely the ACE instance in the Viva Connections Dashboard. For that unique ID you can, for example, use a `Guid` value converted into a string. You can define such a value as a private static string variable in the Bot class definition. + +```CSharp +private static string adaptiveCardExtensionId = Guid.NewGuid().ToString(); +``` + +The `OnSharePointTaskGetCardViewAsync` asynchronous method returns an instance of type `CardViewResponse`, while the `OnSharePointTaskGetQuickViewAsync` method returns an instance of type `QuickViewResponse`. Both `CardViewResponse` and `QuickViewResponse` are defined in the `Microsoft.Bot.Schema.SharePoint` namespace. + +### Rendering Card Views + +Every `CardViewResponse` instance is made of a property named `AceData` that defines some aesthetic settings like the size of the card, its icon, the title, and the description. It also defines the unique ID of the card and a JSON object to represent some custom `Properties`, if there's need. Every `CardViewResponse` instance also provides a `ViewId` string property, which declares a unique ID to identify the specific Card View instance for the ACE and which is mandatory to assign a value to. There's also an event with name `OnCardSelection`, which can be used to handle custom actions when the user selects on the Card View. + +Moreover, the `CardViewResponse` instance provides a property named `CardViewParameters` that defines the actual outline of the Card View. The content of the `CardViewParameters` property defines the structure of the components model used to render the card. Using the `CardViewParameters` factory type you can define different flavors of Card Views using the following methods: + +* `BasicCardViewParameters`: factory method to create a Basic Text Card View. +* `ImageCardViewParameters`: factory method to create an Image Card View. +* `PrimaryTextCardViewParameters`: factory method to create a Primary Text Card View. +* `SignInCardViewParameters`: factory method to create a Sign-in Card View. +* `SearchCardViewParameters`: factory method to create a Search Card View. +* `TextInputCardViewParameters`: factory method to create a Text Input Card View. + +For instance, to create the Card View to collect user feedback you can use the `TextInputCardViewParameters` method of `CardViewParameters` and define the components that make up the Card View. Furthermore, the Card View to confirm that the feedback was collected can be created using the `ImageCardViewParameters` method. It's a common habit to define the Card Views, and the Quick Views as well, in the constructor of the Bot, storing them in a static dictionary, where the item key is the `ViewId` of the card. Then, based on the requested Card View, you can return the corresponding item of the dictionary as the result of the `OnSharePointTaskGetCardViewAsync` method. + +Here follows a sample implementation of the Bot constructor, also relying on Dependency Injection to retrieve some settings from the **appsettings.json** file via the `IConfiguration` service implementation. + +```CSharp +public class CollectFeedbackBot : SharePointActivityHandler +{ + private static string adaptiveCardExtensionId = Guid.NewGuid().ToString(); + private readonly IConfiguration _configuration = null; + public readonly string _baseUrl; + + private static ConcurrentDictionary cardViews = new ConcurrentDictionary(); + + private static string CollectFeedbackCardView_ID = "GET_FEEDBACK_CARD_VIEW"; + private static string OkFeedbackCardView_ID = "OK_FEEDBACK_CARD_VIEW"; + private static string FeedbackQuickView_ID = "FEEDBACK_QUICK_VIEW"; + + public CollectFeedbackBot(IConfiguration configuration): base() + { + this._configuration = configuration; + this._baseUrl = configuration["BaseUrl"]; + + // ************************************ + // Add the CardViews + // ************************************ + + // Prepare ACE data for all Card Views + var aceData = new AceData() + { + Title = "Your voice matters!", + CardSize = AceData.AceCardSize.Large, + DataVersion = "1.0", + Id = adaptiveCardExtensionId + }; + + // Collect Feedback Card View (Input Text Card View) + CardViewResponse feedbackCardViewResponse = new CardViewResponse(); + feedbackCardViewResponse.AceData = aceData; + feedbackCardViewResponse.CardViewParameters = CardViewParameters.TextInputCardViewParameters( + new CardBarComponent() + { + Id = "FeedbackCardView", + }, + new CardTextComponent() + { + Text = "Please, provide feedback" + }, + new CardTextInputComponent() + { + Id = "feedbackValue", + Placeholder = "Your feedback ..." + }, + new List() + { + new CardButtonComponent() + { + Id = "SendFeedback", + Title = "Submit", + Action = new SubmitAction() + { + Parameters = new Dictionary() + { + {"viewToNavigateTo", OkFeedbackCardView_ID} + } + } + } + }, + new Microsoft.Bot.Schema.SharePoint.CardImage() + { + Image = $"{_baseUrl}/Media/Collect-Feedback.png", + AltText = "Collect feedback picture" + }); + feedbackCardViewResponse.ViewId = CollectFeedbackCardView_ID; + + feedbackCardViewResponse.OnCardSelection = new QuickViewAction() + { + Parameters = new QuickViewActionParameters() + { + View = FeedbackQuickView_ID + } + }; + + cardViews.TryAdd(feedbackCardViewResponse.ViewId, feedbackCardViewResponse); + + // OK Feedback Card View (Image Card View) + CardViewResponse okFeedbackCardViewResponse = new CardViewResponse(); + okFeedbackCardViewResponse.AceData = aceData; + okFeedbackCardViewResponse.CardViewParameters = CardViewParameters.ImageCardViewParameters( + new CardBarComponent() + { + Id = "OkFeedbackCardView", + }, + new CardTextComponent() + { + Text = "Here is your feedback '' collected on ''" + }, + new List() + { + new CardButtonComponent() + { + Id = "OkButton", + Title = "Ok", + Action = new SubmitAction() + { + Parameters = new Dictionary() + { + {"viewToNavigateTo", CollectFeedbackCardView_ID} + } + } + } + }, + new Microsoft.Bot.Schema.SharePoint.CardImage() + { + Image = $"{_baseUrl}/Media/Ok-Feedback.png", + AltText = "Feedback collected" + }); + okFeedbackCardViewResponse.ViewId = OkFeedbackCardView_ID; + + okFeedbackCardViewResponse.OnCardSelection = new QuickViewAction() + { + Parameters = new QuickViewActionParameters() + { + View = FeedbackQuickView_ID + } + }; + + cardViews.TryAdd(okFeedbackCardViewResponse.ViewId, okFeedbackCardViewResponse); + } +} +``` + +Notice how the constructor relies on a `ConcurrentDictionary` to store the Card View definitions, to support multi-threaded access to the static dictionary. Notice also how the various components are used to define the outline of the `TextInputCardViewParameters` and of the `ImageCardViewParameters`. + +In the following picture, you can see a diagram that explains the structure of a component-based Card View rendered in "Large" format. + +![A diagram with the structure of a component based Card View in "Large" format. The shape of the Card View is divided into two main sections, the left one is made of a CardBarComponent, a CardTextComponent, a component that varies depending on the kind of Card View template selected, and a list CardButtonComponent to provide zero, one, or two buttons. On the right section there can be an instance of Microsoft.Bot.Schema.SharePoint.CardImage to render an image, if any, depending on the kind of Card View template selected.](./images/ACE-Component-Based-Structure.png) + +A component-based Card View in "Large" format does have a shape divided into two main sections, the left one is made of a `CardBarComponent`, a `CardTextComponent`, a component that varies depending on the kind of Card View template selected, and a list of `BaseCardComponent` objects to provide zero, one, or two buttons. On the right section, there can be an instance of `Microsoft.Bot.Schema.SharePoint.CardImage` to render an image, if any, depending on the kind of Card View template selected + +For example, the `TextInputCardViewParameters` instance is made of the following components: + +* `CardBarComponent`: defines the top bar of the Card View, including the icon and the title. +* `CardTextComponent`: defines a text component with some informative text for the user. +* `CardTextInputComponent`: defines the input text field to collect feedback. Here, the `Id` property is fundamental because you need it later to retrieve the value of the textbox. +* `List`: defines a list of zero, one, or two action buttons. Each action button does have an `Id` property that is fundamental to identify the button pressed by the user. A button can also have a set of custom properties, which are provided to the Bot upon submission of the form. +* `Microsoft.Bot.Schema.SharePoint.CardImage`: defines an image that is rendered in the right side of the Card View. + +In the code excerpt, the images used to render the Card Views are downloaded from the website hosted in the Bot project, and available under the **wwwroot** folder of the project. In that folder, you should upload the **Media** subfolder that you can find in the [samples folder of the reference GitHub repository](https://github.com/SharePoint/sp-dev-docs/tree/main/assets/bot-powered/Media). + +### Serving Card Views requests + +To serve the card views, you need to implement the `OnSharePointTaskGetCardViewAsync` method so that it returns the instance of the card view to collect feedback that you created in the constructor. Here follows the method implementation. + +```CSharp +protected override Task OnSharePointTaskGetCardViewAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) +{ + return Task.FromResult(cardViews[CollectFeedbackCardView_ID]); +} +``` + +### Handling user's tasks and actions + +When the user selects the submit action in a Card View, the `OnSharePointTaskHandleActionAsync` method is triggered and you can handle the submission event. In the following code excerpt, you can see how the ACE collects the feedback submission. + +```CSharp +protected override Task OnSharePointTaskHandleActionAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) +{ + if (turnContext != null) + { + if (cancellationToken.IsCancellationRequested) + { + cancellationToken.ThrowIfCancellationRequested(); + } + } + Trace.Write("\n\n\nStarted to handle action.\n\n\n"); + JObject actionParameters = aceRequest.Data as JObject; + + if (actionParameters["type"].ToString().Equals("Submit", StringComparison.InvariantCultureIgnoreCase) && + actionParameters["id"].ToString().Equals("SendFeedback", StringComparison.InvariantCultureIgnoreCase)) + { + CardViewHandleActionResponse response = new CardViewHandleActionResponse(); + + string viewToNavigateTo = actionParameters["data"]["viewToNavigateTo"].ToString(); + var feedbackValue = actionParameters["data"]["feedbackValue"].ToString(); + var dateTimeFeedback = DateTime.Now; + + var nextCard = cardViews[viewToNavigateTo]; + + // Configure the text content for the Card View + var textContent = $"Here is your feedback '{feedbackValue}' collected on '{dateTimeFeedback}'"; + ((nextCard.CardViewParameters.Header.ToList())[0] as CardTextComponent).Text = textContent; + + // Set the response for the action + response.RenderArguments = nextCard; + + Trace.Write("\n\n\nFinished handling action.\n\n\n"); + return Task.FromResult(response); + } + else if (actionParameters["type"].ToString().Equals("Submit", StringComparison.InvariantCultureIgnoreCase) && + actionParameters["id"].ToString().Equals("OkButton", StringComparison.InvariantCultureIgnoreCase)) + { + CardViewHandleActionResponse response = new CardViewHandleActionResponse(); + + string viewToNavigateTo = actionParameters["data"]["viewToNavigateTo"].ToString(); + + // Set the response for the action + response.RenderArguments = cardViews[viewToNavigateTo]; + + Trace.Write("\n\n\nFinished handling action.\n\n\n"); + return Task.FromResult(response); + } + + Trace.Write("\n\n\nFinished handling action.\n\n\n"); + return Task.FromResult(new NoOpHandleActionResponse()); +} +``` + +First of all, the method checks if there's a proper instance of the `TurnContext`, and if the user canceled the asynchronous operation. Inside the `TurnContext` instance, there's all the needed information to properly handle the user's action. For example, there's the `turnContext.Activity.Value` property that represents a `JObject` instance with a property named `data` that contains a dictionary of properties to understand the type of action and the `Id` of the source component for the action. + +In the code excerpt, when the action type is **Submit** and the `Id` of the action is **SendFeedback**, it means that the user selected the submit button defined in the `TextInputCardViewParameters` instance, which is the one to collect the feedback. The actual value of the feedback is available in the data field with name equal to the `Id` of the textbox defined in the `CardTextInputComponent` component instance. The handling of the feedback is up to you. In the code excerpt, the sample configures an instance of the second Card View defined in the constructor and then instructs the ACE to render the new Card View via the `BaseHandleActionResponse` return value. + +### Rendering Quick Views + +While the Card Views are rendered based on a set of predefined component based templates, the Quick Views are rendered based on an Adaptive Card definition. The Adaptive Card can be defined either using a declarative and code based approach or using the `AdaptiveCards.Templating` NuGet package and reading a JSON file with an Adaptive Card definition. + +> [!IMPORTANT] +> Keep into account that the `AdaptiveCards.Templating` NuGet package can parse and process JSON files with Adaptive Card definitions up to Adaptive Card schema v1.2, while using the declarative and code-based model you can leverage any version of the Adaptive Card schema. + +Here follows a sample implementation of the `OnSharePointTaskGetQuickViewAsync` method, rendering a Quick View using a code-based and declarative model. + +```CSharp +protected override Task OnSharePointTaskGetQuickViewAsync(ITurnContext turnContext, AceRequest aceRequest, CancellationToken cancellationToken) +{ + // Add the Feedback QuickViews + QuickViewResponse feedbackQuickViewResponse = new QuickViewResponse(); + feedbackQuickViewResponse.Title = "Your feedback"; + feedbackQuickViewResponse.Template = new AdaptiveCard("1.5"); + + AdaptiveContainer container = new AdaptiveContainer(); + container.Separator = true; + AdaptiveTextBlock titleText = new AdaptiveTextBlock(); + titleText.Text = "Thanks for your feedback!"; + titleText.Color = AdaptiveTextColor.Dark; + titleText.Weight = AdaptiveTextWeight.Bolder; + titleText.Size = AdaptiveTextSize.Large; + titleText.Wrap = true; + titleText.MaxLines = 1; + titleText.Spacing = AdaptiveSpacing.None; + container.Items.Add(titleText); + + AdaptiveTextBlock dateTimeCollectedText = new AdaptiveTextBlock(); + dateTimeCollectedText.Text = $"We truly appreciate your effort in providing valuable feedback to us. Thanks!"; + dateTimeCollectedText.Color = AdaptiveTextColor.Dark; + dateTimeCollectedText.Size = AdaptiveTextSize.Medium; + dateTimeCollectedText.Wrap = true; + dateTimeCollectedText.MaxLines = 3; + dateTimeCollectedText.Spacing = AdaptiveSpacing.None; + container.Items.Add(dateTimeCollectedText); + + feedbackQuickViewResponse.Template.Body.Add(container); + + feedbackQuickViewResponse.ViewId = FeedbackQuickView_ID; + + return Task.FromResult(feedbackQuickViewResponse); +} +``` + +The code relies on the `AdaptiveCard` type defined in the `AdaptiveCards` NuGet package and builds the content of the Adaptive Card nesting various blocks of content into a hierarchy of elements. In the code excerpt, there's an `AdaptiveContainer` made of two `AdaptiveTextBlock` instances. + +## Define the **manifest.json** file for the solution + +Create a new folder with the name **TeamsAppManifest** in the root folder of your project and add a couple of image files for the icons of the Microsoft 365 application that you're defining and a **manifest.json** file. + +The image files should be the following ones: + +* **icon-color.png**: a 192x192 pixel PNG colored image with a transparent background. +* **icon-outline.png**: a 32x32 pixel PNG wireframe image with a transparent background. + +The manifest file should look like the following: + +```JSON +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.14/MicrosoftTeams.schema.json", + "manifestVersion": "1.16", + "version": "1.0.0", + "id": "", + "packageName": "collectfeedback.botpoweredace", + "developer": { + "name": "", + "websiteUrl": "", + "privacyUrl": "", + "termsOfUseUrl": "", + "mpnId": "" + }, + "name": { + "short": "Collect Feedaback Bot Powered ACE", + "full": "This is a basic sample of a Bot Powered ACE for Microsoft Viva Connections Dashboard to collect user's feedback" + }, + "description": { + "short": "Basic sample of a Bot Powered ACE for Microsoft Viva Connections Dashboard to collect user's feedback", + "full": "Basic sample of how to use the latest release of the Bot Framework SDK to build a Bot Powered ACE for Microsoft Viva Connections Dashboard to collect user's feedback" + }, + "icons": { + "outline": "icon-outline.png", + "color": "icon-color.png" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "", + "needsChannelSelector": false, + "isNotificationOnly": false, + "supportsCalling": false, + "supportsVideo": false, + "supportsFiles": false, + "scopes": [ + "team", + "personal", + "groupchat" + ] + } + ], + "dashboardCards": [ + { + "id": "", + "displayName": "Collect Feedaback", + "description": "Bot Powered ACE to collect user's feedback", + "icon": { + "officeUIFabricIconName": "Feedback" + }, + "contentSource": { + "sourceType": "bot", + "botConfiguration": { + "botId": "" + } + }, + "defaultSize": "medium" + } + ], + "permissions": [ + "identity" + ], + "validDomains": [ + ".ngrok.io" + ] +} +``` + +In the **manifest.json** file, you should replace `` with the actual Client ID of your Microsoft App. You should also configure the actual URL of your Bot in the `validDomains` section of the manifest. Lastly, you should consider providing real values for the settings in the `developer` section. All of the URLs in the `developer` section need to target addresses under HTTPS. + +Notice the `dashboardCards` section that defines the actual settings for your Bot Powered ACEs. In particular, through this section you can configure the `id` of the Microsoft App backing your Azure Bot, the `displayName` and `description` of the ACE, as well as the `icon` as a Fluent UI Icon, the Bot that handles the requests and that must be configured in the `bots` section of the **manifest.json**, and last but not least the `defaultSize` for your ACE in the Viva Connections Dashboard. + +You can consider copying and reusing the images and the **manifest.json** templates from the [samples folder of the reference GitHub repository](https://github.com/SharePoint/sp-dev-docs/tree/main/assets/bot-powered/TeamsAppManifest) associated with this tutorial. + +## Run and test the solution + +You're now ready to package and deploy your custom solution. You simply need to package the **manifest.json** file and the two images into a .ZIP file, like you would do with any other Microsoft Teams or Microsoft 365 custom application. Name the .ZIP file with whatever name you like, open the App Catalog of your target SharePoint Online tenant, and upload the .ZIP file as a new application package. + +The SharePoint Online server-side infrastructure recognizes the manifest structure and prompts you to enable and deploy the solution on the tenant. + +![The UI of the new SharePoint AppCatalog prompting to enable the solution and make it tenant-wide available.](./images/App-Catalog-Package-Publishing.png) + +Make the solution tenant-wide available, by selecting the option **Enable this app and add it to all sites**, and the Bot Powered ACE is available in the Viva Connections Dashboard. + +> [!NOTE] +>Remember to start ngrok, or any other reverse proxy of your choice, before testing the Bot Powered ACE. + +Now, run the Visual Studio project in debug mode (by pressing F5). Open the Microsoft Viva Connections Dashboard. Edit its content and search for the new Bot Powered ACE that you installed. + +![The UI of the new Viva Connections Dashboard while adding a new ACE. There is the new Collect Feedback ACE available in the list of Adaptive Card Extensions. There is also the rendering of the sample ACE in background, already inserted in the Viva Connections Dashboard.](./images/Bot-Powered-ACE-Collect-Feedback-UI-Adding-to-Dashboard.png) + +In the upcoming articles of this guidance, you also learn how to publish and host the Bot Powered ACEs in a real hosting environment on Microsoft Azure, rather than running them locally on a development environment. + +## Additional readings + +Now that you have built your first Bot Powered ACE, you're ready to dig into additional details by reading the following articles. + +* [Authentication and Authorization in Bot Powered Adaptive Card Extensions](./AuthN-and-AuthZ-in-Bot-Powered-ACEs.md) diff --git a/docs/spfx/viva/bot-powered/Extending-existing-Teams-Bot.md b/docs/spfx/viva/bot-powered/Extending-existing-Teams-Bot.md new file mode 100644 index 000000000..c5332258e --- /dev/null +++ b/docs/spfx/viva/bot-powered/Extending-existing-Teams-Bot.md @@ -0,0 +1,388 @@ +--- +title: Extending an existing Teams Bot to become a Bot Powered Adaptive Card Extension +description: Learn how to extend a Teams Bot to become a Bot Powered Adaptive Card Extension for Microsoft Viva Connections. +ms.date: 12/12/2024 +ms.localizationpriority: high +--- +# Extending an existing Teams Bot to become a Bot Powered Adaptive Card Extension + +The main purpose of having the new Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections is to make it possible to reuse already existing bots, enriching their user experience with the support for Microsoft Viva Connections Dashboard. In fact, the return on investment that you can achieve by using and extending an already existing effort is a fundamental benefit of the Bot Powered ACEs. + +In this article, you'll learn how to upgrade an already existing Teams Bot into a Bot Powered Adaptive Card Extension (ACE) experience. + +## Updating the code of an already existing bot + +So, let's assume that you created a bot for Microsoft Teams, using the Microsoft Teams Toolkit, using the **Bot | Basic Bot** template. The first thing to do is to upgrade the **botbuilder** reference in **package.json** to version 4.23.1 or higher. You can use the following command. + +```console +npm i botbuilder --save +``` + +You also need to import the **adaptivecards** package with version 1.2.3, executing the following command. + +```console +npm i adaptivecards@1.2.3 --save +``` + +Then, open the **teamsBot.ts** file (or whatever name you gave to the main bot source code file) and add an import statement to import all the types needed by Bot Powered ACEs. The updated source code file should look like the following one. + +```TypeScript +import { + AceData, + AceRequest, + ActivityHandler, + CardViewResponse, + PrimaryTextCardView, + GetPropertyPaneConfigurationResponse, + HandleActionResponse, + InvokeResponse, + QuickViewResponse, + SetPropertyPaneConfigurationResponse, + TeamsActivityHandler, + TurnContext } +from "botbuilder"; +import * as AdaptiveCards from 'adaptivecards'; +``` + +Then, you need to initialize some infrastructural data in the bot constructor, to support the rendering of the Bot Powered ACE. It's a common habit to define a set of Card Views and Quick Views in the constructor of the Bot Powered ACE. You can then reuse them while rendering the actual user experience of the ACE. You can learn more about implementing Bot Powered ACEs by reading the article [Building your first Bot Powered Adaptive Card Extension with Microsoft Teams Toolkit and TypeScript](./Building-Your-First-Bot-Powered-ACE-TTK-TS.md). + +In the following code excerpt, you can see the updated constructor of the bot. + +```TypeScript +export class TeamsBot extends TeamsActivityHandler { + + private readonly _botId: string = 'AceFromExistingBot'; + private _cardViews: { [key: string]: CardViewResponse } = {}; + + private WELCOME_CARD_VIEW_ID: string = 'WELCOME_CARD_VIEW'; + private WELCOME_QUICK_VIEW_ID: string = 'WELCOME_QUICK_VIEW'; + + constructor() { + super(); + + // Prepare the ACE data for all the card views and quick views. + const aceData: AceData = { + id: this._botId, + title: 'Your extended bot!', + description: 'Welcome to your extended bot.', + cardSize: 'Large', + iconProperty: 'Robot', + properties: {}, + dataVersion: '1.0', + }; + + // Welcome Card View (Primary Text Card View) + const welcomeCardViewResponse: CardViewResponse = { + aceData: aceData, + cardViewParameters: PrimaryTextCardView( + { + componentName: 'cardBar', + title: 'Welcome!' + }, + { + componentName: 'text', + text: 'Welcome!' + }, + { + componentName: 'text', + text: 'Here is your Teams bot available also in Microsoft Viva Connections!' + }, + [ + { + componentName: 'cardButton', + title: 'Show Quick View', + id: 'ShowQuickView', + action: { + type: 'QuickView', + parameters: { + view: this.WELCOME_QUICK_VIEW_ID + } + } + } + ] + ), + viewId: this.WELCOME_CARD_VIEW_ID, + onCardSelection: { + type: 'QuickView', + parameters: { + view: this.WELCOME_QUICK_VIEW_ID + } + } + }; + this._cardViews[this.WELCOME_CARD_VIEW_ID] = welcomeCardViewResponse; + + this.onMessage(async (context, next) => { + console.log("Running with Message Activity."); + const removedMentionText = TurnContext.removeRecipientMention(context.activity); + const txt = removedMentionText.toLowerCase().replace(/\n|\r/g, "").trim(); + await context.sendActivity(`Echo: ${txt}`); + // By calling next() you ensure that the next BotHandler is run. + await next(); + }); + + this.onMembersAdded(async (context, next) => { + const membersAdded = context.activity.membersAdded; + for (let cnt = 0; cnt < membersAdded.length; cnt++) { + if (membersAdded[cnt].id) { + await context.sendActivity( + `Hi there! I'm a Teams bot that will echo what you said to me.` + ); + break; + } + } + await next(); + }); + } +} +``` + +Then, you need to add some new custom logic to the bot to support rendering as a Bot Powered ACE. Override the `onInvokeActivity` method of the base class and provide support for any of the following actions: + +- **cardExtension/getCardView**: handles the rendering of a Card View. +- **cardExtension/getQuickView**: handles the rendering of a Quick View. +- **cardExtension/getPropertyPaneConfiguration**: allows rendering the Property Pane of the ACE. +- **cardExtension/setPropertyPaneConfiguration**: allows saving the settings configured using the Property Pane of the ACE. +- **cardExtension/handleAction**: handles a custom action in the ACE like the select on a button in a Card View or any custom action in the UI of a Quick View. + +Here follows a sample implementation of the **onInvokeActivity** method. + +```TypeScript +/** + * Invoked when an invoke activity is received from the connector. + * Invoke activities can be used to communicate many different things. + * * Invoke activities communicate programmatic commands from a client or channel to a bot. + * + * @param context A strongly-typed context object for this turn + * @returns A task that represents the work queued to execute + */ +protected async onInvokeActivity(context: TurnContext): Promise { + try { + switch (context.activity.name) { + case 'cardExtension/getCardView': + return ActivityHandler.createInvokeResponse( + await this.onSharePointTaskGetCardViewAsync(context, context.activity.value as AceRequest) + ); + case 'cardExtension/getQuickView': + return ActivityHandler.createInvokeResponse( + await this.onSharePointTaskGetQuickViewAsync(context, context.activity.value as AceRequest) + ); + case 'cardExtension/getPropertyPaneConfiguration': + return ActivityHandler.createInvokeResponse( + await this.onSharePointTaskGetPropertyPaneConfigurationAsync( + context, + context.activity.value as AceRequest + ) + ); + case 'cardExtension/setPropertyPaneConfiguration': + return ActivityHandler.createInvokeResponse( + await this.onSharePointTaskSetPropertyPaneConfigurationAsync( + context, + context.activity.value as AceRequest + ) + ); + case 'cardExtension/handleAction': + return ActivityHandler.createInvokeResponse( + await this.onSharePointTaskHandleActionAsync(context, context.activity.value as AceRequest) + ); + default: + return super.onInvokeActivity(context); + } + } catch (err) { + if (err.message === 'NotImplemented') { + return { status: 501 }; + } else if (err.message === 'BadRequest') { + return { status: 400 }; + } + throw err; + } +} +``` + +You can read the article [Overview of Bot Powered Adaptive Card Extensions](Overview-Bot-Powered-ACEs.md), to learn about the basic requirement for a Bot Powered ACE to provide at least one Card View. You can optionally provide more Card Views and one or more Quick Views, in case you want to have a better and more personalized user experience. + +In this article, you'll add both a Card View and a Quick View. As such, you're going to implement the actions **cardExtension/getCardView** and **cardExtension/getQuickView**, respectively with methods `onSharePointTaskGetCardViewAsync` and `onSharePointTaskGetQuickViewAsync`. While you don't need to implement all the other methods. + +```TypeScript +/** + * Override this in a derived class to provide logic for when a card view is fetched + * + * @param _context - A strongly-typed context object for this turn + * @param _aceRequest - The Ace invoke request value payload + * @returns A Card View Response for the request + */ +protected async onSharePointTaskGetCardViewAsync( + _context: TurnContext, + _aceRequest: AceRequest +): Promise { + return this._cardViews[this.WELCOME_CARD_VIEW_ID]; +} + +/** + * Override this in a derived class to provide logic for when a quick view is fetched + * + * @param _context - A strongly-typed context object for this turn + * @param _aceRequest - The Ace invoke request value payload + * @returns A Quick View Response for the request + */ +protected async onSharePointTaskGetQuickViewAsync(_context: TurnContext, _aceRequest: AceRequest): Promise { + + // Prepare the AdaptiveCard for the Quick View + const card = new AdaptiveCards.AdaptiveCard(); + card.version = new AdaptiveCards.Version(1, 5); + const cardPayload = { + type: 'AdaptiveCard', + $schema: "http://adaptivecards.io/schemas/adaptive-card.json", + body: [ + { + type: 'TextBlock', + text: 'Welcome!', + weight: 'Bolder', + size: 'Large', + wrap: true, + maxLines: 1, + spacing: 'None', + color: 'Dark' + }, + { + type: 'TextBlock', + text: 'We are happy to see that you are consuming your extended Teams Bot in Microsoft Viva Connections! Thanks!', + weight: 'Normal', + size: 'Medium', + wrap: true, + maxLines: 3, + spacing: 'None', + color: 'Dark' + } + ] + }; + card.parse(cardPayload); + + // Add the Feedback QuickViews + const welcomeQuickViewResponse: QuickViewResponse = { + viewId: this.WELCOME_QUICK_VIEW_ID, + title: 'Welcome!', + template: card, + data: {}, + externalLink: null, + focusParameters: null + }; + + return Promise.resolve(welcomeQuickViewResponse); +} + +/** + * Override this in a derived class to provide logic for getting configuration pane properties. + * + * @param _context - A strongly-typed context object for this turn + * @param _aceRequest - The Ace invoke request value payload + * @returns A Property Pane Configuration Response for the request + */ +protected async onSharePointTaskGetPropertyPaneConfigurationAsync( + _context: TurnContext, + _aceRequest: AceRequest +): Promise { + throw new Error('NotImplemented'); +} + +/** + * Override this in a derived class to provide logic for setting configuration pane properties. + * + * @param _context - A strongly-typed context object for this turn + * @param _aceRequest - The Ace invoke request value payload + * @returns A Card view or no-op action response + */ +protected async onSharePointTaskSetPropertyPaneConfigurationAsync( + _context: TurnContext, + _aceRequest: AceRequest +): Promise { + throw new Error('NotImplemented'); +} + +/** + * Override this in a derived class to provide logic for setting configuration pane properties. + * + * @param _context - A strongly-typed context object for this turn + * @param _aceRequest - The Ace invoke request value payload + * @returns A handle action response + */ +protected async onSharePointTaskHandleActionAsync( + _context: TurnContext, + _aceRequest: AceRequest +): Promise { + throw new Error('NotImplemented'); +} +``` + +The `onSharePointTaskGetCardViewAsync` method returns the Card View defined in the constructor as the only element in the dictionary of Card Views. The `onSharePointTaskGetQuickViewAsync` method creates an Adaptive Card using the **adaptivecards** package that you imported previously and then returns the card into a Quick View object. + +## Updating the manifest of an already existing bot + +Your bot is now ready to support rendering as a Bot Powered ACE in Microsoft Viva Connection. However, to make it available as a new ACE in the Viva Connections Dashboard, you need to update the **manifest.json** file of the solution to declare this new capability. Specifically, you need to add a section `dashboardCards`, for example right after the `bots` configured as follows. Here you can see an excerpt of the **manifest.json** file. + +```JSON +"dashboardCards": [ + { + "id": "${{BOT_ID}}", + "pickerGroupId": "8cd406cc-7a66-42b5-bda5-9576abe7a818", + "displayName": "Teams Bot Extended", + "description": "Bot Powered ACE created from an already existing Teams bot", + "icon": { + "officeUIFabricIconName": "Robot" + }, + "contentSource": { + "sourceType": "bot", + "botConfiguration": { + "botId": "${{BOT_ID}}" + } + }, + "defaultSize": "large" + } +] +``` + +Then, update the `validDomains` section according to the following excerpt. + +```JSON +"validDomains": [ + "${{BOT_DOMAIN}}" +] +``` + +The setting includes the domain of the bot in the list of valid domains so that Microsoft 365 can trust any resource published by the Bot web application. + +## Deploying the updated bot + +You can now package and deploy the solution using the out-of-the-box capabilities of Microsoft Teams Toolkit. You simply need to trigger the actions to **Provision**, **Deploy**, and **Publish** the bot in Microsoft Teams. After no more than 24 hours, your bot becomes available in Microsoft Viva Connections as a new Bot Powered ACE. + +## Configure the Bot in Azure + +While waiting for the ACE to become available in the Dashboard, you need to slightly update the configuration of the Azure Bot. Open a web browser and navigate to the [Azure Management Portal](https://portal.azure.com/). From the Azure Management Portal home page, select "Azure Bot" and choose the Bot that you provisioned with the Microsoft Teams Toolkit. + +Open the **Configuration** panel of the Bot. Notice that the Microsoft Teams Toolkit configured the Bot to run with a **User-Assigned Managed Identity**. Here you can see what the available options are: + +- **User-Assigned Managed Identity**: if your Bot app doesn't need to access resources outside of its home tenant and if your Bot app is hosted on an Azure resource that supports Managed Identities. +- **Single Tenant**: if your Bot app doesn't need to access resources outside of its home tenant, but your Bot app isn't hosted on an Azure resource that supports Managed Identities. +- **Multi-Tenant**: if your Bot app needs to access resources outside its home tenant or serves multiple tenants. + +Notice also that the "Messaging endpoint" URL for your Bot targets the URL of the Web App provisioned on Microsoft Azure by the Microsoft Teams Toolkit. + +![The configuration panel for an Azure Bot. It includes settings about Messaging Endpoint URL, the Microsoft App ID, the Application Insights keys, the Schema Transformation Version, and the OAuth Connection settings.](./images/Azure-Portal-Create-Azure-Bot-TTK-01.png) + +### Configuring the Microsoft 365 Channel + +You can now select the panel **Channels** in the Azure Bot to configure a new channel for Microsoft 365. In the **Available Channels** section of the page, you need to select the channel with the name **Microsoft 365** to enable it. + +![The panel to configure channels for the Azure Bot. There are two pre-selected channels: "Direct Line" and "Web Chat". There is a list of "Available Channels", including the "Microsoft 365" channel.](./images/Azure-Portal-Create-Azure-Bot-10-TTK.png) + +A new page shows up, explaining the purpose of the **Microsoft 365** channel. Select the **Apply** button to enable the new channel and go back to the list of channels configured for your Azure Bot. + +![The panel to configure the "Microsoft 365" channel in the list of channels supported by the Azure Bot. There is a description of the purpose of the channel and an "Apply" button to add the channel to the list of channels supported by the Azure Bot.](./images/Azure-Portal-Create-Azure-Bot-11.png) + +Right after that, your Azure Bot is fully configured and ready to be used. + +![The panel to configure channels for the Azure Bot. There are now three pre-selected channels: "Direct Line", "Web Chat", and "Microsoft 365.](./images/Azure-Portal-Create-Azure-Bot-12-TTK.png) + +You're now ready to run and test your Bot Powered ACE built with Microsoft Teams Toolkit and TypeScript. +In the following screenshot, you can see the output of the Bot Powered ACE in the Microsoft Viva Connections Dashboard. + +![The interface Bot Powered ACE created starting from a Teams Bot. There is a Card View with a welcome message and a button to show a QuickView. There is a QuickView welcoming the user, too.](./images/Extend-Teams-Bot-01.png) diff --git a/docs/spfx/viva/bot-powered/Overview-Bot-Powered-ACEs.md b/docs/spfx/viva/bot-powered/Overview-Bot-Powered-ACEs.md new file mode 100644 index 000000000..7933d2a96 --- /dev/null +++ b/docs/spfx/viva/bot-powered/Overview-Bot-Powered-ACEs.md @@ -0,0 +1,40 @@ +--- +title: Overview of Bot Powered Adaptive Card Extensions +description: Generic overview about the Bot Powered Adaptive Card Extensions +ms.date: 02/01/2024 +ms.localizationpriority: high +--- +# Overview of Bot Powered Adaptive Card Extensions + +Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections can be used to build custom experiences for the Microsoft Viva Connections Dashboard using the Bot development model. Bot Powered ACEs are an addition to the already existing Viva Connections extensibility model, which is based on SharePoint Framework (SPFx) components. + +Objective of the Bot Powered ACEs is to enable existing Microsoft Teams developers, with existing bot implementations, extend their bot implementations to be available in the Viva Connections. Bot Powered ACEs are packaged using the Microsoft Teams solution model, enabling the same bot to be used in both Microsoft Teams and in Microsoft Viva Connections. + +While with SPFx components you create client-side solutions to extend Viva Connections, using the Bot Powered ACEs you can apply server-side solutions. Depending on your requirements, objectives, expertise, and scenario you can choose between these two options that are complementary and not alternative. + +In the following picture, you can see an Adaptive Card Extension to collect user's feedback in action in the desktop experience of Viva Connection Dashboard. The ACE was implemented as a Bot Powered ACE. + +![An Adaptive Card Extension with a textbox to collect user's feedback and a button to submit the feedback.](./images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-01.png) + +While in the following picture you can see the same ACE rendered inside the mobile experience of the Viva Connections Dashboard. + +![The mobile Viva Connections Dashboard with some Adaptive Card Extensions, including one to collect user's feedback with a textbox and a button to submit the feedback.](./images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-01.jpg) + +From a developer point of view, you build the ACE once and you can benefit of it in both desktop and mobile experiences. + +## Start building Bot Powered ACEs for Microsoft Viva Connections + +In this series of articles, you can understand what Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections are, their architecture, and how to build real-life solutions. + +The series of articles covers the following topics: + +1. [Building your first Bot Powered Adaptive Card Extension with .NET](Building-Your-First-Bot-Powered-ACE.md) +1. [Building your first Bot Powered Adaptive Card Extension with Microsoft Teams Toolkit and TypeScript](Building-Your-First-Bot-Powered-ACE-TTK-TS.md) +1. [Understanding Bot Powered Adaptive Card Extensions](Understanding-Bot-Powered-ACEs.md) +1. [Authentication and Authorization in Bot Powered Adaptive Card Extensions](AuthN-and-AuthZ-in-Bot-Powered-ACEs.md) +1. [Building Bot Powered Adaptive Card Extensions with Microsoft Entra ID and Single Sign-on](AuthN-and-AuthZ-in-Bot-Powered-ACEs-Entra.md) +1. [Building Bot Powered Adaptive Card Extensions with Magic Code authentication](AuthN-and-AuthZ-in-Bot-Powered-ACEs-Magic-Code.md) + +By reading the above articles, you're able to manage the development of Bot Powered ACEs for Microsoft Viva Connections and to apply the potential of this new technology. + +In order to understand the content of this series of articles, you need to have a good understanding of how a Bot works in Microsoft Azure and in Microsoft Teams, as well as to have a basic knowledge of either .NET and C# development or TypeScript and Node.js development. diff --git a/docs/spfx/viva/bot-powered/Understanding-Bot-Powered-ACEs.md b/docs/spfx/viva/bot-powered/Understanding-Bot-Powered-ACEs.md new file mode 100644 index 000000000..d47ef79eb --- /dev/null +++ b/docs/spfx/viva/bot-powered/Understanding-Bot-Powered-ACEs.md @@ -0,0 +1,70 @@ +--- +title: Understanding Bot Powered Adaptive Card Extensions +description: Provides a technological and architectural overview of the Bot Powered Adaptive Card Extensions +ms.date: 02/01/2024 +ms.localizationpriority: high +--- +# Understanding Bot Powered Adaptive Card Extensions + +Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections can be used to build custom experiences for the Microsoft Viva Connections Dashboard using the Bot development model. + +> [!TIP] +> You can also watch the key areas of this article in video format on the Microsoft Community Learning YouTube Channel. + +> [!Video https://www.youtube.com/embed/OWPVe3n5UnM] + +Bot Powered ACEs is the new addative extensibility extensibility model for the Viva Connections Dashboard, which can be also extended using the client-side ACEs built using the SharePoint Framework. SPFx based extensibility model is solid and mature, especially with the latest features introduced with the [component based ACEs](/sharepoint/dev/spfx/viva/design/designing-card) released with SharePoint Framework version 1.18.x. However, there are some use cases that can't be addressed with a client-side development model, like just to make few examples: + +* You have an existing server-side bot for Microsoft Teams which you'd like to use to power power an ACE running in the Viva Connections dashboard for a better return of investment. +* Existing applications developed using C# and .NET that can't be used on the client-side in SharePoint Framework. +* Software architectures where you rely on external (non-Microsoft) identity providers (IDPs) and you would like to have a seemless and silent single sign-on (SSO) experience for your end users. With SharePoint Framework and SharePoint Online there's no native support for external IDPs. +* Scenarios where you rely on REST APIs secured with API Key and you can't store them on the client-side, for security reasons. +* Application architectures where you need to apply business critical logic and formulas that you don't want to make available on the client-side. +* Etc. + +In all the above scenarios, being able to generate and manage the rendering of an ACE on the server-side allows defining better software architectures. The Bot Powered ACEs are designed and provided to make these scenarios possible. + +## Architecture of Bot Powered ACEs + +Let's have a look at the architecture of Bot Powered ACEs in order to better understand how they work and what their potentials are. + +From a development point of view, a Bot Powered ACE behaves like a regular client-side ACE built with SharePoint Framework. As such, you can render Card Views, Quick Views, you can provide properties configurable via a Property Pane, and you can implement specific behaviors to handle actions in the user interface of the ACE. + +You can learn more about the basics of client-side Adaptive Card Extensions for Microsoft Viva Connections by reading the tutorial ["Build your first SharePoint Adaptive Card Extension."](/sharepoint/dev/spfx/viva/get-started/build-first-sharepoint-adaptive-card-extension) + +Bot Powered ACEs are based on Azure Bots. To create a new Bot Powered ACE, you need to register an Azure Bot in the Microsoft Azure portal, and you have to implement a Bot using the [Microsoft Bot Framework SDK](https://learn.microsoft.com/en-us/azure/bot-service/index-bf-sdk?view=azure-bot-service-4.0). + +![The architectural diagram of an Azure hosted Bot Powered ACE. The end user interacts with the Bot via the Microsoft 365 Channel, which relies on the Azure Bot Services. The Azure Bot Services are an intermediary to the Bot Adapter which handles the actual requests, creates a `TurnContext` object and hands control to the actual Bot. The response of a Bot request flows back to the end user following the reversed path.](./images/Bot-Architectural-Diagram.png) + +A Bot Powered ACE relies on the Microsoft 365 Channel, which is used also to create Bots for other Microsoft 365 apps. Whenever an end user interacts with a Bot Powered ACE, the Microsoft 365 Channel handles the request and hands it to the Azure Bot Services. Then, the Azure Bot Services transfers the request to a Bot Adapter that creates a proper `TurnContext` object, which includes request context information and a definition of the `Activity` requested for the Bot. + +The actual Bot implements the logic to render the Bot Powered ACE and replies back to the end user/front-end providing a new card (Card View or Quick View). The new card renders in the Viva Connections Dashboard. + +As a developer, you don't need to dig into all the technical details of how an Azure Bot works. You can focus on implementing the Adaptive Card Extension, while the Bot architecture takes care of all the plumbing for you. + +It's important to know that the Bot Powered ACEs can only be created starting from a specific release of the [Microsoft Bot Framework SDK](/azure/bot-service/index-bf-sdk). In fact, starting from version 4.21.2 of the Bot Framework SDK there are new types supporting Bot Powered ACEs. You can develop Bot Powered ACEs either using C# and .NET or using TypeScript and Node.js. As such, depending on your development background and eventually on your already existing code, you can extend your already existing Bots to support Bot Powered ACEs. + +### Bot Framework SDK `SharePointActivityHandler` + +Starting from version 4.21.2 of the Bot Framework SDK there are new types supporting the creation of Bot Powered ACEs. Specifically, there's a specialized `ActivityHandler` type with name `SharePointActivityHandler` that provides the following overridable methods: + +* `OnSharePointTaskGetCardViewAsync`: handles the rendering of a Card View. +* `OnSharePointTaskGetQuickViewAsync`: handles the rendering of a Quick View. +* `OnSharePointTaskGetPropertyPaneConfigurationAsync`: allows rendering the Property Pane of the ACE. +* `OnSharePointTaskSetPropertyPaneConfigurationAsync`: allows saving the settings configured using the Property Pane of the ACE. +* `OnSharePointTaskHandleActionAsync`: handles a custom action in the ACE like the select on a button in a Card View or any custom action in the UI of a Quick View. + +To implement a custom Bot Powered ACE, you aren't forced to override all of the above methods. You can override what you need in order to implement your own custom ACE. + +For example, if your custom ACE relies on Card Views only, you can override `OnSharePointTaskGetCardViewAsync` and you can skip overriding all the other methods. In the article ["Building your first Bot Powered Adaptive Card Extension,"](Building-Your-First-Bot-Powered-ACE.md) you can understand how to build a real Bot Powered ACE following a step by step guidance. + +### Important considerations + +There are some architectural things that are worth being aware of to design and implement custom Bot Powered ACEs the proper way: + +1. Bots are a **stateless technology** and you should always implement your logic accordingly. For example, you can't make the assumption that you can share context and state across multiple requests from the same user. Eventually, you can take care of storing state information in the response and you collect the state back from the user on the next interaction. +1. The Bot Powered ACEs are based on a **pull model**, meaning that you can't push content to Card Views or Quick Views without an explicit user's intervention. As such, you can't implement solutions that automatically update their content based on a timer or when an external trigger event occurs. You need the end users to interact with your ACE and reload its content. The refresh occurs by pressing a button in a Card View, or by interacting with an action in a Quick View, or by refreshing the whole web page if they are on a web client. +1. By default, a Bot Powered ACE **doesn't provide you with any information about the consumer tenant or user**. If you want to access information about the tenant or the user consuming your Bot Powered ACE, you have to rely on a single sign-on (SSO) enabled Bot. +1. At the time of this writing, you **can have multiple Bots and multiple dashboard cards configured** in the **manifest.json** file of a Microsoft 365 solution. Theoretically, this configuration allows for multiple Bot Powered ACEs in a single project, if you register one Azure Bot for each. However, it's important to note that in the **manifest.json** file, only one application ID can be included in the _webApplicationInfo_ section. This section is used to configure single sign-on (SSO), which is a common requirement. So, each Visual Studio project can only have one Bot Powered ACE with SSO functionality. +1. When rendering Quick Views in Bot Powered ACEs you can rely on the **AdaptiveCards.Templating** NuGet package and on a JSON template file defining an Adaptive Card, or you can use a code based and declarative approach. Keep into account that the **AdaptiveCards.Templating** NuGet package, at the time of this writing, can only parse and process JSON files with Adaptive Card definitions up to Adaptive Card schema v. 1.2, while using the declarative and code based model you can use any version of the Adaptive Card schema. +1. If you have multiple instances of the same Bot Powered ACE on the same dashboard relying on single sign-on (SSO), they can **share the same security context**. In fact, users can authenticate on one of the card instances and their security context is shared across all of the instances. However, you need to manually refresh the dashboard to make all the instances aware of the authenticated context. The same happens when a user signs out from a single card instance. You need to refresh the page to make all the other card instances aware of the unauthenticated context. diff --git a/docs/spfx/viva/bot-powered/images/ACE-Component-Based-Structure-TS.png b/docs/spfx/viva/bot-powered/images/ACE-Component-Based-Structure-TS.png new file mode 100644 index 000000000..16eaf02ed Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/ACE-Component-Based-Structure-TS.png differ diff --git a/docs/spfx/viva/bot-powered/images/ACE-Component-Based-Structure.png b/docs/spfx/viva/bot-powered/images/ACE-Component-Based-Structure.png new file mode 100644 index 000000000..bdb3eaa4c Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/ACE-Component-Based-Structure.png differ diff --git a/docs/spfx/viva/bot-powered/images/App-Catalog-Package-Publishing.png b/docs/spfx/viva/bot-powered/images/App-Catalog-Package-Publishing.png new file mode 100644 index 000000000..7c1690f2d Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/App-Catalog-Package-Publishing.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-01.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-01.png new file mode 100644 index 000000000..be921e964 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-02.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-02.png new file mode 100644 index 000000000..25488829b Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-02.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-03.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-03.png new file mode 100644 index 000000000..0e733565d Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-OAuth-Connection-Azure-Bot-03.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-01.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-01.png new file mode 100644 index 000000000..95ea559e7 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-02.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-02.png new file mode 100644 index 000000000..cc441812e Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-02.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-03.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-03.png new file mode 100644 index 000000000..b23477d42 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SPO-Web-App-Principal-03.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-01.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-01.png new file mode 100644 index 000000000..7311b9061 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-02.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-02.png new file mode 100644 index 000000000..7961400c5 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-02.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-03.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-03.png new file mode 100644 index 000000000..5f552f24e Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-03.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-04.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-04.png new file mode 100644 index 000000000..13f7f9b5d Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-04.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-05-jwt-ms-token.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-05-jwt-ms-token.png new file mode 100644 index 000000000..218046e52 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Configure-SSO-Azure-Bot-05-jwt-ms-token.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-01.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-01.png new file mode 100644 index 000000000..d238796af Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-02.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-02.png new file mode 100644 index 000000000..5be19902e Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-02.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-03.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-03.png new file mode 100644 index 000000000..39a0162fb Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-03.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-04.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-04.png new file mode 100644 index 000000000..6921a78ae Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-04.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-05.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-05.png new file mode 100644 index 000000000..6dddfd0b0 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-05.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-06.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-06.png new file mode 100644 index 000000000..50d3693ed Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-06.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-07.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-07.png new file mode 100644 index 000000000..083010f5f Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-07.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-08.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-08.png new file mode 100644 index 000000000..fedfab4f4 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-08.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-09.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-09.png new file mode 100644 index 000000000..d2eba73e8 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-09.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-09b.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-09b.png new file mode 100644 index 000000000..9e80ae62a Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-09b.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-10-TTK.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-10-TTK.png new file mode 100644 index 000000000..74addff54 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-10-TTK.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-10.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-10.png new file mode 100644 index 000000000..ee7823e53 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-10.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-11.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-11.png new file mode 100644 index 000000000..26f6b2026 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-11.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-12-TTK.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-12-TTK.png new file mode 100644 index 000000000..a869bad36 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-12-TTK.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-12.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-12.png new file mode 100644 index 000000000..ca0455aa2 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-12.png differ diff --git a/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-TTK-01.png b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-TTK-01.png new file mode 100644 index 000000000..9838e1e3a Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Azure-Portal-Create-Azure-Bot-TTK-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Architectural-Diagram.png b/docs/spfx/viva/bot-powered/images/Bot-Architectural-Diagram.png new file mode 100644 index 000000000..340626653 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Architectural-Diagram.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Adding-to-Dashboard.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Adding-to-Dashboard.png new file mode 100644 index 000000000..2dab4abce Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Adding-to-Dashboard.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-01-filled-in.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-01-filled-in.png new file mode 100644 index 000000000..9e99e40d5 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-01-filled-in.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-01.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-01.png new file mode 100644 index 000000000..04e32467e Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-02-feedback.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-02-feedback.png new file mode 100644 index 000000000..306d8439d Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-02-feedback.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-03-Quick-View.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-03-Quick-View.png new file mode 100644 index 000000000..53f57fce4 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop-03-Quick-View.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop.png new file mode 100644 index 000000000..99d43a18c Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Desktop.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-01-filled-in.jpg b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-01-filled-in.jpg new file mode 100644 index 000000000..cd639bae4 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-01-filled-in.jpg differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-01.jpg b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-01.jpg new file mode 100644 index 000000000..179c9200f Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-01.jpg differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-02-feedback.jpg b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-02-feedback.jpg new file mode 100644 index 000000000..3b4266a23 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-02-feedback.jpg differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-03-Quick-View.jpg b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-03-Quick-View.jpg new file mode 100644 index 000000000..055d6136e Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile-03-Quick-View.jpg differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile.png new file mode 100644 index 000000000..c2e85171c Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Collect-Feedback-UI-Mobile.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Secured-Consent-Multitenant.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Secured-Consent-Multitenant.png new file mode 100644 index 000000000..091258b63 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Secured-Consent-Multitenant.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Secured-UI-Desktop-Add-to-Dashboard.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Secured-UI-Desktop-Add-to-Dashboard.png new file mode 100644 index 000000000..77c7a63fd Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Secured-UI-Desktop-Add-to-Dashboard.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-Complete-Sign-In.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-Complete-Sign-In.png new file mode 100644 index 000000000..98283f971 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-Complete-Sign-In.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Desktop-SSO.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Desktop-SSO.png new file mode 100644 index 000000000..9d13b6537 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Desktop-SSO.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Desktop.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Desktop.png new file mode 100644 index 000000000..99b9fe1ad Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Desktop.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Mobile-SSO.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Mobile-SSO.png new file mode 100644 index 000000000..c7ea4b7ba Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Mobile-SSO.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Mobile.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Mobile.png new file mode 100644 index 000000000..06fdcd6a9 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACE-Welcome-User-UI-Mobile.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-Market-Place-Block.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-Market-Place-Block.png new file mode 100644 index 000000000..4444a8f1f Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-Market-Place-Block.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-Market-Place-ValidManifest.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-Market-Place-ValidManifest.png new file mode 100644 index 000000000..2befd7b69 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-Market-Place-ValidManifest.png differ diff --git a/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-SignIn-Flow-Diagram.png b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-SignIn-Flow-Diagram.png new file mode 100644 index 000000000..b5101fb54 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Bot-Powered-ACEs-SignIn-Flow-Diagram.png differ diff --git a/docs/spfx/viva/bot-powered/images/Extend-Teams-Bot-01.png b/docs/spfx/viva/bot-powered/images/Extend-Teams-Bot-01.png new file mode 100644 index 000000000..f738bbd67 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Extend-Teams-Bot-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Visual-Studio-Bot-Builder-Extension-Project.png b/docs/spfx/viva/bot-powered/images/Visual-Studio-Bot-Builder-Extension-Project.png new file mode 100644 index 000000000..b07c7ebfa Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Visual-Studio-Bot-Builder-Extension-Project.png differ diff --git a/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-Lifecycle.png b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-Lifecycle.png new file mode 100644 index 000000000..8bed67292 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-Lifecycle.png differ diff --git a/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-01.png b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-01.png new file mode 100644 index 000000000..cebb26e19 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-01.png differ diff --git a/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-02.png b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-02.png new file mode 100644 index 000000000..f8c6e21f2 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-02.png differ diff --git a/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-03.png b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-03.png new file mode 100644 index 000000000..91ccdda1d Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-03.png differ diff --git a/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-Outline.png b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-Outline.png new file mode 100644 index 000000000..535407546 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Visual-Studio-Code-TTK-New-Project-Outline.png differ diff --git a/docs/spfx/viva/bot-powered/images/Visual-Studio-NuGet-Bot-Builder-SDK-Version.png b/docs/spfx/viva/bot-powered/images/Visual-Studio-NuGet-Bot-Builder-SDK-Version.png new file mode 100644 index 000000000..f73916055 Binary files /dev/null and b/docs/spfx/viva/bot-powered/images/Visual-Studio-NuGet-Bot-Builder-SDK-Version.png differ diff --git a/docs/spfx/viva/bot-powered/publish-to-marketplace-overview.md b/docs/spfx/viva/bot-powered/publish-to-marketplace-overview.md new file mode 100644 index 000000000..050479be9 --- /dev/null +++ b/docs/spfx/viva/bot-powered/publish-to-marketplace-overview.md @@ -0,0 +1,44 @@ +--- +title: Publishing Bot Powered Adaptive Card Extensions to the market place +description: Provides details on how Bot Powered Adaptive Card Extensions can be published to the market place +ms.date: 03/25/2024 +ms.localizationpriority: high +--- + +# Publishing Bot Powered Adaptive Card Extensions to the market place + +Bot Powered Adaptive Card Extensions (ACEs) for Microsoft Viva Connections can be used to build custom experiences for the Microsoft Viva Connections Dashboard using the Bot development model. Bot Powered ACEs are an addition to the already existing Viva Connections extensibility model, which is based on SharePoint Framework (SPFx) components. + +Objective of the Bot Powered ACEs is to enable existing Microsoft Teams developers, with existing bot implementations, extend their bot implementations to be available in the Viva Connections. Bot Powered ACEs are packaged using the Microsoft Teams solution model, enabling the same bot to be used in both Microsoft Teams and in Microsoft Viva Connections. + +Because Bot Powered ACEs are packaged using the Microsoft Teams solution model they have to be submitted as Microsoft Teams solutions to the market place following the [market place guidance for Teams solutions](https://learn.microsoft.com/microsoftteams/platform/concepts/deploy-and-publish/appsource/publish). There are however some differences related to how Bot Powered ACEs deployed using the Teams solution model will show up in Viva Connections and how they can be governed. Also, currently, not all possible Bot Powered ACE Teams solutions are accepted by the market place. + +## Market place acceptance criteria for Bot Powered Adaptive Card Extensions + +Bot Powered ACEs enable existing Microsoft Teams developers, with existing bot implementations, extend their bot implementations to be available in the Viva Connections and this approach is what we support for the market place today. You can also develop stand-alone Bot Powered ACEs which have no other functional Teams component, these however will be allowed for market place submission in a later phase. So, currently, market place will only accept a Teams applications which already contains a bot implementation that's being used by the Teams application. So if your Teams application was already on the market place and you've extended your application to also offer Bot Powered ACEs then you're simply submitting an update to your existing application. Both updated and new Teams applications need to follow the [market place guidance for Teams solutions](https://learn.microsoft.com/microsoftteams/platform/concepts/deploy-and-publish/appsource/publish). + +> [!Note] +> +> - Bot Powered ACEs require the [Teams app manifest version](https://learn.microsoft.com/microsoftteams/platform/resources/schema/manifest-schema) 1.17 or higher. +> - We're working on support for bringing "stand-alone" Bot Powered ACEs to the market place and will update this guidance whenever that change happens. + +Market place acceptance criteria overview: + +- Follow the [market place guidance for Teams solutions](https://learn.microsoft.com/microsoftteams/platform/concepts/deploy-and-publish/appsource/publish) +- Use [Teams manifest version](https://learn.microsoft.com/microsoftteams/platform/resources/schema/manifest-schema) 1.17 or higher +- Have a valid Teams bot implementation (see lines 27-39) that's used as Bot Powered ACE (see line 53) + +![A snippet from a Teams application manifest showing how an existing Teams bot is used as Bot Powered ACE.](./images/Bot-Powered-ACEs-Market-Place-ValidManifest.png) + +## Making your Bot Powered ACEs available in Viva Connections + +Bot Powered ACEs that are added as part of a Teams application in market place will become automatically available as cards for adding to the Viva Connections dashboard, there's **no explicit install required** of the Teams application containing the Bot Powered ACEs. So, by default, once your Teams application containing Bot Powered ACEs is published in the market place all Viva Connection dashboard admins for all tenants will see your ACEs appearing in the card picker when they configure their Viva Connection dashboards. The Teams admin can however control ACE visibility via policies controlling app availability in Teams, this will be explained in next chapter. + +## Bot Powered ACEs governance + +Bot Powered ACEs will become automatically available as mentioned earlier, but the Teams admin does have an option to control visibility. ACEs will only show up if their Teams application has not been blocked by the Teams admin, so [allowing or blocking applications](https://learn.microsoft.com/microsoftteams/manage-apps#allow-or-block-apps) is the approach that Teams admins can use to govern ACE visibility. When a Teams application gets blocked for all users or for the user loading the Viva Connections dashboard, and ACEs were not yet used then they'll not show up in the card picker anymore and cannot be added to the dashboard. If the ACEs were already added to a Viva Connections dashboard then at runtime the respective cards simply will not show up, at design time an "error card" will be showing indicating that the card might have been removed/blocked by the Teams administrator. + +> [!Note] +> Blocking and unblocking a Teams app will not immediately see effect on the Viva Connections dashboards using the cards, it can take several hours before the impact is visible. + +![An Adaptive Card Extension showing that the card was blocked by the Teams admin.](./images/Bot-Powered-ACEs-Market-Place-Block.png) diff --git a/docs/spfx/viva/design/design-intro.md b/docs/spfx/viva/design/design-intro.md new file mode 100644 index 000000000..8943efeed --- /dev/null +++ b/docs/spfx/viva/design/design-intro.md @@ -0,0 +1,53 @@ +--- +title: Design guidance for Viva Connections cards +description: Design guidance for Viva Connections cards +ms.date: 08/28/2024 +ms.localizationpriority: high +--- +# Design guidance for Viva Connections cards + +Developers can extend [Microsoft Viva Connections](https://www.microsoft.com/microsoft-viva) for building engaging experiences with the widely adopted SharePoint Framework (SPFx). Viva Connections is your gateway to a modern employee experience where you can build and integrate apps that shape culture and foster connections to help employees thrive. With SPFx, you have multiple ways to extend – using the same out-of-the-box or custom SPFx web parts, SPFx extensions (for example header, footer), and specific components for optimized mobile experiences. + +> [!IMPORTANT] +> For the Viva Connections Desktop design guidance, please see [Designing great SharePoint experiences](/sharepoint/dev/design/design-guidance-overview). + +## Overview + +### Intro + +Use this toolkit to help you design custom cards for your dashboard. You'll learn the structure of cards, how users can interact with them, and the design principles to help you make them attractive and engaging for mobile and desktop use. + +To learn more about how to create custom cards, see [Getting Started - Adaptive Cards](/adaptive-cards/authoring-cards/getting-started). + +### What is a Dashboard? + +The Viva Connections Dashboard is the digital toolset for your employees. You can create a curated experience using dashboard cards to give your employees access to their most critical content and tools. + +The cards, called Adaptive Card Extensions (ACEs) are designed to enable quick task completion by interacting with a card directly (the Card View) or by opening a Quick View from the Card View. + +![Dashboard in mobile and in Desktop view](../../../images/viva-design/viva-design_dashboard_overview.jpg) + +## Types of cards + +ACEs are implemented using two types of cards: the Card View and an optional Quick View card(s). + +### Card View + +The Card View is the primary view for an ACE. The Card View is defined using Adaptive Cards and is rendered on the Viva Connections experience. + +![Example Viva Connections mobile layout as available in 2024](../images/viva-connections-mobile-and-tablet.png) + +### Quick View + +The Quick View card is displayed when a user performs an action, such as selecting a button on the Card View. The Quick View enables users to take action or view additional information about the content shown in a Card View. + +![Screenshot of the search card, primary button, and secondary button interactions.](../../../images/viva-design/img-search-template.png) + +Quick View cards can be implemented using Adaptive Cards or using HTML. + +## Resources + +- [Sample Adaptive Cards for Viva Connections](https://aka.ms/adaptivecards/samples) +- [Fluent UI](https://developer.microsoft.com/fluentui#/) +- [Fluent Theme designer](https://fluentuipr.z22.web.core.windows.net/heads/master/theming-designer/index.html) +- [AC Designer](https://adaptivecards.io/designer/) diff --git a/docs/spfx/viva/design/designing-card.md b/docs/spfx/viva/design/designing-card.md new file mode 100644 index 000000000..973be4535 --- /dev/null +++ b/docs/spfx/viva/design/designing-card.md @@ -0,0 +1,199 @@ +--- +title: Dashboard cards design guidance +description: Design guidance for the Viva Connections custom cards +ms.date: 08/28/2024 +ms.localizationpriority: high +--- +# Designing Viva Connections custom cards for your dashboard + +## Principles + +Cards are used to link resources, surface information, and power direct interaction with applications. + +**Integrate rather than duplicate:** Take advantage of the experiences already available on your intranet, such as task assignments and completion, shift schedules, company policies, and more. + +**Stay in context:** Design cards to avoid making users jump around to different experiences. For example, it's ideal if you can keep interactions within the Viva Connections app using the [Quick View](design-intro.md#quick-view). The next best is to keep user interactions within the dashboard. + +**Bring cards to life with relevant and dynamically refreshable data:** Company stock price, due dates for training or projects, task assignment updates, and remaining vacation days are some examples. + +:::image type="content" source="../../../images/viva-design/img-card-design2.gif" alt-text="Moving image that shows the process of clocking in for a shift."::: + +## Anatomy of cards + +The Connections dashboard is made up of cards that each serve a specific purpose. Each card is a container and is composed of the following sections and elements: + +**Medium card Layout:** + +:::image type="content" source="../../../images/viva-design/img-medium-card-layout.png" alt-text="Diagram showing the medium card container and card elements, showing the time off and paid time-off available options."::: + +**Large card layout:** + +:::image type="content" source="../../../images/viva-design/img-large-card-layout.png" alt-text="Diagram showing the large card container and card elements, showing the time off and paid time-off available options."::: + +The first section is the **card bar**, which includes the card’s icon and title. + +- **Icon**: Unique visual representation of this card. You can choose the icon from the pre-defined set or upload a customized icon. + + > [!NOTE] + > For customized icons, the maximum size is 24 px by 24 px. Recommended formats are PNG or SVG. SVG icons scale better across different screen resolutions. Make sure the icon has a transparent background, and it looks good both on light and dark themes. + +- **Title**: Typically the app name. All titles should be in sentence case. + +The second section is the **header**, which will be the most prominent words on the card. + +- This content is likely to be read first. It's used to communicate the most information and keywords. Heading text can be static or dynamically updated. All headings should be in sentence case. + +The third section is referred to as the **body**. + +- The body can contain elements such as text input, a search box, or a text description. + + > [!NOTE] + > Use text when the description can add valuable secondary informational value to the heading and can make it easier to understand the purpose of the card. Avoid repeating information already communicated in the heading. + +Finally, the last section of the card is the **footer**. + +- The footer section can contain an action button, text input, or a search footer. + +## Card components and layouts + +As part of the SPFX 1.18, we introduced card components to enhance Adaptive Card Extension layouts. These components are the building blocks of card layouts, representing individual elements within a card. Here are **card components** available: + +- Card Bar Component +- Text +- Text input +- Action button +- Search box +- Search footer + +With the card components approach, we provide two types of card layout templates, each offering developers varying degrees of flexibility and customization: + +1. **Generic card layout template** + 1. The generic card template serves as a foundational or base card with no predefined elements/ components. + 1. Developers can utilize this template to fully customize card design layouts according to their specific needs. +1. **Scenario-focused card layout template** + 1. Scenario-focused templates are designed to address specific customer needs, delivering tailored solutions for distinct scenarios. + 1. These templates come with pre-built user experiences, enabling developers to initiate their projects swiftly and effortlessly. + +### Generic card layout template + +While the generic card layout offers developers significant flexibility in customizing the card design, we have established a specific set of component combinations in accordance with our design language and guidelines. This approach not only ensures adherence to our design principles but also guarantees a superb user experience for our customers. + +**Examples of the generic card with an image (Allowed combinations)** + +| Combination | Card bar | Header | Body | Footer | Notes | Sample Card | +|:-----------: |:--------: |:------------: |:-----: |:-------: |--------------------------------------- |------------- | +| 1 | Yes | Text | Empty | Action button | Previously known as the Image template | :::image type="content" source="../../../images/viva-design/img-permutation-01-card-layout.png" alt-text="Generic card with image permutation 1."::: | +| 2 | Yes | Text | Empty | Empty | Previously known as the Image template | :::image type="content" source="../../../images/viva-design/img-permutation-02-card-layout.png" alt-text="Generic card with image permutation 2."::: | +| 3 | Yes | Text | Empty | Text Input | New layout | :::image type="content" source="../../../images/viva-design/img-permutation-03-card-layout.png" alt-text="Generic card with image permutation 3."::: | +| 4 | Yes | Text | Text input | Action Button | New layout | :::image type="content" source="../../../images/viva-design/img-permutation-04-card-layout.png" alt-text="Generic card with image permutation 4."::: | +| 5 | Yes | Text | Text input | Empty | New layout | :::image type="content" source="../../../images/viva-design/img-permutation-05-card-layout.png" alt-text="Generic card with image permutation 5."::: | + +> [!NOTE] +> When using images on a card, note: Images draw the viewer's eye, so use images carefully either to create recognition of a familiar app or website or increase the overall visual prominence of the card on the dashboard. The image should meaningfully connect to the heading and/or title. + + +**Examples of generic cards without images (Allowed combinations)** + +| Combination | Card bar | Header | Body | Footer | Notes | Sample Card | +|:-----------: |:--------: |:------------: |:-----: |:-------: |--------------------------------------- |------------- | +| 1 | Yes | Text | Empty | Action button | Previously known as the Basic Text | :::image type="content" source="../../../images/viva-design/img-examples-01-card-withoutimage.png" alt-text="Generic card without image permutation 1."::: | +| 2 | Yes | Text | Empty | Empty | Previously known as the Basic Text | :::image type="content" source="../../../images/viva-design/img-examples-02-card-withoutimage.png" alt-text="Generic card without image permutation 2."::: | +| 3 | Yes | Text | Empty | Text Input | New layout | :::image type="content" source="../../../images/viva-design/img-examples-03-card-withoutimage.png" alt-text="Generic card without image permutation 3."::: | +| 4 | Yes | Text | Text | Action Button | Previously known as the Primary Text | :::image type="content" source="../../../images/viva-design/img-examples-04-card-withoutimage.png" alt-text="Generic card without image permutation 4."::: | +| 5 | Yes | Text | Text | Empty | Previously known as the Primary Text | :::image type="content" source="../../../images/viva-design/img-examples-05-card-withoutimage.png" alt-text="Generic card without image permutation 5."::: | +| 6 | Yes | Text | Text | Text Input | New layout | :::image type="content" source="../../../images/viva-design/img-examples-06-card-withoutimage.png" alt-text="Generic card without image permutation 6."::: | +| 7 | Yes | Text | Text input | Action Button | New layout | :::image type="content" source="../../../images/viva-design/img-examples-07-card-withoutimage.png" alt-text="Generic card without image permutation 7."::: | +| 8 | Yes | Text | Text input | Empty | New layout | :::image type="content" source="../../../images/viva-design/img-examples-08-card-withoutimage.png" alt-text="Generic card without image permutation 8."::: | + +> [!NOTE] +> Search box and search footer components can't be used in generic card template layout. + +#### Recommended best practice for the generic card layout template and components + +- When adding the text in the heading and body sections, ensure the text doesn't truncate and can fit in the card width on both desktop and mobile in both card sizes and all languages used. Truncated text can hide key information that might be necessary for the end user to complete the task. For the header, in most cases, a length of 10-12 characters should fit the card width well. +- Whenever you use a text input component, we highly recommend adding an icon button. Although we allow an icon before and an icon after the text input component, we recommend using one icon to clearly communicate the intent of the card. + + > [!NOTE] + > The icon before the text input disappears once the textbox is active. + +- Generally, we don't recommend using text input with an action button AND extra action buttons in the footer BUT if there's a text input with a button AND extra buttons in the footer - we recommend using a secondary button style (default or undefined value for the button style property) +- Although we do support the entire card being clickable, we don't recommend having a selection action on a card if there's a text input in the body or it's a search card. This won't provide a great user experience +- While we do allow the entire card to be clickable, we strongly advise against enabling selection actions on a card if it contains text input in the body or is a search card template. Doing so will result in a suboptimal user experience. + +### Scenario-focused card layout template + +#### Search template + +This scenario-focused card template allows developers to quickly create a search experience for the users. Examples include people, messages or chats, files etc. + +:::image type="content" source="../../../images/viva-design/img-search-template.png" alt-text="Screenshot of the search card, primary button, and secondary button interactions."::: + +## Interaction + +There are three possible ways to interact with a card: + +- Card (the entire card can be clickable) +- Primary button +- Secondary button + +:::image type="content" source="../../../images/viva-design/img_card_interactions.jpg" alt-text="Screenshot of the image card, primary button, and secondary button interactions."::: + +Each of these interactions can be customized. Use these to perform an instant action, send a request to the server, open a [Quick View](design-intro.md#quick-view), link to a Teams app, open an external website and so on. + +Here are the best practices for designing card interactions: + +- The overall card should always be interactive. +- If the primary button is used, because of its visual prominence, it should be the most important action on the card. +- The secondary button can used either on its own or with the primary button if two actions are needed (only available in large-size card layouts). If it's used with the primary button, make sure it's linked to the second most important action on the card. In that case, the card itself will become the least important action. +- For button labels, use concise and clear text that accurately reflects button behavior. For example 'View tasks' can be better than only 'View'. +- Make sure each interaction on the card is unique. +- Design cards to avoid making users jump around to different experiences. For example, it's ideal if you can keep interactions within the Viva Connections app using the Quick View. The next best is to keep user interactions within the dashboard. + +> [!NOTE] +> Due to lack of space: +> +> - Heading + Image layout does not have buttons with medium size cards. +> - Heading and Heading + Description layouts can only have one button with medium size cards. + +### Examples + +​​​​​​​Here are some example cards for how these layouts can be used + +:::image type="content" source="../../../images/viva-design/img_card_collections.jpg" alt-text="Screenshot showing various example cards, including cards for Shifts, Tasks, COVID 19, and Tutorials."::: + +## Platforms and modes + +Dashboard cards are supported on iOS, Android, and Web. However, there are slight differences in the styling between different platforms – fonts (Segoe UI for desktop, Roboto for Android, SF Display Pro for iOS), colors, sizes, and spacing are slightly tweaked to better suit the respective platform and make the cards look consistent with the overall experience of that platform. + +:::image type="content" source="../../../images/viva-design/img_card_platforms.jpg" alt-text="Screenshot showing how the same card appears on web, iOS, and Android platforms."::: + +Dashboard cards also support both light and dark mode themes. Ensure that the colors you use work for both modes – text should be legible, and buttons and icons should be clearly recognizable against the background. To meet accessibility criteria, text should have a color ratio of 4.5:1 against the button background, and non-text components like icon should have a color ratio of 3:1 against the background. [Use this tool to check color contrast](https://fluentuipr.z22.web.core.windows.net/heads/master/theming-designer/index.html). + +:::image type="content" source="../../../images/viva-design/img_card_modes.jpg" alt-text="Screenshot that shows how the same card appears in light mode versus how it appears in dark mode."::: + +### Displaying your app in the toolbox + +New cards are added to that dashboard using the following toolbox. + +:::image type="content" source="../../../images/viva-design/img_card_toolbox.jpg" alt-text="Screenshot of the Relecloud screen showing the Dashboard, which displays various tools."::: + +To display your custom app in the dashboard picker, you'll need the following: + +:::image type="content" source="../../../images/viva-design/img_card_toolbox2.jpg" alt-text="Screenshot of the dashboard with a focus on the icon, title, and descriptive text for each tool in the dashboard."::: + +1. **Icon:** Unique visual representation of this app. Your custom icon maximum size is 24px by 24px and should preferably in PNG or SVG format. SVG icons scale better across different screen resolutions. It's preferable to use a monochromatic icon, but you can use color icons if you want to represent your unique brand with the icons. Either way, make sure the icon has a transparent background, and it looks good both on light and dark theme. [​​​​​​​Learn about SharePoint themes](/sharepoint/dev/declarative-customization/site-theming/sharepoint-site-theming-overview). The same icon is to be used for the dashboard card (see above). +1. **Title:** Make sure the title of the app is concise and isn't truncated. Recommended length is 10-12 characters. The same title should be used for the dashboard card (see above) and the Quick View (if used). If you have multiple apps, it's recommended that each app has a unique title. All titles should be in sentence case. +1. **Descriptive text:** A clear, concise description explains the purpose of the card and provides information about how to use it. It should show up in the tooltip on hover (in web). Make sure the text wraps appropriately and isn't too wide or too narrow in the tooltip. The optimal line length is considered to be 50-60 characters per line, including spaces. + +### Defining settings for the card + +When the app is clicked, the card is displayed on the dashboard. The card can be edited using the settings panel on the right. + +:::image type="content" source="../../../images/viva-design/img_card_settings.jpg" alt-text="Screenshot of the Rerecloud application showing an edit pane that allows the user to edit the title, heading, and description of a card."::: + +Here are some best practices for offering customization settings: + +- Include descriptive text that explains the purpose of the card and provides information about how to use it. Ensure that this is either the same text as the tooltip or adds to it. +- Unless the text on the card is dynamically updated, allow users to edit the text on the card to tailor it to their needs. Consider providing prewritten default text in the fields that the user can override and edit as necessary. +- If multiple cards are available from the same organization, ensure that labels and interactions in the settings panel are consistent across all the cards. +- If there are multiple settings and the card is complex in design, it's recommended to add a "Learn more" link where users can find best practices for adding your card to their dashboard, for example, recommended size, example cards, and so on. diff --git a/docs/spfx/viva/design/designing-quick-view.md b/docs/spfx/viva/design/designing-quick-view.md new file mode 100644 index 000000000..d461d3e47 --- /dev/null +++ b/docs/spfx/viva/design/designing-quick-view.md @@ -0,0 +1,105 @@ +--- +title: Quick View design guidance +description: Design guidance for the Viva Connections Quick Views +ms.date: 06/13/2022 +ms.localizationpriority: high +--- +# Designing Viva Connections Quick Views + +## Principles + +Create Quick Views to provide a bit more detailed information (for example: a detailed list with data) or to accomplish quick tasks (for example a simple form) without opening an app. + +Here are a few examples of Quick Views: + +:::image type="content" source="../../../images/viva-design/img_quickviews.jpg" alt-text="Screenshot of various examples of Quick Views."::: + +> [!TIP] +> Sample adaptive card designs for the Quick Views are available from [GitHub](https://github.com/pnp/AdaptiveCards-Templates) + +The Quick View experience works across different platforms and form-factors based on a single JSON. This introduces certain limitations in terms of available styling and placement on controls. You should not expect identical or pixel perfect comparison of a Quick View rendered on web / iOS or Android. + +> [!TIP] +> JSON is an open standard file format and data interchange format that uses human-readable text to store and transmit data objects consisting of attribute–value pairs and arrays (or other serializable values). It is a common data format with a diverse range of functionality in data interchange including communication of web applications with servers. JSON is a language-independent data format. It was derived from JavaScript, but many modern programming languages include code to generate and parse JSON-format data. JSON filenames use the extension .json. + +## Layout + +:::image type="content" source="../../../images/viva-design/img_quickview_layout.jpg" alt-text="Screenshot of a card with a focus on the header and content area, which includes containers, elements, and inputs."::: + +1. Header + 1. Dismiss Quick View + 1. Card name​​​​​​​, defined by the Dashboard card title + 1. Open linked app (optional)​​​​​​​ +1. Content area - Scrollable, can contain the following elements defined by Adaptive cards schema: + 1. Containers + 1. Container + 1. ImageSet + 1. FactSet + 1. ColumnSet + 1. Table + 1. Elements + 1. TextBlock + 1. RichTextBlock + 1. Image + 1. Media + 1. ActionSet + 1. Inputs + 1. Input.Text + 1. Input.Date + 1. Input.Time + 1. Input.Number + 1. Input.ChoiceSet + 1. Input.Toggle + +## Interaction + +Quick Views are vertically scrollable independent of the rest of the underlying interface and should not be horizontally scrolled. + +### Back stack + +Avoid adding too many navigation levels within the Quick View. It's best to keep it simple so that it's easy for users to accomplish their task quickly. + +While you can open several children Quick Views from the parent Quick View, we recommend not to navigate more than one level down. + +:::image type="content" source="../../../images/viva-design/img_quickview_backstack.gif" alt-text="Moving image of accessing the registration form task which leads to the registration F A Q card."::: + +### Quick Views vs Web views + +Despite being visually similar, they are two different surfaces for different use cases. + +:::image type="content" source="../../../images/viva-design/img_quickview_webview.jpg" alt-text="Screenshot of the registration form card and of a web browser tab of Microsoft dot com."::: + +#### Quick View + +This UI surface is built using JSON code. Serves as a mean to perform fast actions or fill pout simple forms or render more information with faster load times compared to a web page called via Web view. + +#### Web view + +Can be used to load web pages with everything they can offer including more complex layouts and better styles, can be way slower to load than a than Quick View. + +Any web page opened on mobile is going to be rendered within a web view, while it's going to be a new browser tab if opened on SharePoint. + +## Theming + +### We​​​​​​​b + +Quick Views will follow SharePoint default and custom company-created themes. + +:::image type="content" source="../../../images/viva-design/img_quickview_web_theme.jpg" alt-text="Screenshot that shows how a Card Viewed on webpages appears in light mode and dark mode."::: + +### Mobile + +Currently dark themes are not supported for Quick Views on iOS and Android mobile. + +:::image type="content" source="../../../images/viva-design/img_quickview_ios_theme.jpg" alt-text="Screenshot that shows how a Card Viewed on mobile appears in light mode and dark mode."::: + +We plan to introduce dark theme support in Quick View in Viva Connections Mobile for both iOS and Android in early Q4 of CY23. ([`context.sdks.microsoftTeams.teamsJs.app.getContext()`](/javascript/api/sp-adaptive-card-extension-base/ipartialsdks)) to get the theme in which Quick View is rendered of the Quick View will be available in SPFx 1.18.1 package. + +:::image type="content" source="../../../images/viva-design/img_quickview_new_ios_theme.png" alt-text="Screenshot that shows how a card quickview viewed on mobile will appear in light mode and dark mode."::: + +> [!IMPORTANT] +> Please test your existing cards using [Adaptive Card designer](https://adaptivecards.io/designer) to make sure that the icons and images used in light mode for Quick View of the existing cards are compatible with dark mode as some discrepancies have been observed. Tenant admins will also be able to test their card Quick Views in dark mode. To update your card for the new theming, please follow the tutorial [**'Making your Quick View compatible with Dark Mode in Mobile'**](../get-started/making-quickview-compatable-darkmode-mobile.md). + +### Behavior for links and Single sign-on + +For some cards, you will use links to URLs. Depending on the location of the content, links to URLs may display content in Microsoft Teams or elsewhere and Single sign-on (SSO) behavior can differ. Get more information about how links to URLs and SSO behave depending on the location of the content you are linking to. [Learn more](/viva/connections/create-dashboard#how-urls-and-single-sign-on-works) diff --git a/docs/spfx/viva/design/quick-view-samples.md b/docs/spfx/viva/design/quick-view-samples.md new file mode 100644 index 000000000..9240b6610 --- /dev/null +++ b/docs/spfx/viva/design/quick-view-samples.md @@ -0,0 +1,109 @@ +--- +title: Viva Connections Adaptive Card Extension Quick View samples +description: Provides Viva Connections Adaptive Card extension Quick View samples and outlines various GitHub samples for Quick View templates. +ms.date: 06/13/2022 +ms.localizationpriority: high +--- + +# Viva Connections Adaptive Card Extension Quick View samples + +You can find 12 different Quick View samples for the Viva Connections Adaptive Card extensions provided by Microsoft. These samples can be used for inspiration on how the Quick Views could look like. Samples can be reused and copied to your own solutions. + +> [!TIP] +> Sample adaptive card designs for the Quick Views are available from [GitHub](https://github.com/pnp/AdaptiveCards-Templates) + +## News and article listing + +Design for presenting news and company updates with numerous referenced articles or posts. This design is for showcasing Quick View design option with the Viva Connections dashboard. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/benefits) + +:::image type="content" source="../../../images/viva-design/samples/benefits.png" alt-text="Benefits sample"::: + +## Event schedule + +Design for listing two day event schedule in a tab with optionally visible form for the attendee registration. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/event-schedule) + +:::image type="content" source="../../../images/viva-design/samples/events.png" alt-text="Events sample"::: + +## FAQ accordion + +Design for showing Frequently Asked Questions in Accordion style. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/faq-accordion) + +:::image type="content" source="../../../images/viva-design/samples/faq.png" alt-text="FAQ sample"::: + +## Image carousel with product details + +Design for presenting product information in image carousel style format. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/image-carousel) + +:::image type="content" source="../../../images/viva-design/samples/image-carousel.png" alt-text="Image Carousel"::: + +## Inventory details + +Design for presenting inventory details from warehouse. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/inventory) + +:::image type="content" source="../../../images/viva-design/samples/inventory.png" alt-text="Screenshot of a sample inventory details card from a warehouse, showing Distribution center number 73's top selling items."::: + +## Payslip + +Design for showing payslip details in adaptive card format. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/payslip) + +:::image type="content" source="../../../images/viva-design/samples/payslip.png" alt-text="Screenshot of payslip details populating in an adaptive card format."::: + +## Simple list with praise information + +Design for showing simple list of people in praise scenario. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/simple-list) + +:::image type="content" source="../../../images/viva-design/samples/praise.png" alt-text="Screenshot of a card reading Send praise to your colleagues."::: + +## Team calendar + +Design for showing calendar format and upcoming team events. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/team-calendar) + +:::image type="content" source="../../../images/viva-design/samples/teamcalendar.png" alt-text="Screenshot of the sample team calendar, showing upcoming team events for October 2021."::: + +## Timeline events + +Design for showing a timeline with upcoming events. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/timeline-holidays) + +:::image type="content" source="../../../images/viva-design/samples/holidays.png" alt-text="Screenshot of a sample timeline event card, showing the Thanksgiving and Christmas Eve events in 2021."::: + +## Vacation / time off + +Design for showing current balance on the time off days and a form to submit a request for a vacation. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/timeoff) + +:::image type="content" source="../../../images/viva-design/samples/timeoff.png" alt-text="Time off"::: + +## Vaccination booster appointment booking + +Design for booking vaccination booster appointment with images and a submission form. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/vaccination-booster) + +:::image type="content" source="../../../images/viva-design/samples/vaccination.png" alt-text="Screenshot of the Living Well Health Center and Pharmacy providing information on scheduling a free COVID-19 booster appointment."::: + +## Visual list with cafeteria menu scenario + +Design for a visual list with the cafeteria scenario details, including two tab presentation. + +* Sample at [GitHub](https://github.com/pnp/AdaptiveCards-Templates/tree/main/samples/visual-list) + +:::image type="content" source="../../../images/viva-design/samples/visual-list.png" alt-text="Visual List"::: diff --git a/docs/spfx/viva/features/card-designer/card-designer-api-support.md b/docs/spfx/viva/features/card-designer/card-designer-api-support.md new file mode 100644 index 000000000..ef77abc30 --- /dev/null +++ b/docs/spfx/viva/features/card-designer/card-designer-api-support.md @@ -0,0 +1,74 @@ +--- +title: Overview of Viva Connections Card Designer advance API features +description: Viva Connections Card Designer advance API feature enables Viva Connection dashboard editors to create API powered experiences without code. +ms.date: 12/13/2023 +ms.localizationpriority: high +--- +# Overview of Viva Connections Card Designer advance API features + +Advance API features for the Viva Connections Card Designer enable the dashboard editors to create API powered Quick View experiences without actual code. This new option is supported with all the different form factors or Viva Connections dashboard - mobile, tablet and desktop. + +> [!IMPORTANT] +> First version of this feature is rolling out worldwide by end of the 2023 calendar year. User interface for Card designer will be further evolved within early 2024 for a better end user experience with the advance API features. + +## Enabling feature in the tenant + +By default this feature isn't currently available in the tenants and it has to be enabled by using SharePoint Online Management Shell with following command. + +```powershell +Set-SPOTenant -IsDataAccessInCardDesignerEnabled $true +``` + +> [!IMPORTANT] +> You'll need to use [SharePoint Online PowerShell](https://www.powershellgallery.com/packages/Microsoft.Online.SharePoint.PowerShell/16.0.24322.12000) version 16.0.24308.12000 or newer to have this option available in the `Set-SPOTenant` cmdlet. + +If this setting isn't enabled in the tenant, you see following message in the Card Designer property pane: `Advance features have not been enabled by an administrator`. + +When the feature is enabled, you see new options visible as a Data source in the **Data source** selection as shown in following image. + +![API options in the Data source selection in the webpart toolbox](./img/data-source-api-options.png) + +## Managing available API permissions + +To be able to use the API features, you'll need to grant the available API permissions in the Entra app management. Card designer feature uses the same app registration as the [SharePoint Framework (SPFx) solutions](https://aka.ms/spfx), so any API that is approved for the SharePoint Framework solutions, will be also available to be used in the Card Designer. + +If you try to use the API features in the Card Designer, you'll see following exception in the property pane: `Cannot make any requests to Microsoft Graph as the SharePoint Online Client Extensibility Web Application Principal is not configured or consented to.` + +Needed permissions can be also granted directly to the SharePoint Framework extensibility app registration in the Entry Applications with following steps. + +1. Move to the API management page in the SharePoint administration - first time you access this page, the needed app registrations are automatically created to the tenant. + + ![API access page in the SharePoint admin center](./img/sharepoint-admin-api-management.png) + +1. Move the Microsoft Entra admin center to confirm that the needed app registrations are available. + + ![Microsoft Entra admin center app registration](./img/entra-app-registration.png) + +1. Move to the **SharePoint Online Client Extensibility Web Application Principal** registration and include the needed permissions, which you'd like to be available for the dashboard editors when they use Card Designer feature. + + ![Microsoft Entra admin center app permissions](./img/entra-app-permissions.png) + +Notice that after you granted the permissions in the Microsoft Entra admin center, the matching permissions are also visible in the API management page in the SharePoint admin center. + +## Using dynamic API data in the Card Designer + +When the needed API permissions are available, dashboard designer can use the API features to get dynamic content based on the user identity. As an example, you could use the following Microsoft Graph endpoint to get the following events for the particular user. + +```text +https://graph.microsoft.com/v1.0/me/events?$take=5&$select=id,webLink,subject,start,end,location +``` + +Combining that API call with a custom adaptive card presentation, you could, for example, present the user's upcoming meetings with following Quick View rendering. + +![Screenshot of an ACE Quick View showing upcoming meetings](./img/quick-view-upcoming-meetings.png) + +> [!TIP] +> You can use the [Microsoft Graph Explorer](https://developer.microsoft.com/graph/graph-explorer) to see the different available APIs from Microsoft Graph and their output in JSON. Using that output with [Adaptive Card Designer](https://adaptivecards.io/designer/), you can easily create powerful experiences with the Card Designer advance API features. + +## References + +- [YouTube - Introduction to new advance API features in Viva Connections Card Designer](https://www.youtube.com/watch?v=NjZj1F6D6jw) +- [Viva Connections Card designer](/viva/connections/create-dashboard#design-your-own-card-with-a-quick-view) +- [Microsoft Graph Explorer](https://developer.microsoft.com/graph/graph-explorer) +- [Adaptive Card Designer](https://www.adaptivecards.io/designer/) +- [SharePoint Online Management Shell](/powershell/sharepoint/sharepoint-online/connect-sharepoint-online) diff --git a/docs/spfx/viva/features/card-designer/img/card-solution-in-app-catalog.png b/docs/spfx/viva/features/card-designer/img/card-solution-in-app-catalog.png new file mode 100644 index 000000000..3fbc33506 Binary files /dev/null and b/docs/spfx/viva/features/card-designer/img/card-solution-in-app-catalog.png differ diff --git a/docs/spfx/viva/features/card-designer/img/data-source-api-options.png b/docs/spfx/viva/features/card-designer/img/data-source-api-options.png new file mode 100644 index 000000000..b9e7e3e90 Binary files /dev/null and b/docs/spfx/viva/features/card-designer/img/data-source-api-options.png differ diff --git a/docs/spfx/viva/features/card-designer/img/entra-app-permissions.png b/docs/spfx/viva/features/card-designer/img/entra-app-permissions.png new file mode 100644 index 000000000..496bc6de6 Binary files /dev/null and b/docs/spfx/viva/features/card-designer/img/entra-app-permissions.png differ diff --git a/docs/spfx/viva/features/card-designer/img/entra-app-registration.png b/docs/spfx/viva/features/card-designer/img/entra-app-registration.png new file mode 100644 index 000000000..95b9df117 Binary files /dev/null and b/docs/spfx/viva/features/card-designer/img/entra-app-registration.png differ diff --git a/docs/spfx/viva/features/card-designer/img/quick-view-upcoming-meetings.png b/docs/spfx/viva/features/card-designer/img/quick-view-upcoming-meetings.png new file mode 100644 index 000000000..c3b385049 Binary files /dev/null and b/docs/spfx/viva/features/card-designer/img/quick-view-upcoming-meetings.png differ diff --git a/docs/spfx/viva/features/card-designer/img/sharepoint-admin-api-management.png b/docs/spfx/viva/features/card-designer/img/sharepoint-admin-api-management.png new file mode 100644 index 000000000..dc75eb443 Binary files /dev/null and b/docs/spfx/viva/features/card-designer/img/sharepoint-admin-api-management.png differ diff --git a/docs/spfx/viva/features/focus-feature/FocusFeatureDocumentation.md b/docs/spfx/viva/features/focus-feature/FocusFeatureDocumentation.md new file mode 100644 index 000000000..9722c7c96 --- /dev/null +++ b/docs/spfx/viva/features/focus-feature/FocusFeatureDocumentation.md @@ -0,0 +1,100 @@ +--- +title: Focus feature in Adaptive Card Extension +description: The focus feature allows developers to determine focus of elements in the Quick View. +ms.date: 04/04/2023 +--- +# Focus feature in Adaptive Card Extension + +Microsoft added support for the focus feature, unique to Viva Connections, in the [SharePoint Framework (SPFx) v1.17](../../../release-1.17.md) release. + +> [!NOTE] +> This tutorial also assumes that you've already built an SPFx Adaptive Card Extension. +> +> To learn how to create your first SPFx Adaptive Card Extension, see [Build your first SharePoint Adaptive Card Extension](../../get-started/build-first-sharepoint-adaptive-card-extension.md). + +## Focus Feature + +Just like the way that developers can set a template and data via `get data()` and `get template()`, users will be able to hook into a new getter method that will allow them the flexibility to pass in an initial focus element on each render. If implementation isn't provided by developer, then a focus on the first tab-able element will be set. + +```typescript +/** + * An optional focus element to set focus when the view is rendered for accessibility purposes. + * @remarks If not overriden, the focus element defaulted to the first actionable element of the Quick View. + * + * @virtual + */ + public get focusParameters(): IFocusParameters | undefined { + return undefined; + } +``` + +This new function allows developers to customize what the focus element is by returning `IFocusParameters`. The return values are as follows: + +- `focusTarget`: Set to the root element of the Quick View by default. +- `ariaLive` [OPTIONAL]: Determines reading priority from a screen reader standpoint. Set to off by default. + +```typescript +{ + /** + * Sets the default focus on the DOM. Developers pass in the id of a unique element that is to attain focus within a Quick View. + * If the `focusTarget` is not defined then the root element is selected. + */ + focusTarget: string | undefined; + + /** + * Sets the accessibility reading of the contents within the focus target. + * Polite - Content in the target's subtree is read when the user is idle. + * Assertive - Disrupts any announcement in favor of the changed contents within the target's subtree. + * Off - The screen reader will not read contents within the target's subtree. + */ + ariaLive?: 'polite' | 'assertive' | 'off'; +} +``` + +## Tutorial and Examples + +You can take a look at [this tutorial](./FocusFeatureTutorial.md), which goes over a step by step guide on how to create a card with the available media upload action. + +1. **Read target information after once user is idle** + + In your `focusParameters` function, return the following object: + + ```javascript + { + focusTarget: myFocusTarget, + ariaLive: 'polite' + } + ``` + +1. **Read target information immediately** + + In your `focusParameters` function, return the following object: + + ```javascript + { + focusTarget: myFocusTarget, + ariaLive: 'assertive' + } + ``` + +1. **Read all contents of the Quick View** + + In your template json file, add the following action: + + In your `focusParameters` function, return the following object: + + ```javascript + { + focusTarget: undefined, + ariaLive: 'assertive' + } + ``` + +## Availability of focus feature + +> [!NOTE] +> Currently this feature is not supported in teams mobile. + + Action | Viva Connection Desktop | Viva Connections Mobile | Browser +------------- | ----------------------- | ----------------------- | --------- +Focus Feature | Supported | Not Supported | Supported diff --git a/docs/spfx/viva/features/focus-feature/FocusFeatureTutorial.md b/docs/spfx/viva/features/focus-feature/FocusFeatureTutorial.md new file mode 100644 index 000000000..6759343ec --- /dev/null +++ b/docs/spfx/viva/features/focus-feature/FocusFeatureTutorial.md @@ -0,0 +1,318 @@ +--- +title: Create an Adaptive Card Extension with the focus feature +description: Step by step guide on how to create an Adaptive Card Extension with the focus feature. +ms.date: 12/14/2023 +ms.localizationpriority: high +--- +# Create an Adaptive Card Extension with focus feature + +## Scaffold an Adaptive Card Extension project + +Create a new project directory for your project and change your current folder to that directory. + +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (select the default option for all prompts omitted below): + +- **What is your solution name?** focus-feature +- **Which type of client-side component to create?** Adaptive Card Extension +- **Which template do you want to use?** Geneic Card Template +- **What is your Adaptive Card Extension name?** HelloWorld + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This process might take few minutes. + +Before moving forward, update the `title` and `description` fields of your ACE to give it a personal touch. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx/adaptive-card-extension-manifest.schema.json", + "id": "2c2fb587-a351-40f9-83f7-0840e3ee857f", + "alias": "HelloWorldAdaptiveCardExtension", + "componentType": "AdaptiveCardExtension", + + // The "*" signifies that the version should be taken from the package.json + "version": "*", + "manifestVersion": 2, + + // 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": ["Dashboard"], + "preconfiguredEntries": [{ + "groupId": "bd067b1e-3ad5-4d5d-a5fe-505f07d7f59c", // Dashboard + "group": { "default": "Dashboard" }, + "title": { "default": "Focus feature advanced I" }, + "description": { "default": "Focus feature advanced I" }, + "iconImageUrl": "https://res.cdn.office.net/files/fabric-cdn-prod_20230308.001/assets/brand-icons/product-monoline/svg/vivaconnections_32x1.svg", + "properties": { + "title": "Focus feature advanced I" + }, + "cardSize": "Large" + }] +} +``` + +Next, run **gulp serve** from the command line in the root of the project to start the build and debugging process. In the hosted workbench, you'll see the **FocusFeature** card: + +![See the FocusFeature card icon in the webpart toolbox](./img/focusFeatureTutorialACE.png) + +## Add focus feature to your Adaptive Card Extension Quick View + +At this point, we have out of the box Adaptive Card Extension code. Now it's time to flare things up with focusing on elements in the Quick View. + +In the Quick View, we'll introduce buttons for two actions: + +- Move to the next Quick View +- Move to the previous Quick View + +We'll first define the template of the Quick View. For this, locate and open the following file in your project: **./src/adaptiveCardExtensions/focusFeature/quickView/template/QuickViewTemplate.json** + +Replace the content of this file as below: + +```json +{ + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "TextBlock", + "weight": "Bolder", + "text": "${title}", + "id": "quick-view-title" + }, + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "weight": "Bolder", + "text": "${subTitle}", + "id": "quick-view-sub-title", + "wrap": true + } + ] + } + ] + }, + { + "type": "ActionSet", + "actions": [ + { + "type": "Action.Submit", + "title": "Forward skip update", + "data": { + "id": "forward-skip" + } + }, + { + "type": "Action.Submit", + "title": "Forward", + "data": { + "id": "forward" + } + }, + { + "type": "Action.Submit", + "title": "Back", + "data": { + "id": "back" + } + } + ] + } + ] +} +``` + +Next let's implement the logic that will allow us to navigate to the next Quick View. We'll use the QuickViewNavigator to manipulate the view stack. + +```typescript +public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id } = action.data; + if (id === 'back') { + this.quickViewNavigator.pop(); + } else if (id === 'forward-skip') { + this.quickViewNavigator.push(QUICK_VIEW_REGISTRY_ID_2, true); + } else { + this.quickViewNavigator.push(QUICK_VIEW_REGISTRY_ID_2, false); + } + } +} +``` + +Create a new template file for the second Quick View: **./src/adaptiveCardExtensions/focusFeature/quickView/template/QuickViewTemplate2.json** + +```json +{ + "schema":"http://adaptivecards.io/schemas/adaptive-card.json", + "type":"AdaptiveCard", + "version":"1.5", + "body":[ + { + "type":"TextBlock", + "weight":"Bolder", + "text":"${title}", + "id": "quick-view-title" + }, + { + "type":"TextBlock", + "text":"${subTitle}", + "id": "quick-view-sub-title", + "wrap":true + }, + { + "type":"ActionSet", + "actions":[ + { + "type":"Action.Submit", + "title":"Forward skip update", + "data":{ + "id":"forward-skip" + } + }, + { + "type":"Action.Submit", + "title":"Forward", + "data":{ + "id":"forward" + } + }, + { + "type":"Action.Submit", + "title":"Back", + "data":{ + "id":"back" + } + } + ] + } + ] +} +``` + +Create a new file for the second Quick View: **./src/adaptiveCardExtensions/focusFeature/quickView/QuickView2.ts** + +We'll add the following **onAction** function. + +```typescript +public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id } = action.data; + if (id === 'back') { + this.quickViewNavigator.pop(); + } else if (id === 'forward-skip') { + this.quickViewNavigator.push(QUICK_VIEW_REGISTRY_ID_3, true); + } else { + this.quickViewNavigator.push(QUICK_VIEW_REGISTRY_ID_3, false); + } + } +} +``` + +Create a new template file for the third Quick View: **./src/adaptiveCardExtensions/focusFeature/quickView/template/QuickViewTemplate3.json** + +```json +{ + "schema":"http://adaptivecards.io/schemas/adaptive-card.json", + "type":"AdaptiveCard", + "version":"1.5", + "body":[ + { + "type":"TextBlock", + "weight":"Bolder", + "text":"${title}", + "id":"quick-view-title" + }, + { + "type":"TextBlock", + "text":"${subTitle}", + "id":"quick-view-sub-title", + "wrap":true + }, + { + "type":"ActionSet", + "actions":[ + { + "type":"Action.Submit", + "title":"Back", + "data":{ + "id":"back" + } + } + ] + } + ] +} +``` + +Create a new file for the third Quick View: **./src/adaptiveCardExtensions/focusFeature/quickView/QuickView3.ts** + +We'll add the following **onAction** function. + +```typescript +public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id } = action.data; + if (id === 'back') { + this.quickViewNavigator.pop(); + } + } +} +``` + +After adding these changes, your Quick Views will look like: + +![Card appearance after introducing changes in the first quick-view](./img/focusFeatureFirstView.png) + +Second Quick View as + +![Card appearance after introducing changes in the second quick-view](./img/focusFeatureSecondView.png) + +Third Quick View as + +![Card appearance after introducing changes in the third quick-view](./img/focusFeatureThirdView.png) + +### Implement the focusParameters function + +So far we'e modified our Quick Views to have a simple title, subtitle, and respective buttons to navigate to other Quick Views. Now we can finally implement the `focusParameters` function, which gives the ability to the third-party developer to decide what they wish to set focus on in the Quick View. + +For this, open each respective QuickView file (**./src/adaptiveCardExtensions/focusFeature/quickView/QuickView.ts**) and import the `IFocusParameters` interface, as follows: + +```typescript +import { IFocusParameters } from '@microsoft/sp-adaptive-card-extension-base'; +``` + +Finally, introduce the following `focusParameters()` function in the QuickView class so that we set focus on an element. Each QuickView should look as follows: + +```typescript +public get focusParameters(): IFocusParameters { + return { + focusTarget: 'quick-view-sub-title', + ariaLive: 'polite' + } +} +``` + +At this point, you can run **gulp serve** again and see how all the changes you made so far came together. + +This is it! Congratulations on successfully creating you Adaptive Card Extension with the focus feature. + +![Aria Polite added](./img/focusFeatureTutorialQuickViewAriaSet.PNG) + +## Notes with screen readers + +When loading your card for the first time, you'll notice that the contents of the first Quick View are read in their entirety. This is the default behavior when a screen reader sees a dialog as it treats it as navigation. Subsequent loads of the Quick View stack won't run into this. As you navigate back and forth threw Quick Views, you'll notice that the element target is focused and will be the only thing to be read. + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/features/focus-feature/img/focusFeatureFirstView.png b/docs/spfx/viva/features/focus-feature/img/focusFeatureFirstView.png new file mode 100644 index 000000000..0c0ae9b4f Binary files /dev/null and b/docs/spfx/viva/features/focus-feature/img/focusFeatureFirstView.png differ diff --git a/docs/spfx/viva/features/focus-feature/img/focusFeatureSecondView.png b/docs/spfx/viva/features/focus-feature/img/focusFeatureSecondView.png new file mode 100644 index 000000000..9138dbeaa Binary files /dev/null and b/docs/spfx/viva/features/focus-feature/img/focusFeatureSecondView.png differ diff --git a/docs/spfx/viva/features/focus-feature/img/focusFeatureThirdView.png b/docs/spfx/viva/features/focus-feature/img/focusFeatureThirdView.png new file mode 100644 index 000000000..e5d0a070b Binary files /dev/null and b/docs/spfx/viva/features/focus-feature/img/focusFeatureThirdView.png differ diff --git a/docs/spfx/viva/features/focus-feature/img/focusFeatureTutorialACE.png b/docs/spfx/viva/features/focus-feature/img/focusFeatureTutorialACE.png new file mode 100644 index 000000000..ae91b26c2 Binary files /dev/null and b/docs/spfx/viva/features/focus-feature/img/focusFeatureTutorialACE.png differ diff --git a/docs/spfx/viva/features/focus-feature/img/focusFeatureTutorialQuickViewAriaSet.png b/docs/spfx/viva/features/focus-feature/img/focusFeatureTutorialQuickViewAriaSet.png new file mode 100644 index 000000000..cd6ff41ec Binary files /dev/null and b/docs/spfx/viva/features/focus-feature/img/focusFeatureTutorialQuickViewAriaSet.png differ diff --git a/docs/spfx/viva/get-started/actions/geolocation/GeolocationDocumentation.md b/docs/spfx/viva/get-started/actions/geolocation/GeolocationDocumentation.md new file mode 100644 index 000000000..751637f8e --- /dev/null +++ b/docs/spfx/viva/get-started/actions/geolocation/GeolocationDocumentation.md @@ -0,0 +1,193 @@ +--- +title: Location capabilities in Adaptive Card Extension +description: Geolocation is a new action that the SharePoint Adaptive Card Extension framework supports, which enables third party developers to come up with their location specific scenarios. +ms.date: 01/15/2024 +ms.localizationpriority: high +--- +# Location capabilities in Adaptive Card Extension + +Microsoft added support for two geolocation actions, unique to Viva Connections, in the [SharePoint Framework (SPFx) v1.15 release](../../../../release-1.15.md). + +> [!IMPORTANT] +> This tutorial also assumes that you've already built an SPFx Adaptive Card Extension. +> +> To learn how to create your first an SPFx Adaptive Card Extension, try out [this tutorial](../../../get-started/build-first-sharepoint-adaptive-card-extension.md). + +## New action types for geolocation + +There are 2 Location actions: + +1. Get Location +1. Show Location + +## Get Location + +The `VivaAction.GetLocation` action takes user’s current device location or opens a location picker and returns the location chosen by the user. The Viva Connections browser client uses Bing Maps for the mapping experience: + +```json +{ + "id": "originLocation", + "type": "VivaAction.GetLocation", + "title": "Select location on the map", + "parameters": { + "chooseLocationOnMap": true + } +} +``` + +When the optional parameter property `ChooseLocationOnMap` is set to `true`, the action will open a map, and user will get to choose a location on the map. If set to `false` (*the default setting*), it will fetch user's current device location. + +## Show Location + +The `VivaAction.ShowLocation` action displays a map that displays the user's current location on the map or a specified location: + +```json +{ + action: { + type: 'VivaAction.ShowLocation', + parameters: { + locationCoordinates: { + latitude: 28.6132039578389, + longitude: 77.229488240066 + } + } + } +} +``` + +It takes an optional location parameter: `locationCoordinates`. + +To show a specific location, set the optional `locationCoordinates` property the location coordinates (*latitude and longitude*). + +The `locationCoordinates` object consists of the following properties: + +```typescript +{ + /** + * Latitude of the location. + */ + latitude: number; + + /** + * Longitude of the location. + */ + longitude: number; + + /** + * Timestamp (optional). + */ + timestamp?: number; + + /** + * Accuracy of the location (optional). + */ + accuracy?: number; +} +``` + +## Tutorial and Examples + +You can take a look at [this tutorial](./GeolocationTutorial.md) which goes over the step by step details of how you could create a card with geolocation actions. + +The following examples describe the geolocation action and their purpose. + +1. **Get user's current location** + + In your template JSON, introduce the following action: + + ```json + "actions": [{ + type: 'VivaAction.GetLocation', + id: 'Get Location' + }] + ``` + + When this action gets invoked, user's current geolocation is fetched and is passed to the Third Party Developer via the onAction callback. + + > [!NOTE] + > In this case, map doesn't show up. + +1. **Select location from a map** + + In your template JSON, introduce the following action: + + ```json + "actions": [{ + type: 'VivaAction.GetLocation', + id: 'Get Location', + parameters: {chooseLocationOnMap: true} + }] + ``` + + When this action gets invoked, a map pointing to user's current location opens up and the user gets to select and share the location of their choice. The selected location's coordinates are passed to the Third Party Developer via the onAction callback. + +1. **Display user's current location** + + In your template JSON, introduce the following action: + + ```json + "actions": [{ + type: 'VivaAction.ShowLocation', + id: 'Show Location' + }] + ``` + + When this action gets invoked, a map opens up and the user's current location coordinates are shown on it. + +1. **Display a specified location** + + In your template JSON, introduce the following action: + + ```json + "actions": [{ + type: 'VivaAction.ShowLocation', + id: 'Show Location', + parameters: { + locationCoordinates: { + latitude: 28.6132039578389, + longitude: 77.229488240066 + } + } + }] + ``` + + When this action gets invoked, a map opens up and it shows the location coordinates specified in the action. + +## Access geolocation actions via card-designer card's property pane + +If you don't want to write code, but still wish to see how the geolocation actions work, then you can explore [this tutorial](./GeolocationPropertyPane.md) which lets you create cards with geolocation actions via property pane. + +> [!NOTE] +> Theses geolocation actions can be added on the CardView or the buttons of the CardView or inside the QuickView. + +## Permission and error codes + +For the location APIs to work, the user must grant the browser permission to access device's location. + +Error Code | Error Description +----------------- | ----------------- +PermissionDenied | User has denied the permission to access location +InternalError | An unexpected error happened while invoking the location APIs +HostNotSupported | The location action is being used in an unsupported environment + +## Callbacks for Card Developers + +When the action `VivaAction.GetLocation` is invoked, we pass the fetched location coordinates via the onAction callback. + +> [!NOTE] +> `onAction` callback is not invoked for `VivaAction.ShowLocation`. + +For actions: `VivaAction.GetLocation` and `VivaAction.ShowLocation`, if the user lands into an error state, then an `onError` callback will get invoked, to which we pass the action name and the error code. + +## Availability of geolocation actions + +The support matrix for location capabilities in Viva Connections is the following: + + Action | Teams Desktop and Web | Teams Mobile | SharePoint (browser) +------------- | --------------------- | --------------------- | --------- +Get Location | Not Supported | Supported | Supported +Show Location | Not Supported | Supported | Supported + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/actions/geolocation/GeolocationPropertyPane.md b/docs/spfx/viva/get-started/actions/geolocation/GeolocationPropertyPane.md new file mode 100644 index 000000000..8b87eca7e --- /dev/null +++ b/docs/spfx/viva/get-started/actions/geolocation/GeolocationPropertyPane.md @@ -0,0 +1,74 @@ +--- +title: Explore Geolocation capability via property pane of card-desinger card in Adaptive Card Extension +description: Geolocation is a new action that the SharePoint Adaptive Card Extension framework supports, and in this tutorial we see how we can explore this capability via the property pane of the card-designer card. +ms.date: 09/12/2023 +ms.localizationpriority: high +--- + +# Explore Geolocation capability via property pane of card-desinger card in Adaptive Card Extension + +In this tutorial we will see how we can use the card-designer card's property pane to explore geolocation actions. + +We will: + +- Update the card strings +- Introduce geolocation actions on the Card View, Primary button and Secondary button + +First, figure out the domain to the URL of your SharePoint tenant and site you want to use for testing and access the `workbench.aspx` page. For example: `https://contoso.sharepoint.com/sites/devsite/_layouts/workbench.aspx`. + +Here, click on the '+' icon in the middle of the page, and add the `card-designer` card on the canvas. + +Next, click the pencil icon adjacent to this card to open the property pane. + +## Update the card strings + +Here, first set the `card size` to `Large`. + +To provide descriptive labels, change `Title` to `GeoLocation`, `Heading` to `GeoLocation Demo` and `description` to `Demo GeoLocation Actions`. + +![Adding strings in the property pane of card designer card](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneStrings.png) + +## Adding action on Card View + +Under `Actions`, click the drop-down menu of `card action` and select `Select location from a map` option. + +![Set the on-click action to "Select location from a map" from the drop-down menu of card-view](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardAction.png) + +## Adding action on Primary button + +Next, for the `Primary Button`, set the `Title` to `My Location` and from its action drop-down menu, select `Display a specified or current location`. + +![Set the on-click action to "Display a specified or current location" from the drop-down menu for the primary button](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionPropertyPanePrimaryButtonAction.png) + +### Adding action on Secondary button + +Finally, for the `Secondary Button`, set the `Title` to `Custom Location` and from its action drop-down menu, select `Display a specified or current location`. + +Next, turn on the `Display a specified location` toggle button. + +This will bring up two text boxes for location coordinates. + +Here you may provide any location coordinates of your choice. + +For our example, we are putting in `27.98884062493244` as the value for the text-box labeled `latitude` and `86.9249751` for the text-box labeled `longitude`. These are the coordinates of Mount Everest. + +![Set the on-click action to "Display a specified or current location" from the drop-down menu for the secondary button and pass coordinates of your choice in the respective location text-boxes](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneSecondaryButtonAction.png) + +## Try the geolocation actions + +Now close the property pane and click `Preview` from the top right hand corner of the page: + +- Click on the card itself to select a location from the map +- Clicking on `My location` will open a map showing your current location +- Clicking on `Show custom location` will open a map showing your custom location (Mount Everest) + +You can now check out the three geolocation actions that you introduced via the property pane. + +![Card-Designer card with geolocation actions configured](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionPropertyPaneCardGenerated.png) + +> [!NOTE] +> This property-pane experience doesn't allow you to introduce onAction callback, and hence the action `Select location from a map` is actually a no-op. + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/actions/geolocation/GeolocationTutorial.md b/docs/spfx/viva/get-started/actions/geolocation/GeolocationTutorial.md new file mode 100644 index 000000000..559c8e729 --- /dev/null +++ b/docs/spfx/viva/get-started/actions/geolocation/GeolocationTutorial.md @@ -0,0 +1,267 @@ +--- +title: Create an Adaptive Card Extension with geolocation action +description: Step by step guide on creating Adaptive Card Extension for Geolocation action. +ms.date: 12/15/2023 +ms.localizationpriority: high +--- +# Create an Adaptive Card Extension with geolocation action + +> [!NOTE] +> This tutorial assumes that you have installed the SPFx v1.18 +> +> For more information on installing the SPFx v1.18, see [SharePoint Framework v1.18 release notes](../../../../release-1.18.md). + +## Scaffold an Adaptive Card Extension project + +Create a new project directory for your project and change your current folder to that directory. + +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (select the default option for all prompts omitted below): + +- **What is your solution name?** geolocation-tutorial +- **Which type of client-side component to create?** Adaptive Card Extension +- **Which template do you want to use?** Generic Card Template +- **What is your Adaptive Card Extension name?** GeoLocation + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This process might take few minutes. + +Next, run **gulp serve** from the command line in the root of the project. When the hosted workbench loads, you'll see the **GeoLocation** card: + +![See the GeoLocation card icon in the webpart toolbox](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionAppIcon.png) + +## Add geolocation actions to your Adaptive Card Extension + +At this point we have got the out of the box scaffolded code. Now, let us try adding geolocation actions to the Card View and Quick View experiences. + +We will create a card which will have a Card View and a Quick View. On the Card View, we will provide a button, which will show the user their current location and clicking the Card View itself will open a Quick View. + +In the Quick View, we will provide three buttons which will perform the following actions: + +- Get user's current location +- Let user choose a location from the map +- Show a specific location on the map + +### Update the labels that will show up on the card + +Before we start adding the actions, let us first update the strings that you will see on the card. + +For this, locate and open the following file in your project: **./src/adaptiveCardExtensions/geoLocation/loc/en-us.js** + +Replace the content of this file with: + +```javascript +define([], function() { + return { + "PropertyPaneDescription": "Tutorial on geolocation action in ACE.", + "TitleFieldLabel": "Geolocation", + "Title": "GeoLocation", + "SubTitle": "GeoLocation Actions", + "PrimaryText": "Location Demo", + "Description": "Demonstrating GeoLocation Capabilities", + "ShowCurrentLocation": "My Location" + } +}); +``` + +Next, locate and open the following file in your project: **./src/adaptiveCardExtensions/geoLocation/loc/mystring.d.ts** + +Add the following: + +```typescript +ShowCurrentLocation: string; +``` + +to the `IGeoLocationAdaptiveCardExtensionStrings` interface. + +### Add actions on the Card View + +As mentioned earlier, on the Card View, we will add a button, which will show user their current location and on clicking the Card View, we will show the Quick View experience. + +We will first add the functionality for the button on the Card View. For this, locate and open the following file in your project: **./src/adaptiveCardExtensions/geoLocation/cardView/CardView.ts** + +Here, replace the definition of `footer` in `cardViewParameters` getter with the following: + +```typescript +public get cardViewParameters(): ComponentsCardViewParameters { + return return PrimaryTextCardView({ + // ... + footer: { + componentName: 'cardButton', + title: strings.ShowCurrentLocation, + action: { + type: 'VivaAction.ShowLocation' + } + } + }); +} +``` + +With this change, we have configured a button with label **My Location** and on click action is `VivaAction.ShowLocation`, which will show user their current location. + +Next, replace the content of `onCardSelection()` function with the following: + +```typescript +public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined { + return { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + }; +} +``` + +This change implies that when a user clicks the Card View, then it should open a Quick View for them. + +With the changes made so far, your Card View would look like: + +![Card appearance after introducing the strings and changes in the card-view](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionCardView.png) + +### Add actions on the Quick View + +In the Quick View, we will introduce buttons for 3 actions: + +- Get user's current location +- Let user choose a location from the map +- Show a specific location on the map (for our example we will show Mount Everest) + +In addition to these, we will have two text blocks for showing **Latitude** and **Longitude**, which will show the respective coordinates when the `VivaAction.GetLocation` action is executed (more on this later). + +We will first define the template of the Quick View. For this, locate and open the following file in your project: **./src/adaptiveCardExtensions/geoLocation/quickView/template/QuickViewTemplate.json** + +Replace the content of this file with the following: + +```json +{ + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "TextBlock", + "text": "${latitude}" + }, + { + "type": "TextBlock", + "text": "${longitude}" + } + ], + "actions": [ + { + "title": "Choose location on map", + "type": "VivaAction.GetLocation", + "parameters": { + "chooseLocationOnMap": true + } + }, + { + "title": "Get my location", + "type": "VivaAction.GetLocation" + }, + { + "title": "Show custom location", + "type": "VivaAction.ShowLocation", + "parameters": { + "locationCoordinates": { + "latitude": 27.98884062493244, + "longitude": 86.9249751 + } + } + } + ] +} +``` + +With this, we are providing two text-blocks to show the **Latitude** and **Longitude** of the location we get via `VivaAction.GetLocation`. In addition to these, we described three geolocation actions. + +After adding these actions, your Quick View would look like: + +![Card appearance after adding actions in the quick-view](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionQuickView.png) + +### Set up the state for our Adaptive Card Extension + +So far we have created our Card View and Quick View. If you do a **gulp serve** at this point, then you will be able to perform the actions that were described above. + +But now, let us take it a notch higher. + +We now wish to show the coordinates of user's current location or user's chosen location on the Quick View when the respective actions are executed. + +For this, we will leverage the two text-blocks that we had introduced earlier in the **QuickViewTemplate.json** file + +In order to do this, we will first introduce new states. First locate and open the following file in your project: **./src/adaptiveCardExtensions/geoLocation/GeoLocationAdaptiveCardExtension.ts** + +Here, add the following states to the `IGeoLocationAdaptiveCardExtensionState` interface: + +```typescript +latitude: string; +longitude: string; +``` + +Next, in the `onInit()` function, change `this.state={}` to + +```typescript +this.state = { + latitude: 'TBD', + longitude: 'TBD' +}; +``` + +We will now make similar changes in Quick View as well. + +Locate and open the following file in your project: **./src/adaptiveCardExtensions/geoLocation/quickView/QuickView.ts** + +Add the following properties to the `IQuickViewData` interface: + +```typescript +latitude: string; +longitude: string; +``` + +and then add the following two lines in the returned object of `data` getter: + +```typescript +latitude: "Latitude: " + this.state.latitude, +longitude: "Longitude: " + this.state.longitude +``` + +### Implement the onAction function + +So far we have created defined our geolocation actions and wired in our states. Now we can finally implement the `onAction` function, which gives the ability to the third-party developer to decide what they wish to do with the location coordinates that the user has shared with them. + +For this, open the **QuickView.ts** file (**./src/adaptiveCardExtensions/geoLocation/quickView/QuickView.ts**) and import the `IGetLocationActionArguments` interface, as follows: + +```typescript +import {IGetLocationActionArguments} from '@microsoft/sp-adaptive-card-extension-base'; +``` + +Finally, introduce the following `onAction()` function in the QuickView class: + +```typescript +public onAction(action: IGetLocationActionArguments): void { + if (action.type === 'VivaAction.GetLocation') { + this.setState({ + latitude: action.location.latitude.toString(), + longitude: action.location.longitude.toString() + }); + } +} +``` + +After clicking on the `Get my location` button, the `onAction` function will be triggered and the Quick View will display the coordinates of the user's current location: + +![Card appearance after introducing changes in the quick-view](../../../../../../docs/images/viva-extensibility/geolocation/geoloactionQuickViewCoordinates.png) + +So now, whenever the `VivaAction.GetLocation` action is triggered from your Quick View, then depending on the parameters that were passed, the Adaptive Card Extension framework will either pass user's current coordinates or user's chosen coordinates to the `onAction` callback. In the implementation shared above, we check if the `action` type is of type `VivaAction.GetLocation`, and if it is, then we re-render the Quick View by doing a `setState`, in which we update the `latitude` and `longitude` text-blocks. + +At this point, you can run **gulp serve** again and see how all the changes you made so far came together. + +This is it! Congratulations on successfully creating you Adaptive Card Extension with geolocation actions. + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/actions/media-upload/MediaUploadDocumentation.md b/docs/spfx/viva/get-started/actions/media-upload/MediaUploadDocumentation.md new file mode 100644 index 000000000..f85926d24 --- /dev/null +++ b/docs/spfx/viva/get-started/actions/media-upload/MediaUploadDocumentation.md @@ -0,0 +1,161 @@ +--- +title: Media upload in Adaptive Card Extension +description: Media upload is a new action that the SharePoint Adaptive Card Extension framework supports, which enable third-party developers to upload data content to sharepoint. +ms.date: 08/28/2024 +ms.localizationpriority: high +--- +# Media upload in Adaptive Card Extension + +Microsoft added support for an action to upload media, unique to Viva Connections, in the [SharePoint Framework (SPFx) v1.15.2](../../../../release-1.15.2.md) release. + +> [!NOTE] +> This tutorial also assumes that you've already built an SPFx Adaptive Card Extension. +> +> To learn how to create your first SPFx Adaptive Card Extension, try out [this tutorial](../../../get-started/build-first-sharepoint-adaptive-card-extension.md). + +## Action type for media uploads + +### Select Media + +Allows users to upload media content via an Adaptive Card Extension (ACE). The current size limitation is 1 MB per image. A user can specify any image type to be uploaded. + +> [!WARNING] +> If an image type isn't specified, then an error indicating only images can be uploaded is displayed. + +The ACE action for Select Media is: `VivaAction.SelectMedia`. + +```json +{ + "type": "VivaAction.SelectMedia", + "id": "Select Media", + "title": "Select Files", + "parameters": { + "mediaType": "MediaType.Image" + } +} +``` + +The parameters that it takes are as follows: + +- `mediaType`: Currently set as image by default. Audio and documents, such as PDFs, are supported as well. +- `allowMultipleCapture` [OPTIONAL]: Enables multiple files to be added at once. + - This is enabled by default. +- `maxSizePerFile` [OPTIONAL]: The limitation for the file size to be uploaded, suggested limitation is 1 MB. +- `supportedFileFormats` [OPTIONAL]: Space-delimited format on allowed types. If none are supplied, then standard image files are used for type checking. + - Any file that is attempted to be upload that doesn't match the allowed type results in an error message stating: _This isn't a file type we support. You can only upload images._ + +```typescript +{ + /** + * Specify the specific media type that should be selected + */ + mediaType: MediaType; + /** + * Allow multiple images to be selected. + */ + allowMultipleCapture?: boolean; + /** + * Max file size that can be uploaded. + */ + maxSizePerFile?: number; + /** + * File formats supported for upload. + */ + supportedFileFormats?: string[]; +} +``` + +> [!WARNING] +> If a user uploads a file that is not supported in the format parameters, an error code of **InCorrectFileFormat** is thrown. + +## Tutorial and Examples + +You can take a look at [this tutorial](./MediaUploadTutorial.md) which goes over a step-by-step guide on how to create a card with the available media upload action. + +1. **Upload an image** + + In your template json file, add the following action: + + ```json + "actions": [ + { + "type": "VivaAction.SelectMedia", + "id": "Select Media", + "title": "Upload Image", + "parameters": { + "mediaType": MediaType.Image + } + } + ] + ``` + +1. **Upload multiple images** + + In your template json file, add the following action: + + ```json + "actions": [ + { + "type": "VivaAction.SelectMedia", + "id": "Select Media", + "title": "Upload Image", + "parameters": { + "mediaType": MediaType.Image, + "allowMultipleCapture": true + } + } + ] + ``` + +1. **Upload only JPG images** + + In your template json file, add the following action: + + ```json + "actions": [ + { + "type": "VivaAction.SelectMedia", + "id": "Select Media", + "title": "Upload Image", + "parameters": { + "mediaType": MediaType.Image, + "supportedFileFormats": "jpg" + } + } + ] + ``` + +1. **Upload allow only small images to be uploaded** + + In your template json file, add the following action: + + ```json + "actions": [ + { + "type": "VivaAction.SelectMedia", + "id": "Select Media", + "title": "Upload Image", + "parameters": { + "mediaType": MediaType.Image, + "supportedFilemaxSizePerFileFormats": 1000 + } + } + ] + ``` + +## Access media upload action via card-designer card's property pane + +If you don't want to write up a new ACE but still want to see the media upload in action, be sure to explore [this tutorial](./MediaUploadPropertyPane.md) which allows you to explore this through the property pane. + +> [!NOTE] +> The media upload action can be added on the Card View, buttons of the Card View, or inside the Quick View itself. + +## Availability of media upload action + + Action | Viva Connection Desktop | Viva Connections Mobile | Browser +------------ | ----------------------- | ----------------------- | --------- +Select Media | Supported | Supported | Supported + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/actions/media-upload/MediaUploadPropertyPane.md b/docs/spfx/viva/get-started/actions/media-upload/MediaUploadPropertyPane.md new file mode 100644 index 000000000..2606d92e3 --- /dev/null +++ b/docs/spfx/viva/get-started/actions/media-upload/MediaUploadPropertyPane.md @@ -0,0 +1,67 @@ +--- +title: Explore Media Upload capability via property pane of card-designer card in Adaptive Card Extension +description: Media Upload is a new action that the SharePoint Adaptive Card Extension framework supports. In this tutorial we'll see how we can explore this capability via the property pane of the card-designer card. +ms.date: 03/08/2023 +ms.localizationpriority: high +--- + +# Explore Media Upload capability via property pane of card-designer card in Adaptive Card Extension + +In this tutorial we'll see how we can explore this capability via the property pane of the card-designer card. + +- Update the card strings +- Introduce media upload actions on the Card View, primary button, and secondary button. + +First, figure out the domain to the URL of your SharePoint tenant and site you want to use for testing and access the `workbench.aspx` page. For example: `https://contoso.sharepoint.com/sites/devsite/_layouts/workbench.aspx`. + +Here, click on the '+' icon in the middle of the page, and add the `card-designer` card on the canvas. + +Next, click the pencil icon adjacent to this card to open the property pane. + +## Update the card strings + +Here, first set the `Card size` to `Large`. + +To provide descriptive labels, change `Title` to `Media Upload`, `Heading` to `Media Upload Demo` and `description` to `Demo Media Upload Actions`. + +![Adding strings in the property pane of card designer card](./img/mediaUploadPropertyPaneStrings.PNG) + +## Adding action on Card View + +Under `Actions`, click the drop-down menu of `Card action` and select `Select media` option. By default **Images** is the only media type to be captured. + +Set the expected file formats as **png** and **jpg**. + +![Set the on-click action to "Select Media" from the drop-down menu of card-view](./img/mediaUploadPropertyPaneCardAction.PNG) + +## Adding action on Primary button + +Next, for the `Primary Button`, set the `Title` to `Select single media` and from its action drop-down menu, select `Select Media`. + +Ensure that `Allow Multiple Capture` is toggled off. + +![Set the on-click action to "Select Media" from the drop-down menu for the primary button](./img//mediaUploadPropertyPanePrimaryButtonAction.PNG) + +## Adding action on Secondary button + +Change the size of the card from Medium to Large. + +Ensure that `Allow Multiple Capture` is toggled on. + +Finally, for the `Secondary Button`, set the `Title` to `Select multiple media` and from its action drop-down menu, select `Select Media`. + +![Set the on-click action to "Select Media" from the drop-down menu for the secondary button and enable multiple file uploading](./img/mediaUploadPropertyPaneSecondaryButtonAction.PNG) + +## Try the Select Media action + +Now close the property pane and click `Preview` from the top right hand corner of the page: + +- Click on the card to open up media upload and exit +- Clicking `Select single media` will pull open the same modal +- Clicking `Select multiple media` will open up the same modal but will allow the user to upload several files at once + +![Multiple images uploaded at once](./img/mediaUploadPropertyPaneMultipleImages.PNG) + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/actions/media-upload/MediaUploadTutorial.md b/docs/spfx/viva/get-started/actions/media-upload/MediaUploadTutorial.md new file mode 100644 index 000000000..d5a3365c5 --- /dev/null +++ b/docs/spfx/viva/get-started/actions/media-upload/MediaUploadTutorial.md @@ -0,0 +1,250 @@ +--- +title: Create an Adaptive Card Extension with the select media action +description: Step by step guide on how to create an Adaptive Card Extension with the select media action. +ms.date: 12/14/2023 +ms.localizationpriority: high +--- +# Create an Adaptive Card Extension with select media action + +## Scaffold an Adaptive Card Extension project + +Create a new project directory for your project and change your current folder to that directory. + +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (select the default option for all prompts omitted below): + +- **What is your solution name?** media-upload-tutorial +- **Which type of client-side component to create?** Adaptive Card Extension +- **Which template do you want to use?** Generic Card Template +- **What is your Adaptive Card Extension name?** MediaUpload + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This process might take few minutes. + +Next, run **gulp serve** from the command line in the root of the project. When the hosted workbench loads, you'll see the **MediaUpload** card: + +![See the MediaUpload card icon in the webpart toolbox](./img/mediaUploadTutorialACE.PNG) + +## Add media upload action to your Adaptive Card Extension + +At this point, we have out of the box Adaptive Card Extension code. Now it's time to flare things up with selecting media from the Card and Quick Views. + +In the Card View, we'll provide a button that will perform the following actions: **Upload an image file** + +### Update the labels that will show up on the card + +Before we start adding the actions, let us first update the strings that you'll see on the card. + +For this, locate and open the following file in your project: **./src/adaptiveCardExtensions/mediaUpload/loc/en-us.js** + +Replace the content of this file with: + +```javascript +define([], function() { + return { + "PropertyPaneDescription": "Tutorial on media upload action in ACE.", + "TitleFieldLabel": "MediaUpload", + "Title": "Media Upload", + "SubTitle": "Media Upload Actions", + "PrimaryText": "Media Upload Demo", + "Description": "Demonstrating Media Upload Capabilities", + "UploadPNG": "Upload PNG file" + } +}); +``` + +Next, locate and open the following file in your project: **./src/adaptiveCardExtensions/mediaUpload/loc/mystring.d.ts** + +Add the following: + +```typescript +UploadPNG: string; +``` + +to the `IMediaUploadAdaptiveCardExtensionStrings` interface. + +### Add actions on the Card View + +As mentioned earlier, on the Card View, we'll add a button, which will allow the user to upload a png file when clicking the Card View. + +Locate and open the following file in your project: **./src/adaptiveCardExtensions/mediaUpload/cardView/CardView.ts** + +Here, replace the definition of `footer` in `cardViewParameters` getter with the following: + +```typescript +public get cardViewParameters(): ComponentsCardViewParameters { + return return PrimaryTextCardView({ + // ... + footer: { + componentName: 'cardButton', + title: strings.UploadPNG, + action: { + type: 'VivaAction.SelectMedia', + parameters: { + mediaType: MediaType.Image + } + } + } + }); +} +``` +You will also need to import `MediaType` from `@microsoft/sp-adaptive-card-extensions-base`: + +With this change, we have configured a button with label **Upload PNG file** and on click action is `VivaAction.SelectMedia`, which load the file uploader modal. + +Next, replace the content of `onCardSelection()` function with the following: + +```typescript +public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined { + return { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + }; +} +``` + +This change implies that when a user clicks the Card View, then it should open a Quick View for them. + +With the changes made so far, your Card View would look like: + +![Card appearance after introducing the strings and changes in the card-view](./img/mediaUploadTutorialCardView.PNG) + +### Add actions on the Quick View + +In the Quick View, we will introduce buttons for three actions: + +- Upload a png file +- Upload a jpg file +- Upload both a png and jpg file + +We will first define the template of the Quick View. For this, locate and open the following file in your project: **./src/adaptiveCardExtensions/mediaUpload/quickView/template/QuickViewTemplate.json** + +Replace the content of this file with the following: + +```json +{ + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "TextBlock", + "text": "${filesUploaded}" + } + ], + "actions": [ + { + "title": "Upload a png", + "type": "VivaAction.SelectMedia", + "parameters": { + "mediaType": "MediaType.Image", + "allowMultipleCapture": false, + "supportedFileFormats": "png" + } + }, + { + "title": "Upload a jpg", + "type": "VivaAction.SelectMedia", + "parameters": { + "mediaType": "MediaType.Image", + "allowMultipleCapture": false, + "supportedFileFormats": "jpg" + } + }, + { + "title": "Upload a png and jpg", + "type": "VivaAction.SelectMedia", + "parameters": { + "mediaType": "MediaType.Image", + "allowMultipleCapture": true, + "supportedFileFormats": "png jpg" + } + } + ] +} +``` + +After adding these actions, your Quick View would look like: + +![Card appearance after introducing changes in the quick-view](./img/mediaUploadTutorialQuickView.PNG) + +### Set up the state for our Adaptive Card Extension + +So far we have created our Card View and Quick View. If you do a **gulp serve** at this point, then you'll be able to perform the actions that were described above. + +But now, let us take it a notch higher. + +We now wish to show all files uploaded on the Quick View when the respective actions are executed. + +We'll need to make a few quick changes will first introduce new states. First locate and open the following file in your project: **./src/adaptiveCardExtensions/mediaUpload/MediaUploadAdaptiveCardExtension.ts** + +Here, add the following `states` to the `IMediaUploadAdaptiveCardExtensionState` interface: + +```typescript +filesUploaded: string; +``` + +Next, in the `onInit()` function, change `this.state={}` to + +```typescript +this.state = { + filesUploaded: '' +}; +``` + +We will now make similar changes in Quick View as well. + +Locate and open the following file in your project: **./src/adaptiveCardExtensions/mediaUpload/quickView/QuickView.ts** + +Add the following properties to the `IQuickViewData` interface: + +```typescript +filesUploaded: string; +``` + +and then add the following line in the returned object of `data` getter: + +```typescript +filesUploaded: this.state.filesUploaded +``` + +### Implement the onAction function + +So far we have created defined our media upload action and wired in our states. Now we can finally implement the `onAction` function, which gives the ability to the third party developer to decide what they wish to do with the media information uploaded. + +For this, open the **QuickView.ts** file (**./src/adaptiveCardExtensions/mediaUpload/quickView/QuickView.ts**) and import the `ISelectMediaActionArguments` interface, as follows: + +```typescript +import {ISelectMediaActionArguments} from '@microsoft/sp-adaptive-card-extension-base'; +``` + +Finally, introduce the following `onAction` function in the QuickView class so that we can attain a list of our files: + +```typescript +public onAction(action: ISelectMediaActionArguments): void { + if (action.type === 'VivaAction.SelectMedia') { + // media is an array of attachment objects which contain the content and filename + this.setState({ + filesUploaded: action.media.map(attachment => attachment.fileName).join(',') + }); + } +} +``` + +So now, whenever the `VivaAction.SelectMedia` action is triggered from your Quick View, depending on the parameters that were passed, the Adaptive Card Extension framework will pass a media attachment to the `onAction` callback. In the implementation shared above, we check if the `action` type is of type `VivaAction.SelectMedia`, and if it is, then we re-render the Quick View by doing a `setState`, in which we update the `filesUploaded` text-block. + +At this point, you can run **gulp serve** again and see how all the changes you made so far came together. + +This is it! Congratulations on successfully creating you Adaptive Card Extension with media upload action. + +![Two media uploaded](./img/mediaUploadTutorialFileNames.PNG) + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneCardAction.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneCardAction.PNG new file mode 100644 index 000000000..84fa0a332 Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneCardAction.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneMultipleImages.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneMultipleImages.PNG new file mode 100644 index 000000000..e14052eaf Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneMultipleImages.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPanePrimaryButtonAction.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPanePrimaryButtonAction.PNG new file mode 100644 index 000000000..2159139c1 Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPanePrimaryButtonAction.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneSecondaryButtonAction.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneSecondaryButtonAction.PNG new file mode 100644 index 000000000..1d1c4e499 Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneSecondaryButtonAction.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneStrings.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneStrings.PNG new file mode 100644 index 000000000..0b0ab049e Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadPropertyPaneStrings.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialACE.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialACE.PNG new file mode 100644 index 000000000..7f87430d2 Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialACE.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialCardView.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialCardView.PNG new file mode 100644 index 000000000..8fc48d11e Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialCardView.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialFileNames.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialFileNames.PNG new file mode 100644 index 000000000..d2f2c4e0c Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialFileNames.PNG differ diff --git a/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialQuickView.PNG b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialQuickView.PNG new file mode 100644 index 000000000..559da79ab Binary files /dev/null and b/docs/spfx/viva/get-started/actions/media-upload/img/mediaUploadTutorialQuickView.PNG differ diff --git a/docs/spfx/viva/get-started/adaptive-card-extensions-and-teams.md b/docs/spfx/viva/get-started/adaptive-card-extensions-and-teams.md new file mode 100644 index 000000000..e739ae0eb --- /dev/null +++ b/docs/spfx/viva/get-started/adaptive-card-extensions-and-teams.md @@ -0,0 +1,168 @@ +--- +title: Adaptive Card Extensions and Teams Apps +description: "This tutorial builds off the tutorial 'Advanced Quick View Functionality'." +ms.date: 03/08/2023 +ms.localizationpriority: high +--- +# Adaptive Card Extensions and Teams Apps + +This tutorial builds off the following tutorial: [Advanced Quick View Functionality](advanced-quick-view-functionality.md). + +Adaptive Card Extensions can be used as supplemental pieces to a larger Teams App story. An ACE on the Viva Connections Dashboard can link directly to a Teams Personal Tab or Bot. + +In this tutorial, you'll use an ACE within a Microsoft Teams app. + +## Scaffold a SPFx Teams Personal App + +Start with the solution from the previous tutorials and add a new SPFx component to the project using the SPFx generator. Execute the following statement in command prompt from your project's root folder: + +```console +yo @microsoft/sharepoint +``` + +When prompted, accept the default option for all prompts by the generator. + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. + +> [!IMPORTANT] +> There's a known issue where installation of all dependencies will fail after when the generator executes the **npm install** command. +> +> To work around this error, locate and open the following file in the project: **./package.json**. +> +> Remove the dependency **@microsoft/sp-webpart-workbench** from the `devDependencies` section of the file. +> +> Now, execute the following command in the console from your project's root folder: +> +> ```console +> npm install +> ``` + +### Edit the manifest + +Locate and open the following file in the project: **./src/webparts/helloWorld/HelloWorldWebPart.manifest.json**. + +Update the `supportedHosts` array to only support use within a Teams Personal Tab: + +```json +"supportedHosts": ["TeamsPersonalApp"] +``` + +### Package and deploy the solution + +Now package and deploy the solution to your SharePoint Online Tenant App Catalog: + +Start by building the solution in production mode: + +```console +gulp bundle --ship +``` + +Next, package the solution using the **package-solution** task: + +```console +gulp package-solution --ship +``` + +Add your solutions package file (**\*.sppkg** located in the **./sharepoint/solution** folder) and upload it to Tenant +App Catalog. + +:::image type="content" source="../../../images/viva-extensibility/lab4-catalog.png" alt-text="Upload the project to the Tenant App Catalog"::: + +When you deploy the solution, ensure the **Make this solution available to all sites in the organization** box is selected: + +:::image type="content" source="../../../images/viva-extensibility/lab4-deploy.png" alt-text="Ensure the solution is deployed to all sites in the tenant"::: + +Now, deploy the solution to the Microsoft Teams app store for your tenant by selecting the **Sync to Teams** button: + +:::image type="content" source="../../../images/viva-extensibility/lab4-sync.png" alt-text="Deploy the solution to the Teams app store"::: + +### Add a new Personal Tab + +With the solution deployed, let's test it within the Microsoft Teams client. + +Navigate to the to [Microsoft Teams web client](https://teams.microsoft.com), sign in, and select on the `...` icon in the left-most navigation. + +Select the **More apps** link: + +:::image type="content" source="../../../images/viva-extensibility/lab4-apps.png" alt-text="Microsoft Teams More Apps"::: + +You should see your newly uploaded Teams Personal App. Select it and then select **Add**. + +Open your new Personal Tab and copy the following highlighted portion from the URL. This is the Microsoft Teams app ID. You'll need this later in this tutorial: + +:::image type="content" source="../../../images/viva-extensibility/lab4-url.png" alt-text="Microsoft Teams App ID"::: + +## Scaffold a second ACE + +Create a second ACE using the SPFx generator by executing the following statement in command prompt from your project's root folder: + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (*select the default option for all prompts omitted below*): + +- **Which type of client-side component to create?** Adaptive Card Extension +- **What is your Adaptive Card Extension name?** TeamsHelloWorld +- **What is your Adaptive Card Extension description?** TeamsHelloWorld description + +### Add a Teams deep link + +Microsoft Teams deep links have the following format: `https://teams.microsoft.com/l/entity/{appID}/{entityID}` + +1. Replace `{appID}` with the Microsoft Teams app ID value you copied in the last step. +1. Replace `{entityID}` with `0`. + +> [!TIP] +> To learn more about deep links in Microsoft Teams apps, see [Microsoft Teams: Create deep links](/microsoftteams/platform/concepts/build-and-test/deep-links). + +> [!NOTE] +> If you're linking to a non-SPFx Teams App, the `entityID` value is the entity ID specified in the Static Tabs section of the Teams manifest. + +Locate and open the following file in the project: **./src/adaptiveCardExtensions/teamsHelloWorld/cardView/CardView.ts**. + +Update the `onCardSelection()` method to open a deep link: + +```typescript +public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined { + return { + type: 'ExternalLink', + parameters: { + isTeamsDeepLink: true, + target: '' // Set this to your Teams deep link URL + } + }; +} +``` + +Repeat the steps in the section [Package and deploy the solution](#package-and-deploy-the-solution) above to rebuild, package, and deploy the updated solution. + +## Viva Connections Dashboard + +The Viva Connections Dashboard is available on the Home Site of the tenant. + +:::image type="content" source="../../../images/viva-extensibility/lab4-new.png" alt-text="SharePoint home site New menu"::: + +### Add cards to the dashboard + +From the **New** menu, select the **Dashboard** item to create a new dashboard. Add the ACE to the dashboard by selecting **Add Card**: + +:::image type="content" source="../../../images/viva-extensibility/lab4-add.png" alt-text="Add ACE to dashboard"::: + +Add your HelloWorld and TeamsHelloWorld ACEs to the Dashboard. When finished, publish the Dashboard. + +### Deep link + +Select the **TeamsHelloWorld** ACE. The Microsoft Teams desktop client will automatically open to the Personal App you previously created. + +## Conclusion + +After this lab you should be familiar with: + +- Packaging and deployment of heterogeneous SPFx solutions +- Manually creating a Teams deep link URL +- Deep linking from an ACE to a Teams Personal Tab + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/advanced-card-view-functionality.md b/docs/spfx/viva/get-started/advanced-card-view-functionality.md new file mode 100644 index 000000000..0d4ea1ea3 --- /dev/null +++ b/docs/spfx/viva/get-started/advanced-card-view-functionality.md @@ -0,0 +1,539 @@ +--- +title: Advanced Card View Functionality +description: "This tutorial builds off the tutorial 'Build your first SharePoint Adaptive Card Extension'." +ms.date: 09/12/2023 +ms.localizationpriority: high +--- +# Advanced Card View Functionality + +This tutorial builds off the following tutorial: [Build your first SharePoint Adaptive Card Extension](build-first-sharepoint-adaptive-card-extension.md) + +In this tutorial, you'll implement advanced Card View functionality. You'll build off the the previous tutorial and create a Card View that's powered by data in a SharePoint list. + +[!INCLUDE [developer-preview-notice](../../../../includes/snippets/developer-preview-notice.md)] + +## Create a test list + +Prepare this tutorial by creating a new list in a SharePoint site with some sample data: + +1. Browse to your site and create a new list named **Instruction List**. +1. Add a **Single line of text** column named **Description**. + + :::image type="content" source="../../../images/viva-extensibility/lab2-empty-list.png" alt-text="Empty SharePoint list"::: + +1. Add a few items to the list: + + - **Title**: Step 1, **Description**: Use ACEs + - **Title**: Step 2, **Description**: ??? + - **Title**: Step 3, **Description**: SPFx 🚀 🌝 + +1. Get the list's ID: + + 1. While viewing the list, select the *gear* icon in the suite bar to open the **Settings** menu. Then select the **List settings** menu item: + + :::image type="content" source="../../../images/viva-extensibility/lab2-list-settings.png" alt-text="List settings screen"::: + + 1. On the **List Settings** page, locate the list's ID in the URL: + + :::image type="content" source="../../../images/viva-extensibility/lab2-list-id.png" alt-text="List ID in the URL"::: + + 1. Save the list's ID so you can use it in the next step. + +## Add ACE functionality + +Start with the HelloWorld ACE from the previous tutorial, [Build your first SharePoint Adaptive Card Extension](build-first-sharepoint-adaptive-card-extension.md). Make the following updates in preparation for Step 2. + +### Change properties + +Let's modify the properties for our ACE and set the list ID that contains the data our ACE will display: + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. +1. Update the interface used to define the type of the ACE's `properties` property: + + ```typescript + export interface IHelloWorldAdaptiveCardExtensionProps { + title: string; + listId: string; + } + ``` + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.manifest.json**. +1. Initialize the ACE with the ID of the List created in the previous step by setting the following `preConfiguredEntries`: + + ```json + "preconfiguredEntries": [{ + // ... + "properties": { + "title": "HelloWorld", + "listId": "" // TODO: enter list id + } + }] + ``` + + > [!IMPORTANT] + > Make sure you enter the ID of the list you previously obtained into the `listId` property in the `preconfiguredEntries` code above. + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldPropertyPane.ts**. +1. Update the Property Pane by adding the following field: + + ```typescript + PropertyPaneTextField('listId', { + label: 'List ID' + }) + ``` + +### Change the extension state + +Next, let's update the state of the extension. When the state changes, it will trigger the ACE to rerender. These changes will add a collection of list items to the state as well as the current item displayed, as indicated by the `currentIndex` property you'll add. + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. +1. Add a new interface for the List data by adding the following code to the file: + + ```typescript + export interface IListItem { + title: string; + description: string; + } + ``` + +1. Update the interface used to define the ACE's state to use the new **IListItem** interface: + + ```typescript + export interface IHelloWorldAdaptiveCardExtensionState { + currentIndex: number; + items: IListItem[]; + } + ``` + +1. Update the `state` initialization by updating the `onInit()` method in the ACE: + + ```typescript + public onInit(): Promise { + this.state = { + currentIndex: 0, + items: [] + }; + // ... + } + ``` + +1. Temporarily remove where the `state` is referenced in the ACE and Views by updating the `onPropertyPaneFieldChanged()` method: + + ```typescript + // tslint:disable-next-line: no-any + protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void { + } + ``` + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/quickView/QuickView.ts**. +1. Update the `data()` and `onAction()` methods to the following: + + ```typescript + public get data(): IQuickViewData { + return { + subTitle: '', + title: strings.Title + }; + } + + public onAction(action: IActionArguments): void { + } + ``` + +Now that the state has been updated, we can now update our ACE to fetch data from the SharePoint list. + +### Add dependency + +The next step is to add support to the project and ACE to retrieve items from a SharePoint list. To do this, you'll use the SharePoint Framework (SPFx) API to call the SharePoint REST endpoint. + +First, add a dependency to the SPFx package used to submit HTTP requests to REST endpoints: + +1. Locate and open the following file in the project: **./package.json**. Take note of the beta version of the SPFx related beta packages used by the other packages listed as dependencies in the `dependencies` section of the **package.json** file. +1. Install the following NPM package in your project: **@microsoft/sp-http**: + + ```console + npm install @microsoft/sp-http -SE + ``` + +### Fetch the list data + +Next, add support for calling the SharePoint REST API and adding the retrieved items to the ACE's state. When the state is updated, it will trigger the ACE to rerender. + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. +1. Request the list data using the SPFx **SpHttpClient** API. Add the following to the class that implements the ACE: + + ```typescript + import { SPHttpClient } from '@microsoft/sp-http'; + + ... + + private _fetchData(): Promise { + if (this.properties.listId) { + return this.context.spHttpClient.get( + `${this.context.pageContext.web.absoluteUrl}` + + `/_api/web/lists/GetById(id='${this.properties.listId}')/items`, + SPHttpClient.configurations.v1 + ) + .then((response) => response.json()) + .then((jsonResponse) => jsonResponse.value.map( + (item) => { return { title: item.Title, description: item.Description }; }) + ) + .then((items) => this.setState({ items })); + } + + return Promise.resolve(); + } + ``` + +1. Update the ACE to request the list data during when it's initialized by updating the `onInit()` method. + + Replace the last line `return Promise.resolve();` to be `return this._fetchData();` as follows: + + ```typescript + public onInit(): Promise { + // ... + return this._fetchData(); + } + ``` + +1. Update the ACE to request the list data when the Property Pane is updated. Add the following method to the class that implements the ACE. This code will only request the data when the list's ID is changed in the Property Pane: + + ```typescript + protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void { + if (propertyPath === 'listId' && newValue !== oldValue) { + if (newValue) { + this._fetchData(); + } else { + this.setState({ items: [] }); + } + } + } + ``` + +## Card updates + +With the ACE updated to fetch items from a SharePoint list, let's update the card to display this data. + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/cardView/CardView.ts**. +1. Update `cardViewParameters` getter to render Primary Text Card View instead of Basic Card View: + + ```typescript + public get cardViewParameters(): ComponentsCardViewParameters { + return PrimaryTextCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + header: { + componentName: 'text', + text: strings.PrimaryText + }, + body: { + componentName: 'text', + text: '' + }, + footer: { + componentName: 'cardButton', + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + }); + } + ``` + +1. Update the `cardViewParameters()` getter to display data from the list: + + ```typescript + public get cardViewParameters(): ComponentsCardViewParameters { + const { title, description } = this.state.items[this.state.currentIndex]; + return PrimaryTextCardView({ + // ... + header: { + componentName: 'text', + text: title + }, + body: { + componentName: 'text', + text: description + }, + // ... + }); + } + ``` + +Now you can test the ACE. Build and launch the ACE in the hosted workbench: + +```console +gulp serve +``` + +Once the local web server has loaded, navigate to the hosted workbench: `https://{tenant}.sharepoint.com/_layouts/15/workbench.aspx` + +> [!NOTE] +> Remove any old instance of the ACE from your workbench. ACE instances from [the previous tutorial](build-first-sharepoint-adaptive-card-extension.md) will show an error message since the ACE properties have been updated. + +Open the Toolbox and select your ACE: + +:::image type="content" source="../../../images/viva-extensibility/lab2-ace-1.png" alt-text="Select the ACE from the Toolbox"::: + +## Conditional Card Views + +By default, Views are automatically responsive to the Card size. However, ACEs can optionally provide different Views for any given Card size. + +Change the HelloWorld ACE to display the total count of List items in the **Medium** Card size, and display the List items in the **Large** Card size to maximize the use of available space. + +### Medium Card View + +Let's create a medium Card View for our ACE: + +1. Create a new file **./src/adaptiveCardExtensions/helloWorld/cardView/MediumCardView.ts** folder. +1. Add the following code to create a new **Medium** sized Card View: + + ```typescript + import { + BaseComponentsCardView, + ComponentsCardViewParameters, + BasicCardView + } from '@microsoft/sp-adaptive-card-extension-base'; + import { + IHelloWorldAdaptiveCardExtensionProps, + IHelloWorldAdaptiveCardExtensionState, + QUICK_VIEW_REGISTRY_ID, + } from '../HelloWorldAdaptiveCardExtension'; + + export class MediumCardView extends BaseComponentsCardView< + IHelloWorldAdaptiveCardExtensionProps, + IHelloWorldAdaptiveCardExtensionState, + ComponentsCardViewParameters + > { + public get cardViewParameters(): ComponentsCardViewParameters { + + return BasicCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title, + icon: { + url: this.properties.iconProperty + } + }, + header: { + componentName: 'text', + text: `3 Steps`, // Display the total number of steps + }, + footer: { + componentName: 'cardButton', + title: 'View All', + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID, + }, + }, + }, + }); + } + } + ``` + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. +1. Now, register the new View by making the following changes to your ACE: + + ```typescript + import { MediumCardView } from './cardView/MediumCardView'; + + .. + + const MEDIUM_VIEW_REGISTRY_ID: string = 'HelloWorld_MEDIUM_VIEW'; + + .. + + public onInit(): Promise { + // ... + this.cardNavigator.register(CARD_VIEW_REGISTRY_ID, () => new CardView()); + this.cardNavigator.register(MEDIUM_VIEW_REGISTRY_ID, () => new MediumCardView()); + // ... + } + ``` + +1. Update the `renderCard()` method to return either the **Medium** Card View or the **Large** Card View based on the Card size: + + ```typescript + protected renderCard(): string | undefined { + return this.cardSize === 'Medium' ? MEDIUM_VIEW_REGISTRY_ID : CARD_VIEW_REGISTRY_ID; + } + ``` + +Test your changes by refreshing the workbench: + +:::image type="content" source="../../../images/viva-extensibility/lab2-ace-2.png" alt-text="Updated ACE rendering different sizes of the ACE"::: + +Change the Card size to **Large** and refresh the browser: + +:::image type="content" source="../../../images/viva-extensibility/lab2-ace-3.png" alt-text="ACE card rendering the Large card"::: + +## Large Card interactivity + +ACE Card Views support user interaction. The buttons can invoke REST APIs or be used to interact with the Card in other ways. In this section, you'll change the Large Card View to iterate through the items in the SharePoint list. + +1. Locate and open the following file in the project: **./src/adaptiveCardExtensions/helloWorld/cardView/CardView.ts**. +1. At the top of the file, add `IActionArguments`, `GenericCardViewFooterConfiguration` and `IAdaptiveCardExtensionCardButtonParameters` as the references to import from the **@microsoft/sp-adaptive-card-extension-base** package: + + ```typescript + import { + // ... + GenericCardViewFooterConfiguration, + IActionArguments, + IAdaptiveCardExtensionCardButtonParameters + } from '@microsoft/sp-adaptive-card-extension-base'; + ``` + +1. The buttons on the Card View can be dynamic based on the current state of the ACE. Add the following code to your ACE's **CardView.ts** file: + + ```typescript + public get cardViewParameters(): ComponentsCardViewParameters { + const { title, description } = this.state.items[this.state.currentIndex]; + let footer: GenericCardViewFooterConfiguration = undefined; + + if (this.state.currentIndex > 0) { + footer = { + componentName: 'cardButton', + title: 'Previous', + action: { + type: 'Submit', + parameters: { + id: 'previous', + op: -1 // Decrement the current index + } + } + }; + } + if (this.state.currentIndex < this.state.items.length - 1) { + const nextButton: IAdaptiveCardExtensionCardButtonParameters = { + componentName: 'cardButton', + title: 'Next', + action: { + type: 'Submit', + parameters: { + id: 'next', + op: 1 // Increment the current index + } + } + }; + + if (footer) { + footer = [footer as IAdaptiveCardExtensionCardButtonParameters, nextButton]; + } + else { + footer = nextButton; + } + } + + return PrimaryTextCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title, + icon: { + url: this.properties.iconProperty + } + }, + header: { + componentName: 'text', + text: title + }, + body: { + componentName: 'text', + text: description + }, + footer: footer + }); + } + ``` + +1. Next, update the `state` when a button is selected by implementing the following method: + + ```typescript + public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id, op } = action.data; + switch (id) { + case 'previous': + case 'next': + this.setState({ currentIndex: this.state.currentIndex + op }); + break; + } + } + } + ``` + +Test your changes by reloading the workbench in your browser. + +The first instance of the card will show the first list item with a **Next** button: + +:::image type="content" source="../../../images/viva-extensibility/lab2-ace-4.png" alt-text="First view of the card with the Next button"::: + +Select the **Next** button. The card will display the next item in the list and add a **Previous** button: + +:::image type="content" source="../../../images/viva-extensibility/lab2-ace-5.png" alt-text="Card displaying a SharePoint list item that's neither the first or last item in the list"::: + +Select the **Next** button until you get to the last item in the list. The card will display the item in the list and only display the **Previous** button: + +:::image type="content" source="../../../images/viva-extensibility/lab2-ace-6.png" alt-text="Card displaying the last item in the list with only a Previous button"::: + +## Caching Card View and ACE state + +Starting in SPFx v1.14, ACEs have a client-side caching layer that can be configured to store: + +1. The latest rendered card. +1. The state of the ACE. + +### Rendering from cached Card View + +If the latest rendered card is stored, the Dashboard renders this cached card before the ACE is initialized, improving perceived performance. + +The settings for this cache can be configured by overriding the following method: + +```typescript +protected getCacheSettings(): Partial { + return { + isEnabled: true, // can be set to false to disable caching + expiryTimeInSeconds: 86400, // controls how long until the cached card and state are stale + cachedCardView: () => new CardView() // function that returns the custom Card View that will be used to generate the cached card + }; +} +``` + +### Rehydrating from cached ACE state + +The subset of the ACE state that is cached can be configured by overriding the following method: + +```typescript +protected getCachedState(state: TState): Partial; +``` + +The object returned by this method will be serialized and cached. By default, no state is cached. In the next call to `onInit`, the deserialized value will be passed to onInit as part of the `ICachedLoadParameters` + +```typescript +public onInit(cachedLoadParameters?: ICachedLoadParameters): Promise; +``` + +The value can then be used to rehydrate the state of the newly initialized ACE. + +## Conclusion + +After this lab you should be familiar with: + +- Changing the default `properties` of an ACE +- Changing the ACE `properties`/`state` interfaces +- Creating and registering Card Views +- Conditionally rendering Card View elements +- Advanced Card View manipulation +- Caching Card View and ACE state + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/advanced-quick-view-functionality.md b/docs/spfx/viva/get-started/advanced-quick-view-functionality.md new file mode 100644 index 000000000..76ee6aafd --- /dev/null +++ b/docs/spfx/viva/get-started/advanced-quick-view-functionality.md @@ -0,0 +1,345 @@ +--- +title: Advanced Quick View Functionality +description: "This tutorial builds off the tutorial 'Advanced Card View Functionality'." +ms.date: 08/28/2024 +ms.localizationpriority: high +--- +# Advanced Quick View Functionality + +This tutorial builds off the following tutorial: [Advanced Card View Functionality](advanced-card-view-functionality.md). + +Start with the HelloWorld ACE from the previous tutorial, [Advanced Card View Functionality](advanced-card-view-functionality.md). The HelloWorld ACE displays either the count of total steps or one individual step at a time. Using the Quick View, the ACE can show a list of all the steps. Additionally, the ACE can show more details about a particular step if it's selected. + +## Show all items in Quick View + +1. Locate and open the following file in your project: **./src/adaptiveCardExtensions/helloWorld/quickView/QuickView.ts**. +1. Update the code in the **QuickView.ts** file with the following changes: + + ```typescript + import { IListItem } from '../HelloWorldAdaptiveCardExtension'; + + // omitted for brevity + + export interface IQuickViewData { + items: IListItem[]; + } + + // omitted for brevity + + public get data(): IQuickViewData { + return { + items: this.state.items + }; + } + ``` + +1. Next, locate and open the file **src/adaptiveCardExtensions/helloWorld/quickView/template/QuickViewTemplate.json** and replace its contents with the following JSON. This will update the Quick View card rendered in the ACE: + + ```json + { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "Container", + "$data": "${items}", + "selectAction": { + "type": "Action.Submit", + "data": { + "id": "selectAction", + "newIndex": "${index}" + } + }, + "separator": true, + "items": [ + { + "type": "TextBlock", + "text": "${title}", + "color": "dark", + "weight": "Bolder", + "size": "large", + "wrap": true, + "maxLines": 1, + "spacing": "None" + }, + { + "type": "TextBlock", + "text": "${description}", + "color": "dark", + "wrap": true, + "size": "medium", + "maxLines": 1, + "spacing": "None" + } + ] + } + ] + } + ``` + +1. As you can see in the JSON template, we use the ${index} to pass the selected item index to the QuickView. To allow this to works, we must add and populate `index` property of the `IListItem` object defined in the previous tutorial. Open and locate the file **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**, then add the property `index` to the `IListItem` definition: + + ```typescript + export interface IListItem { + title: string; + description: string; + index: number; + } + ``` + +1. Locate the `fetchData()` method in the same class and modify the map function inside it, to: + + ```typescript + ... + .then((jsonResponse) => jsonResponse.value.map( + (item, index) => { return { title: item.Title, description: item.Description, index: index }; }) + ) + ... + ``` + +1. Finally locate **./src/adaptiveCardExtensions/helloWorld/cardView/CardView.ts** and update the `onCardSelection()` getter to: + + ```typescript + public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined { + return { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + }; + } + ``` + + You'll also need to import **QUICK_VIEW_REGISTRY_ID** from **../HelloWorldAdaptiveCardExtension** + +Build and launch the ACE in the hosted workbench: + +```console +gulp serve +``` + +Once the local web server has loaded, navigate to the hosted workbench: `https://{tenant}.sharepoint.com/_layouts/15/workbench.aspx` + +Open the Toolbox and select your ACE. Select the Card to open the Quick View: + +:::image type="content" source="../../../images/viva-extensibility/lab3-ace-1.png" alt-text="Rendered Quick View"::: + +Since the `onAction()` handler hasn't been changed to handle the item select, selecting on an item does nothing. You'll address this in the next step. + +## Create a new Quick View + +1. Create a new file to hold a new Quick View card: **./src/adaptiveCardExtensions/helloWorld/quickView/DetailedQuickViewTemplate.json**. +1. Add the following JSON to the **DetailedQuickViewTemplate.json** file: + + ```json + { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "${title}", + "size": "ExtraLarge" + }, + { + "type": "TextBlock", + "text": "${description}", + "size": "Medium" + } + ] + }, + { + "type": "Column", + "style": "emphasis", + "items": [ + { + "type": "TextBlock", + "text": "${details}", + "weight": "Lighter" + } + ] + } + ] + }, + { + "type": "ActionSet", + "actions": [ + { + "type": "Action.Submit", + "title": "Back", + "data": { + "id": "back" + } + } + ] + } + ] + } + ``` + +1. Create a new file to implement a new Quick View: **./src/adaptiveCardExtensions/helloWorld/quickView/DetailedQuickView.ts** +1. Add the following code to the **DetailedQuickView.ts** file: + + ```typescript + import { BaseAdaptiveCardQuickView, ISPFxAdaptiveCard } from '@microsoft/sp-adaptive-card-extension-base'; + import { IHelloWorldAdaptiveCardExtensionProps, IHelloWorldAdaptiveCardExtensionState } from '../HelloWorldAdaptiveCardExtension'; + + export interface IDetailedViewData { + title: string; + description: string; + details: string; + } + + export class DetailedView extends BaseAdaptiveCardQuickView< + IHelloWorldAdaptiveCardExtensionProps, + IHelloWorldAdaptiveCardExtensionState, + IDetailedViewData + > { + public get data(): IDetailedViewData { + const { description, title } = this.state.items[this.state.currentIndex]; + return { + description, + title, + details: 'More details' + }; + } + + public get template(): ISPFxAdaptiveCard { + return require('./template/DetailedQuickViewTemplate.json'); + } + } + ``` + +### Register the new Quick View + +With the new detailed Quick View created, now you need to register it with the ACE: + +1. Locate and open the following file in your project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. +1. Modify the code in the **HelloWorldAdaptiveCardExtension.ts** file with the following changes: + + ```typescript + import { DetailedView } from './quickView/DetailedQuickView'; + + // omitted for brevity + + export const DETAILED_QUICK_VIEW_REGISTRY_ID: string = 'HelloWorld_DETAILED_QUICK_VIEW'; + + // omitted for brevity + + public onInit(): Promise { + // ... + this.quickViewNavigator.register(QUICK_VIEW_REGISTRY_ID, () => new QuickView()); + this.quickViewNavigator.register(DETAILED_QUICK_VIEW_REGISTRY_ID, () => new DetailedView()); + // ... + } + ``` + +## ViewNavigator + +The ACE's `cardNavigator` and `quickViewNavigator` are instances of a **ViewNavigator**. + +The **ViewNavigator's** capabilities go beyond only registering new Views. The **ViewNavigator** is a state management API for the Card and Quick Views. As Views are created, they're automatically pushed onto a View stack. + +ACEs can use the **ViewNavigator** to manipulate the stack. + +- `ViewNavigator.push()`: Pushes a new View to the top of the View stack. +- `ViewNavigator.replace()`: Replaces the top View with a new View. +- `ViewNavigator.pop()`: If there's more than one View, pops the top View from the View stack. +- `ViewNavigator.close()`: Closes the current view and removes top view from View stack. + +### Navigate between views + +Update the Quick View to navigate between views: + +1. Locate and open the following file in your project: **./src/adaptiveCardExtensions/helloWorld/quickView/QuickView.ts**. +1. Update the code in the **QuickView.ts** file to handle when an item is selected from the Quick View: + + ```typescript + import { DETAILED_QUICK_VIEW_REGISTRY_ID } from '../HelloWorldAdaptiveCardExtension'; + + .. + + public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id, newIndex } = action.data; + if (id === 'selectAction') { + this.quickViewNavigator.push(DETAILED_QUICK_VIEW_REGISTRY_ID, true); + this.setState({ currentIndex: newIndex}); + } + } + } + ``` + +1. Locate and open the following file in your project: **./src/adaptiveCardExtensions/helloWorld/quickView/DetailedQuickView.ts** +1. Update the code in the **DetailedQuickView.ts** file to Handle when the Detailed Quick View's back button is selected: + + ```typescript + public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id } = action.data; + if (id === 'back') { + this.quickViewNavigator.pop(); + } + } + } + ``` + + You'll also need to import `IActionArguments` from `@microsoft/sp-adaptive-card-extension-base`. + +Reload the workbench, select on the Card to open the Quick View, and select on an item in the Quick View. + +:::image type="content" source="../../../images/viva-extensibility/lab3-detailed.png" alt-text="Selecting an item in the Quick View"::: + +Try selecting **Back** and selecting another item. + +## `onRenderTypeChanged()` + +When an ACE transitions from one **RenderType** to another, the `onRenderTypeChanged()` method is invoked with the previous **RenderType**; `this.renderType` is updated at this point. This can be useful for any tasks to do between the transition. + +For example, you might want to maintain the Card state when opening the Quick View. Let's implement this: + +1. Locate and open the following file in your project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. +1. Update the code in the **HelloWorldAdaptiveCardExtension.ts** file to introduce a private member that keeps track the previous index during a **RenderType** change: + + ```typescript + import { RenderType } from '@microsoft/sp-adaptive-card-extension-base'; + import { DetailedView } from './quickView/DetailedQuickView'; + + private _cardIndex: number; + + ... + + protected onRenderTypeChanged(oldRenderType: RenderType): void { + if (oldRenderType === 'QuickView') { + // Reset to the Card state when the Quick View was opened. + this.setState({ currentIndex: this._cardIndex }); + } else { + // The Quick View is opened, save the current index. + this._cardIndex = this.state.currentIndex; + } + } + ``` + +Reload the workbench. Try opening and closing the Quick View after clicking on different items. Notice the Card View will remain in the state it was opened. + +## Conclusion + +After this lab you should be familiar with: + +- Create and register Quick Views +- Using the `ViewNavigator` for navigation +- Handle actions from the Quick View +- Use `onRenderTypeChanged()` +- Advanced Quick View manipulation + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/build-data-visualization-adaptive-card-extension.md b/docs/spfx/viva/get-started/build-data-visualization-adaptive-card-extension.md new file mode 100644 index 000000000..ca35b3583 --- /dev/null +++ b/docs/spfx/viva/get-started/build-data-visualization-adaptive-card-extension.md @@ -0,0 +1,359 @@ +--- +title: Create a Data Visualization Adaptive Card Extension +description: Step-by-step guide on creating Data Visualization Adaptive Card Extension. +ms.date: 08/28/2024 +ms.localizationpriority: high +--- +# Create a Data Visualization Adaptive Card Extension + +The [SharePoint Framework v1.19](../../release-1.19.md) introduces a new Data Visualization Template that can be used to implement charts. This tutorial provides step-by-step guidance on implementing Data Visualization with Adaptive Card Extensions (ACEs). + +> [!NOTE] +> Before you start, complete the procedures in the following articles to ensure that you understand the basic flow of creating a custom Adaptive Card Extension: [Build your first SharePoint Adaptive Card Extension](./build-first-sharepoint-adaptive-card-extension.md) + +> [!IMPORTANT] +> Line chart data visualization type was released as part of the [SPFx 1.19 release](../../release-1.19.md). Other data visualization types, such as the bar chart, donut chart, and pie charts, were introduced in the [SPFx 1.20 release](../../release-1.20.md). + +## Scaffold an Adaptive Card Extension project + +Create a new project directory for your project and change your current folder to that directory. + +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (select the default option for all other prompts): + +- **What is your solution name?** dataVisualization-tutorial +- **Which type of client-side component to create?** Adaptive Card Extension +- **Which template do you want to use?** Data Visualization Card Template +- **What is your Adaptive Card Extension name?** DataVisualization + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This process might take few minutes. + +Next, run **gulp serve** from the command line in the root of the project. Select the **add** icon in the hosted workbench to open the toolbox, you see the **Data Visualization** card: + +![See the Data Visualization card icon in the workbench toolbox](../../../../docs/images/viva-extensibility/data-visualization/toolbox.png) + +Select the **DataVisualization** component to add it to the workbench. The default rendering renders the line chart using mock data: + +![Default Data Visualization card](../../../../docs/images/viva-extensibility/data-visualization/ace-default.png) + +## Explore the scaffolded code + +### Explore the Card View + +Locate and open the following file: **./src/adaptiveCardExtensions/dataVisualization/cardView/CardView.ts**. The Card View implements the `BaseComponentsCardView` base class `cardViewParameters` getter to specify the card configuration: + +```typescript +const seriesData : IDataPoint[] = [ + ... // omitted for brevity +]; + +export class CardView extends BaseComponentsCardView<..> { + public get cardViewParameters(): IDataVisualizationCardViewParameters { + return LineChartCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + body: { + componentName: 'dataVisualization', + dataVisualizationKind: 'line', + series: [{ + data: seriesData, + lastDataPointLabel: '3.1K' + }] + } + }); + } +} +``` + +Notice how the `body` section of the Card View specifies the `dataVisualization` component. + +### Explore possible layouts + +Based on the configuration in Card View, a chart can be rendered in two layouts: + +#### Regular + +Adding zero or one component along with a `dataVisualization` component in the body: + +![Regular](../../../../docs/images/viva-extensibility/data-visualization/regular-chart.png) + +#### Right side + +Adding more than one component in the Card View along with `dataVisualization` component in the body renders the chart on the right side of the card. For example: Header and Footer along with `dataVisualization` component in body. + +Locate & replace the `cardViewParameters()` getter with the following code to add a `header` and `footer` to the card: + +```typescript +public get cardViewParameters(): IDataVisualizationCardViewParameters { + return LineChartCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + header: { + componentName: 'text', + text: 'Sales Projection' + }, + body: { + componentName: 'dataVisualization', + dataVisualizationKind: 'line', + series: [{ + data: seriesData, + lastDataPointLabel: '3.1K' + }] + }, + footer: { + componentName: 'cardButton', + title: 'View Details', + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + }); +} +``` + +![Chart on the right side](../../../../docs/images/viva-extensibility/data-visualization/chart-on-right-side.png) + +### Explore the Quick Views + +The ACE class is located in the following file: **./src/adaptiveCardExtensions/dataVisualization/quickView/QuickView.ts** and mostly has the same code as [Generic Card View](./build-first-sharepoint-adaptive-card-extension.md). + +### Explore the ACE class + +The ACE class is located in the following file: **./src/adaptiveCardExtensions/dataVisualization/dataVisualizationAdaptiveCardExtension.ts** and mostly has the same code as [Generic Card View](./build-first-sharepoint-adaptive-card-extension.md). + +## Support for multiple data series in the chart + +The ACE `dataVisualization` component supports multiple series lines in the chart. To add multiple lines to the chart, add other entries to the `body.series` array on the `LineChartCardView` object in the Card View. + +For example, consider the following data series: + +```typescript +// Sample Data +const seriesData : IDataPoint[] = [ + { x: new Date(2024, 1, 1), y: 1000 }, + { x: new Date(2024, 2, 1), y: 2400 }, + { x: new Date(2024, 3, 1), y: 2000 }, + { x: new Date(2024, 4, 1), y: 2900 }, + { x: new Date(2024, 5, 1), y: 3000 }, + { x: new Date(2024, 6, 1), y: 3100 } +]; + +const seriesData2 : IDataPoint[] = [ + { x: new Date(2024, 1, 1), y: 600 }, + { x: new Date(2024, 2, 1), y: 1200 }, + { x: new Date(2024, 3, 1), y: 3200 }, + { x: new Date(2024, 4, 1), y: 2800 }, + { x: new Date(2024, 5, 1), y: 3600 }, + { x: new Date(2024, 6, 1), y: 4500 } +]; + +const seriesData3 : IDataPoint[] = [ + { x: new Date(2024, 1, 1), y: 5200 }, + { x: new Date(2024, 2, 1), y: 1000 }, + { x: new Date(2024, 3, 1), y: 1800 }, + { x: new Date(2024, 4, 1), y: 2900 }, + { x: new Date(2024, 5, 1), y: 600 }, + { x: new Date(2024, 6, 1), y: 400 } +]; +``` + +Add all three series to the data visualization Card View and optionally set the color of specific series: + +```typescript +export class CardView extends BaseComponentsCardView< + IRecentSalesAdaptiveCardExtensionProps, + IRecentSalesAdaptiveCardExtensionState, + IDataVisualizationCardViewParameters +> { + public get cardViewParameters(): IDataVisualizationCardViewParameters { + return LineChartCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + body: { + componentName: 'dataVisualization', + dataVisualizationKind: 'line', + series: [{ + data: seriesData, + lastDataPointLabel: '3.1K' + }, + { + data: seriesData2, + lastDataPointLabel: '4.5K', + color: '#800080' + }, + { + data: seriesData3, + lastDataPointLabel: '0.4K', + color: '#01CBAE' + }] + } + }); + } + + public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined { + return { + type: 'QuickView', + parameters: { view: QUICK_VIEW_REGISTRY_ID } + }; + } +} +``` + +This card when in the large mode generates the following rendering: + +![Chart with three series displayed](../../../../docs/images/viva-extensibility/data-visualization/chart-three-series.png) + +## Support for more chart types + +The [SharePoint Framework v1.20](../../release-1.20.md) introduces support for newer chart types, enabling developers to create visually appealing data visualizations like bar, pie, and donut charts. + +![Screenshot of example ACE's using different data visualization options.](../../../images/viva-extensibility/data-visualization/ace-dataviz-allup.png) + +### Bar Chart + +To render a vertically grouped bar chart, follow this example: + +```typescript +// Sample Data +const seriesData: IDataPoint[] = [ + { x: "Jan", y: 12986 }, + { x: "Feb", y: 13424 }, + { x: "Mar", y: 17118 }, + { x: "Apr", y: 14017 }, + { x: "May", y: 11245 } +]; + +const seriesData2: IDataPoint[] = [ + { x: "Jan", y: 19631}, + { x: "Feb", y: 19905}, + { x: "Mar", y: 17098}, + { x: "Apr", y: 11918}, + { x: "May", y: 10357} +]; + +const seriesData3: IDataPoint[] = [ + { x: "Jan", y: 19762}, + { x: "Feb", y: 12926}, + { x: "Mar", y: 17670}, + { x: "Apr", y: 19055}, + { x: "May", y: 18142} +]; +``` + +Add all three series to the data visualization Card View and optionally set the name or color of the individual series: + +```typescript +export class CardView extends BaseComponentsCardView< + IDataVisualizationAdaptiveCardExtensionProps, + IDataVisualizationAdaptiveCardExtensionState, + IDataVisualizationCardViewParameters +> { + public get cardViewParameters(): IDataVisualizationCardViewParameters { + return BarChartCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + body: { + componentName: 'dataVisualization', + dataVisualizationKind: 'bar', + series: [{ + data: seriesData, + name: 'Africa' + }, { + data: seriesData2, + name: 'Asia' + }, { + data: seriesData3, + name: 'Europe' + }] + } + }); + } +} +``` + +The rendered bar chart looks something like this: + +![Vertically grouped bar chart](../../../../docs/images/viva-extensibility/data-visualization/bar-chart.png) + +### Pie/Donut Charts + +Here's an example of the **CardView.ts** file that renders a pie chart with the given data: + +```typescript +import { + BaseComponentsCardView, + IDataVisualizationCardViewParameters, + PieChartCardView, + IPieDataPoint, +} from '@microsoft/sp-adaptive-card-extension-base'; +import { + IDataVisualizationAdaptiveCardExtensionProps, + IDataVisualizationAdaptiveCardExtensionState, +} from '../DataVisualizationAdaptiveCardExtension'; + +// Sample Data +const seriesData: IPieDataPoint[] = [ + { x: 'January', y: 50 }, + { x: 'February', y: 25, color: '#eaae32', showLabel: false }, + { x: 'March', y: 40, showLabel: false }, + { x: 'Apr', y: 35 }, + { x: 'May', y: 60 }, + { x: 'Jun', y: 29 } +]; + +export class CardView extends BaseComponentsCardView< + IDataVisualizationAdaptiveCardExtensionProps, + IDataVisualizationAdaptiveCardExtensionState, + IDataVisualizationCardViewParameters +> { + public get cardViewParameters(): IDataVisualizationCardViewParameters { + return PieChartCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + body: { + componentName: 'dataVisualization', + dataVisualizationKind: 'pie', + isDonut: false, + series: [{ + data: seriesData, + }] + } + }); + } +} +``` + +Notice how the `dataVisualizationKind` is set to `pie` and `PieChartCardView` is returned with the required parameters. Upon refreshing the card on the workbench, you see that a pie chart is rendered: + +![Pie chart example](../../../../docs/images/viva-extensibility/data-visualization/pie-chart.png) + +The `isDonut` flag indicates if the pie chart should be rendered as a donut chart, which is `false` by default. When set to true, the donut chart is rendered as follows: + +![Donut chart example](../../../../docs/images/viva-extensibility/data-visualization/donut-chart.png) + +The numeric text in the center displays the sum of all the **y** values in the series. + +## See Also + +- Video: **[Introducing new Viva Connections chart card layout option](https://www.youtube.com/watch?v=JOIb4KhiWAI)** +- Sample: **[Chart Card - Page Creation](https://github.com/pnp/sp-dev-fx-aces/tree/main/samples/ChartCard-PageCreation)** +- Sample: **[Chart Card - Three Series](https://github.com/pnp/sp-dev-fx-aces/tree/main/samples/ChartCard-ThreeSeries)** +- Sample: **[Chart Card - Data Visualization Options](https://github.com/pnp/sp-dev-fx-aces/tree/main/samples/ChartCard-DataVisualizationOptions)** diff --git a/docs/spfx/viva/get-started/build-first-sharepoint-adaptive-card-extension.md b/docs/spfx/viva/get-started/build-first-sharepoint-adaptive-card-extension.md new file mode 100644 index 000000000..01049b551 --- /dev/null +++ b/docs/spfx/viva/get-started/build-first-sharepoint-adaptive-card-extension.md @@ -0,0 +1,518 @@ +--- +title: Build your first SharePoint Adaptive Card Extension +description: Adaptive Card Extensions (ACEs) are a new SharePoint Framework component type, which enable developers to build rich, native extensions to Viva Connections' Dashboards and SharePoint Pages. In this tutorial, you'll build and explore your first ACE. +ms.date: 12/14/2023 +ms.localizationpriority: high +--- +# Build your first SharePoint Adaptive Card Extension + +Adaptive Card Extensions (ACEs) are a new SharePoint Framework component type, which enables developers to build rich, native extensions to Viva Connections' Dashboards and SharePoint Pages. Since Adaptive Card Extensions use Microsoft's Adaptive Card Framework to generate UI with its declarative JSON schema, you only need to focus on your component's business logic and let the SharePoint Framework (SPFx) handle making your component look good and work across all platforms. + +> [!IMPORTANT] +> This tutorial assumes you have installed the SPFx v1.18. For more information on installing the SPFx v1.18, see [SharePoint Framework v1.18 release notes](../../release-1.18.md). + +## Scaffold an Adaptive Card Extension project + +Create a new project directory for your project and change your current folder to that directory. + +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (*select the default option for all prompts omitted below*): + +- **Do you want to allow tenant admin the choice of deploying the solution to all sites immediately without running any feature deployment or adding apps in sites?** Yes +- **Which type of client-side component to create?** Adaptive Card Extension +- **Which template do you want to use?** Generic Card Template +- **What is your Adaptive Card Extension name?** HelloWorld + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This process might take few minutes. + +## Serve the ACE in the workbench + +Before digging into the code, run the scaffolded output and see what an Adaptive Card Extension looks like. + +The inner development loop with ACEs is similar to SPFx Web Parts. We can serve locally and run the code on the workbench. + +```console +gulp serve +``` + +Once local web server is running, navigate to the hosted Workbench: `https://{tenant}.sharepoint.com/_layouts/15/workbench.aspx` + +Open the **Web Part Toolbox** and select your ACE: + +:::image type="content" source="../../../images/viva-extensibility/lab1-toolbox.png" alt-text="Select the ACE from the toolbox"::: + +### Explore the Card View + +ACEs can render in two distinct ways. The first way an ACE can render is called the **Card View**. + +When rendered on a Dashboard or a Page, ACEs will always start in this view. + +:::image type="content" source="../../../images/viva-extensibility/lab1-hw-ace.png" alt-text="ACE rendered in Card View"::: + +### Explore the Quick View + +The second way an ACE can render is called the **Quick View**. When you interact with an ACE, ACEs can launch a larger, customized experience. + +> [!NOTE] +> ACE interaction is disabled while in **Edit** mode. The Workbench or Page must be in *Preview* or *Read* mode to interact with the ACE. + +Switch the Workbench to **Preview** mode. + +:::image type="content" source="../../../images/viva-extensibility/lab1-preview.png" alt-text="Set the workbench to preview mode"::: + +Select the **Quick View** button on the ACE: + +:::image type="content" source="../../../images/viva-extensibility/lab1-hw-ql.png" alt-text="Select the Quick View button on the ACE"::: + +## Examine the scaffolded code + +### Explore the base class + +Locate and open the following file in your project: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. + +```typescript +export default class HelloWorldAdaptiveCardExtension + extends BaseAdaptiveCardExtension { + // ... +} +``` + +All ACEs must extend from the `BaseAdaptiveCardExtension` class. You can optionally implement two generics: + +- **TProperties**: Similar to Web Parts, this is the set of persisted properties of the component (*property bag*). +- **TState**: Unique to ACEs and can *optionally* define the set of renderable data. + +### Rendering the ACE + +```typescript +protected renderCard(): string | undefined { + return CARD_VIEW_REGISTRY_ID; +} +``` + +The `renderCard()` method is `virtual` that returns a string identifier to a registered View; more on View registration later. This method is invoked during the **initial** render of the Card View. + +If `renderCard()` isn't overridden, then a default Card View will be rendered. + +Comment out the `renderCard()` method and see what happens: + +```typescript +/* +protected renderCard(): string | undefined { + return CARD_VIEW_REGISTRY_ID; +} +*/ +``` + +:::image type="content" source="../../../images/viva-extensibility/lab1-default.png" alt-text="Results of commenting the renderCard() method"::: + +Uncomment the `renderCard()` method to go back to the original state. + +The default Card View will render using the following properties from the manifest: + +- Icon: `iconProperty` +- Title: `title` +- Card text: `description` + +> [!NOTE] +> Unlike with the Card View, there is no default Quick View. + +### Register a view for the ACE + +For a View to be used, it must be registered with its respective **ViewNavigator**. Two **ViewNavigator**s are exposed on the ACE: `cardNavigator` and `quickViewNavigator`: + +```typescript +this.cardNavigator.register(CARD_VIEW_REGISTRY_ID, () => new CardView()); +this.quickViewNavigator.register(QUICK_VIEW_REGISTRY_ID, () => new QuickView()); +``` + +> [!NOTE] +> You must register a view before it can be used. You can do this within the class' constructor or `onInit()` method. + +### Card Views + +Locate and open the file: **./src/adaptiveCardExtensions/helloWorld/cardView/CardView.ts**. + +Card Views must extend `BaseComponentsCardView` and override `cardViewParameters` property to specify the look and data for the view. +There are multiple helper methods to simplify the creation of the predefined views: + +- `BasicCardView` + + :::image type="content" source="../../../images/viva-extensibility/lab1-basic-ace.png" alt-text="BasicCardView"::: + +- `ImageCardView` + + :::image type="content" source="../../../images/viva-extensibility/lab1-image-ace.png" alt-text="ImageCardView"::: + +- `PrimaryTextCardView` + + :::image type="content" source="../../../images/viva-extensibility/lab1-primary-ace.png" alt-text="PrimaryTextCardView"::: + +- `TextInputCardView` + + :::image type="content" source="../../../images/viva-extensibility/lab1-textinput-ace.png" alt-text="TextInputCardView"::: + +Each of these Views will render differently and have different constraints on what data can be provided to the template. + +As part of the `cardViewParameters` property, you can specify the following: +- **image**: Image parameters for the Card View. +- **cardBar**: Card bar component for the Card View (title and icon). +- **header**: Header components for the Card View. +- **body**: Body components for the Card View. +- **footer**: Footer components for the Card View. + +> [!NOTE] +> The Card Views for Adaptive Card templates are limited to predefined [permutations](../design/designing-card.md) and cannot be changed. The parameters type (`ComponentsCardViewParameters`) is defined to only accept the properties that are supported by the permutations. + +Additionally, there are two generics for the `properties` and `state` objects shared between the view and the ACE. + +- **TProperties**: The View's properties interface, the same interface used by persisted properties of the ACE (*property bag*). +- **TState**: Unique to ACEs and can *optionally* define the set of renderable data. + +> [!NOTE] +> SPFx will automatically propagate changes to the ACE's state to each View. + +> [!NOTE] +> Whereas the initial Card View is specified in the ACE's `renderCard()` method, the initial Quick View is specified as part of a `cardButton` component's action `parameters` in the footer. This allows two buttons to potentially open different views. + +Add a second button by adding another object to the `footer` property returned from `cardViewParameters` property: + +```typescript +public get cardViewParameters(): ComponentsCardViewParameters { + return BasicCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + header: { + componentName: 'text', + text: strings.PrimaryText + }, + footer: [{ + componentName: 'cardButton', + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + }, { + componentName: 'cardButton', + title: 'Bing', + action: { + type: 'ExternalLink', + parameters: { + target: 'https://www.bing.com' + } + } + }] + }); + } +``` + +:::image type="content" source="../../../images/viva-extensibility/lab1-large.png" alt-text="Rendered large ACE card"::: + +Now, when you select the **Bing** button, Bing will open in a new browser tab. + +Initially, the Card is displayed in **Large** Card size. Let's switch to the **Medium** size to validate how the Card is looking in this size. + +1. Change the Card size by going to the Property Pane and selecting **Medium**. + + :::image type="content" source="../../../images/viva-extensibility/lab1-size.png" alt-text="Select the card size"::: + + :::image type="content" source="../../../images/viva-extensibility/lab1-medium.png" alt-text="Rendered medium ACE card"::: + +2. Now, the **Bing** button is hidden because **Medium** Card size for cards without an image only shows one button in the footer. + +The `onCardSelection()` method determines what will happen if the Card is clicked. If the `onCardSelection()` method isn't implemented, then nothing will happen when the Card is clicked. + +1. Change the Card selection to open the **Quick View** by modifying the `onCardSelection()` method: + + ```typescript + public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined { + return { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + }; + } + ``` + +2. Now, when you select the Card, it will open the Quick View. + +### ACE Quick Views + +Locate and open the following file: **./src/adaptiveCardExtensions/helloWorld/quickView/QuickView.ts**. + +Quick Views must extend the **BaseAdaptiveCardView** base class. There are three optional generics that can be defined: + +- **TData**: The type returned from the `data()` getter method. +- **TProperties**: Similar to the Card View, this is the same interface used by persisted properties of the ACE (*property bag*). +- **TState** Similar to the Card View, this is the set of stateful data the View needs to render. **TState** must share properties with the ACE's state interface. + +A Quick View has more control over the Adaptive Card template schema than a Card View. The +`template()` getter must return valid Adaptive Card template JSON. SPFx ACEs support Adaptive Card +templating. The properties on the object returned from the `data` getter will automatically be mapped +to the bound template slot. + +For example, `${subTitle}` is bound to `strings.SubTitle`. + +```typescript +// QuickView.ts +public get data(): IQuickViewData { + return { + // ... + subTitle: strings.SubTitle + }; +} +``` + +```json +// QuickViewTemplate.json.ts +{ + "type": "TextBlock", + "weight": "Bolder", + "text": "${subTitle}", + "wrap": true +} +``` + +> [!NOTE] +> You must use the Adaptive Card binding syntax that uses `$` and `{}` brackets. + +Let's change this: + +1. Make `subTitle` a part of `IHelloWorldAdaptiveCardExtensionState`, and add two buttons. +1. Update the `data()` method as shown in the following code: + + ```typescript + public get data(): IQuickViewData { + return { + subTitle: this.state.subTitle, + title: strings.Title + }; + } + ``` + +1. Locate and open the following file: **./src/adaptiveCardExtensions/helloWorld/HelloWorldAdaptiveCardExtension.ts**. +1. Update the `IHelloWorldAdaptiveCardExtensionState` interface and `onInit()` method as follows: + + ```typescript + export interface IHelloWorldAdaptiveCardExtensionState { + subTitle: string; + } + + .. + + public onInit(): Promise { + this.state = { + subTitle: 'No button clicked' + }; + // ... + } + ``` + +In its `template()` getter, the Quick View of the ACE you generated returns the object from a JSON file. Let's now modify that template: + +1. Locate and open the following file: **./src/adaptiveCardExtensions/helloWorld/quickView/template/QuickViewTemplate.json**. +1. Replace the contents of this file with the following JSON: + + ```json + { + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "TextBlock", + "weight": "Bolder", + "text": "${title}" + }, + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "weight": "Bolder", + "text": "${subTitle}", + "wrap": true + } + ] + } + ] + }, + { + "type": "ActionSet", + "actions": [ + { + "type": "Action.Submit", + "title": "Button One", + "style": "positive", + "data": { + "id": "button1", + "message": "Clicked Button One" + } + }, + { + "type": "Action.Submit", + "title": "Button Two", + "data": { + "id": "button2", + "message": "Clicked Button Two" + } + } + ] + } + ] + } + ``` + +Test your changes by refreshing the hosted workbench in the browser. It should pickup the changes you've applied to the project if **gulp serve** is still running: + +:::image type="content" source="../../../images/viva-extensibility/lab1-new-ql.png" alt-text="Updated ACE Quick View"::: + +> [!TIP] +> Learn more about Adaptive Cards at [adaptivecards.io](https://adaptivecards.io). This site also includes an Adaptive Cards Designer that lets you preview the rendering and structure of adaptive cards as you create them. + +At this point, you've modified your ACE to include two new buttons in the Quick View card. The next step is to implement what happens when these buttons are selected. This is done using *action handlers*. + +### Action handlers + +Actions are handled by the views where they're defined. + +The Quick View has two buttons, but the view is currently not handling the **Submit** action. The `onAction()` method is invoked whenever an Adaptive Card Action is executed, for instance when the **Action.Submit** action is initiated. + +Locate and open the file **QuickView.ts** and override the `onAction()` to handle the two button selections as shown in the following code: + +```typescript +import { ISPFxAdaptiveCard, BaseAdaptiveCardQuickView, IActionArguments } from '@microsoft/sp-adaptive-card-extension-base'; + +.. + +public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id, message } = action.data; + switch (id) { + case 'button1': + case 'button2': + this.setState({ + subTitle: message + }); + break; + } + } +} +``` + +Test your changes by refreshing the hosted workbench in the browser. It should pickup the changes you've applied to the project if **gulp serve** is still running. + +Selecting either button will now set the state's `subTitle` to the `data.message` value, causing a re-render (*more on this later*). The Quick View's Adaptive Card will now display this message, since its template binds to `subTitle`. + +### Property Pane + +Similar to web parts, ACE's can have configurable properties that are set by users with appropriate permissions. These enable you to customize each implementation of your ACE. This is done using the property pane. + +ACEs can be configured just like Web Parts. The API signatures are identical for the following methods, found in the **HelloWorldAdaptiveCardExtension.ts** file: + +- `getPropertyPaneConfiguration()` +- `onPropertyPaneFieldChanged()` + +The default scaffolding for ACEs uses a new API that aims to minimize the bundle size when the component isn't in **Edit** mode. The `loadPropertyPaneResources()` method utilizes Webpack's chunking feature to separate the Property Pane specific code into its own JS file, which can then be loaded on demand. + +In addition to returning the Property Pane configuration, the **HelloWorldPropertyPane** class is used to encapsulate all your **Edit** mode logic. + +### Properties + +Other than the **Card size** field, the scaffolded ACE has one (1) configurable field, which is defined in `getPropertyPaneConfiguration()` method & defined in the **IHelloWorldAdaptiveCardExtensionProperties** interface: + +- `title` + +Card Views are designed to automatically work across all card sizes. Aside from specifying a default card size, ACEs cannot control this property. + +The `title` value is used in the title of the Property Pane and the title displayed on the Card. + +```typescript + public get cardViewParameters(): ComponentsCardViewParameters { + return BasicCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title, + // ... +``` + +You can also use the `iconProperty` property to specify an icon for your ACE. By default the value is specified as `iconImageUrl` in the manifest. + +```typescript +protected get iconProperty(): string { + // return icon url string +} +``` + +### State + +The `state` property must be initialized before calling the `setState()` method, and it can only be initialized once. + +```typescript +public onInit(): Promise { + this.state = { + subTitle: 'No button clicked' + }; + // ... +} +``` + +Unlike with `properties`, `state` isn't persisted past the current session and should only be used for ephemeral View state. + +### Re-rendering + +Re-rendering happens when a property is updated in the PropertyPane or if `setState()` is called. + +As described above, when changing a **subTitle** property during Quick View action handling, the `setState()` method is called: +```typescript +public onAction(action: IActionArguments): void { + if (action.type === 'Submit') { + const { id, message } = action.data; + switch (id) { + case 'button1': + case 'button2': + this.setState({ + subTitle: message + }); + break; + } + } +} +``` + +Passing a `Partial` object to `setState()` method will update all Views with the new values. + +If no value or identical values are passed, a re-render will still occur. + +The `setState()` method isn't just limited to the Property Pane. It can be used in response to receiving new data or as a result of some user action. + +## Conclusion + +After this tutorial you should be familiar with: + +- Scaffolding an Adaptive Card Extension +- Registering Views +- Changing the Card View and Quick View +- Basic action handling +- Changing the Property Pane +- Defer loading the Property Pane +- How to use `state` +- Difference between `properties` and `state` + +## See Also + +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/viva/get-started/build-html-quickview-adaptive-card-extension.md b/docs/spfx/viva/get-started/build-html-quickview-adaptive-card-extension.md new file mode 100644 index 000000000..f070d6f67 --- /dev/null +++ b/docs/spfx/viva/get-started/build-html-quickview-adaptive-card-extension.md @@ -0,0 +1,205 @@ +--- +title: Build an HTML Quick View SharePoint Framework Adaptive Card Extension +description: Adaptive Card Extensions (ACEs) are a SharePoint Framework component type, which enable developers to build rich, native extensions to Viva Connections' Dashboards and SharePoint Pages. In this tutorial, you'll learn how to use HTML to implement a QuickView. +ms.date: 09/13/2024 +ms.localizationpriority: high +--- +# Build an HTML Quick View SharePoint Framework Adaptive Card Extension + +The SharePoint Framework (SPFx) v1.20 release introduced a new option to use HTML to render the Viva Connection Adaptive Card Extension (ACE) Quick Views. This enables more advanced user experiences. You can even use whatever suitable JavaScript web framework you prefer (ie: React etc.) in your Quick View experiences. + +You can start using this option by updating your Quick View implementation to be inherited from xxx class, which will be automatically detected by the underlying platform. + +> [!IMPORTANT] +> This tutorial assumes you have installed the SPFx v1.20. For more information on installing the SPFx v1.20, see [SharePoint Framework v1.20 release notes](../../release-1.20.md). + +## Scaffold an Adaptive Card Extension project + +Create a new project directory for your project and change your current folder to that directory. + +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (*select the default option for all prompts omitted below*): + +- **Which type of client-side component to create?** Adaptive Card Extension +- **Which template do you want to use?** Generic Card Template +- **What is your Adaptive Card Extension name?** HTML Quick View + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This process might take few minutes. + +## Test the ACE in the hosted workbench + +Before digging into the code, run the scaffolded output and see what an Adaptive Card Extension looks like. + +The inner development loop with ACEs is similar to SPFx Web Parts. We can serve locally and run the code on the SharePoint Online hosted workbench. + +```console +gulp serve +``` + +Once local web server is running, navigate to the hosted Workbench: `https://{tenant}.sharepoint.com/_layouts/15/workbench.aspx` + +Open the **Web Part Toolbox** and select your ACE. + +Once added to the page, select the **Preview** link in the top-right area of the workbench to interact with the ACE. Next, select the **Quick View** button. This will open the default Adaptive Card implementation of the Quick View defined in the **src/adaptiveCardExtensions/htmlQuickView/quickView/template/QuickViewTemplate.json** file: + +![Screenshot of the default ACE & Quick View](../../../images/viva-extensibility/ace-basic-html-quickview-01.png) + +With the ACE project created and working, let's now update to use an HTML rendering instead of using the included Adaptive Card. + +## Update the Quick View to use HTML + +Start by adding the welcome light image from a default web part project: + +1. Create a new folder **assets** within the existing **quickView** folder. +1. Add the **welcome-light.png** file to this folder. + + > [!NOTE] + > You can use any image in this tutorial, or you can find the image in the sample project accompanying this tutorial: [Sample: HTML Quick View demo](https://github.com/pnp/sp-dev-fx-aces/tree/main/samples/BasicCard-HTML-QuickView). + +1. To be sure you won't use the default Adaptive Card template for the Quick View, delete the following file from the project: **./src/adaptiveCardExtensions/htmlQuickView/quickView/template/QuickViewTemplate.json** + +### Add a stylesheet to the project + +Now you'll make a few changes to the project to add a stylesheet to the project. This will simplify formatting the content in the HTML rendering that you'll add. + +1. Install the SPFx Fluent UI core library into the project that we'll use to apply some styles to our project. + 1. From the console, run the following command in the root of the project: + + ```console + npm install @microsoft/sp-office-ui-fabric-core@{{REPLACE_VERSION}} --save-prod --save-exact + ``` + + > [!IMPORTANT] + > Before running this command, check the version of the **@microsoft/sp-core-library** package in the project's **package.json** file. Replace the `{{REPLACE_VERSION}}` in the previous command with the version of the **@microsoft/sp-core-library**. This is to ensure you're using the same version of all SPFx libraries in your project. + +1. Add a new style sheet to the project, **QuickView.module.scss** in the same folder as the **QuickView.ts** file and add the following code that you'll use in the HTML rendering: + + ```scss + @import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'; + + .helloWorld { + overflow: hidden; + padding: 1em; + color: "[theme:bodyText, default: #323130]"; + color: var(--bodyText); + &.teams { + font-family: $ms-font-family-fallbacks; + } + } + + .welcome { + text-align: center; + } + + .welcomeImage { + width: 100%; + max-width: 420px; + } + + .links { + a { + text-decoration: none; + color: "[theme:link, default:#03787c]"; + color: var(--link); // note: CSS Custom Properties support is limited to modern browsers only + + &:hover { + text-decoration: underline; + color: "[theme:linkHovered, default: #014446]"; + color: var(--linkHovered); // note: CSS Custom Properties support is limited to modern browsers only + } + } + } + ``` + +At this point, your ACE component should look similar to the following with the new files added and after removing the default Adaptive Card: + +![Screenshot of the ACE & Quick View project](../../../images/viva-extensibility/ace-basic-html-quickview-02.png) + +### Update the Quick View to use HTML instead of an Adaptive Card in the rendering + +The last step is to update the Quick View component to import the style sheet and use HTML for the rendering instead of the Adaptive Card. + +1. Locate and open the **./src/adaptiveCardExtensions/htmlQuickView/quickView/QuickView.ts** file. +1. Update the `import` statement for the ACE base component. Locate the following line at the top of the file: + + ```typescript + import { ISPFxAdaptiveCard, BaseAdaptiveCardQuickView } from '@microsoft/sp-adaptive-card-extension-base'; + ``` + + Replace this line with the following line: + + ```typescript + import { BaseWebQuickView } from '@microsoft/sp-adaptive-card-extension-base'; + ``` + +1. Add the following two `import` statements after the existing `import` statements: + + ```typescript + import { escape } from '@microsoft/sp-lodash-subset'; + import styles from './QuickView.module.scss'; + ``` + +1. Locate the `QuickView` class declaration and change the base class it extends from the following: + + ```typescript + export class QuickView extends BaseWebQuickView< + IHtmlQuickViewAdaptiveCardExtensionProps, + IHtmlQuickViewAdaptiveCardExtensionState, + IQuickViewData + > { + ``` + + ... to the following: + + ```typescript + export class QuickView extends BaseWebQuickView< + IHtmlQuickViewAdaptiveCardExtensionProps, + IHtmlQuickViewAdaptiveCardExtensionState + > { + ``` + +1. Remove the existing `template()` method from the `QuickView` class. +1. Add the following `render()` method to the `QuickView` class to render the Quick View using HTML: + + ```typescript + render(): void { + this.domElement.innerHTML = ` +
    +
    + +

    Well done, ${escape(this.context.pageContext.user.displayName)}!

    +
    +
    +

    Welcome to HTML powered SPFx Quick Views!

    +

    + Starting with SPFx 1.20, you can use any HTML in the ACE Quick Views to build engaging employee experiences! +

    +

    Learn more about Viva Connections extensibility development:

    + +
    +
    `; + } + ``` + +## Test the new HTML enabled Quick View + +With all the changes now applied, retest solution in the hosted workbench to see the new HTML enabled Quick View: + +![Preview on HTML Quick Views](../../../images/120-release-notes/html-quick-views.png) + +## See Also + +- [Build your first SharePoint Adaptive Card Extension](build-first-sharepoint-adaptive-card-extension.md) +- [Advanced Quick View Functionality](advanced-quick-view-functionality.md) +- [Making Quick View compatible with dark mode in mobile devices](making-quickview-compatable-darkmode-mobile.md) +- [Sample: HTML Quick View demo](https://github.com/pnp/sp-dev-fx-aces/tree/main/samples/BasicCard-HTML-QuickView) diff --git a/docs/spfx/viva/get-started/build-people-search-adaptive-card-extension.md b/docs/spfx/viva/get-started/build-people-search-adaptive-card-extension.md new file mode 100644 index 000000000..3512b5ad3 --- /dev/null +++ b/docs/spfx/viva/get-started/build-people-search-adaptive-card-extension.md @@ -0,0 +1,1008 @@ +--- +title: Create a People Search Adaptive Card Extension +description: Step by step guide on creating People Search Adaptive Card Extension. +ms.date: 12/14/2023 +ms.localizationpriority: high +--- +# Create a People Search Adaptive Card Extension + +SharePoint Framework (SPFx) v1.18 introduces a new Search Card Template that can be used to implement various search scenarios. + +This tutorial provides step-by-step guidance on implementing People Search with ACEs and Microsoft Graph. + +> [!NOTE] +> This tutorial assumes that you have installed the SPFx v1.18 preview version. +> +> For more information on installing the SPFx v1.18, see [SharePoint Framework v1.18 release notes](../../release-1.18.md). + +Before you start, complete the procedures in the following articles to ensure that you understand the basic flow of creating a custom Adaptive Card Extension and using Microsoft Graph in SharePoint Framework solutions: + +- [Build your first SharePoint Adaptive Card Extension](./build-first-sharepoint-adaptive-card-extension.md) +- [Use Microsoft Graph in your solution](../../web-parts/get-started/using-microsoft-graph-apis.md) + +## Scaffold an Adaptive Card Extension project + +Create a new project directory for your project and change your current folder to that directory. + +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created. + +```console +yo @microsoft/sharepoint +``` + +When prompted, enter the following values (select the default option for all questions, which aren't mentioned): + +- **What is your solution name?** peoplesearch-tutorial +- **Which type of client-side component to create?** Adaptive Card Extension +- **Which template do you want to use?** Search Card Template +- **What is your Adaptive Card Extension name?** People Search + +At this point, Yeoman installs the required dependencies and scaffolds the solution files. This process might take few minutes. + +Next, run **gulp serve** from the command line in the root of the project. Once the hosted workbench loads, you'll see the **People Search** card: + +![See the People Search card icon in the workbench toolbox](../../../../docs/images/viva-extensibility/people-search/toolbox.png) + +If you add the ACE to the workbench, you see it already prepared for mock search scenario. + +![Default People Search card](../../../../docs/images/viva-extensibility/people-search/ace-default.png) + +If you switch to Preview mode of the workbench, you can engage with it: + +- type in the search box and select on the search icon to see the results Quick View mockup + + ![Default Search Results Quick View](../../../../docs/images/viva-extensibility/people-search/qv-results-default.png) + +- Select on the **Suggested** item to see a single item view + + ![Default Item Quick View](../../../../docs/images/viva-extensibility/people-search/qv-item-default.png) + +## Explore the scaffolded code + +### Explore the Card View + +- Locate and open the following file in your project: **./src/adaptiveCardExtensions/peopleSearch/cardView/CardView.ts**. +- The Card View implements `BaseComponentsCardView` class and implements `cardViewParameters` getter to specify the card configuration + +```typescript +export class CardView extends BaseComponentsCardView { + public get cardViewParameters(): ISearchCardViewParameters { + return SearchCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + header: { + componentName: 'text', + text: strings.PrimaryText + }, + body: { + componentName: 'searchBox', + placeholder: strings.Placeholder, + id: SEARCH_BOX_ID, + button: { + action: { + type: 'QuickView', + parameters: { + view: SEARCH_RESULTS_QUICK_VIEW_REGISTRY_ID + } + } + } + }, + footer: { + componentName: 'searchFooter', + title: strings.Suggested, + imageInitials: 'MB', + text: strings.Title, + secondaryText: strings.SubTitle, + onSelection: { + type: 'QuickView', + parameters: { + view: ITEM_QUICK_VIEW_REGISTRY_ID + } + } + } + }); + } + + public get onCardSelection(): IQuickViewCardAction | IExternalLinkCardAction | undefined { + return undefined; + } +} +``` + +The **body** section of the Card View specifies the search box. The search button is configured to open the Quick View with the ID `SEARCH_RESULTS_QUICK_VIEW_REGISTRY_ID`. + +The **footer** section of the Card View specifies the suggested item. The suggested item is configured to open the Quick View with the ID `ITEM_QUICK_VIEW_REGISTRY_ID`. + +### Explore the Quick Views + +There are two mock Quick Views in the scaffolded code: `SearchResultsQuickView` and `ItemQuickView`. + +The implementation of both is standard and can be found in the following files: +**./src/adaptiveCardExtensions/peopleSearch/quickView/SearchResultsQuickView.ts** and **./src/adaptiveCardExtensions/peopleSearch/quickView/ItemQuickView.ts**. + +The important part of the `SearchResultsQuickView` implementation is `data` getter that specifies `queryString` value based on the `state` of the ACE: + +```typescript +public get data(): ISearchResultsQuickViewData { + return { + // ... + queryString: this.state.queryString || '' + }; +} +``` + +This approach allows to "share" the query string between the Card View and the Quick View. Below we show how to set this state's property from the ACE. + +### Explore the ACE class + +The ACE class is located in the following file: **./src/adaptiveCardExtensions/peopleSearch/PeopleSearchAdaptiveCardExtension.ts** and mostly has the same code as [Generic Card View](./build-first-sharepoint-adaptive-card-extension.md). + +However, there's important difference: `PeopleSearchAdaptiveCardExtension` overrides `onBeforeAction` method to set `queryString` state's value before opening a `SearchResultsQuickView`. + +```typescript +public onBeforeAction(action: IOnBeforeActionArguments): void { + if (action.type === 'QuickView') { + // + // for the QuickView action we can get search query from the data property. + // it allows to display the same query string in the Quick View's text input. + // + const quickViewActionArguments: IQuickViewActionArguments = action as IQuickViewActionArguments; + if (quickViewActionArguments.viewId === SEARCH_RESULTS_QUICK_VIEW_REGISTRY_ID) { + this.setState({ + queryString: quickViewActionArguments.data && quickViewActionArguments.data[SEARCH_BOX_ID] + }); + } + } +} +``` + +With this code in place, the Quick View displays the same query string as the Card View. + +## Implement People Search Service + +### Request permissions scopes + +The next step is to implement the data source for the People Search ACE. The data source is responsible for fetching the data from the Microsoft Graph and returning it to the ACE. + +We use the [List people](/graph/api/user-list-people) endpoint to get search results and the [Get a user](/graph/api/user-get) endpoint to display a Suggested item. + +For these endpoints we need to request `People.Read` and `User.Read` scopes respectively. +Locate and open the following file in your project: **./src/adaptiveCardExtensions/peopleSearch/config/package-solution.json**. + +Add `webApiPermissions` property as follows + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", + "solution": { + // ... + "webApiPermissionRequests": [{ + "resource": "Microsoft Graph", + "scope": "User.Read" + }, { + "resource": "Microsoft Graph", + "scope": "People.Read" + }] + } + // ... +} +``` + +### Defining Person model + +- Navigate to **./src/adaptiveCardExtensions/peopleSearch** and create a new folder called **model** with **IPerson.ts** file in there. + +The file contains the "model" or representation of a person/user. + +```typescript +export interface IPerson { + id: string; + displayName: string; + jobTitle?: string; + officeLocation?: string; + picture?: string; + emailAddress?: string; + phone?: string; +} +``` + +### Implement People Search Service + +We use Service Locator pattern to inject the data service into the ACE. The pattern is represented by the [ServiceScope](/javascript/api/sp-core-library/servicescope) class in SPFx. + +Navigate to **./src/adaptiveCardExtensions/peopleSearch** and create a new folder called **peopleSearchService** with two files in there: **IPeopleSearchService.ts** and **PeopleSearchService.ts**. + +The **IPeopleSearchService.ts** file contains the "contract" for the service. + +```typescript +import { IPerson } from '../model/IPerson'; + +export interface IPeopleSearchService { + search: (queryString: string) => Promise; + getSuggested: () => Promise; +} +``` + +**PeopleSearchService.ts** file contains the implementation of the service with `ServiceKey` static field to register the service in the Service Scope. + +Before the implementation of the service, install the following dependencies from command line: + +```console +npm install @microsoft/sp-http --save --save-exact +``` + +The implementation of the service is as follows: + +```typescript +import { ServiceKey, ServiceScope } from '@microsoft/sp-core-library'; +import { MSGraphClientFactory, MSGraphClientV3 } from '@microsoft/sp-http'; + +import { IPeopleSearchService } from './IPeopleSearchService'; +import { IPerson } from '../model/IPerson'; +/** + * type of result returned by the Microsoft Graph /people API + */ +interface IGraphPerson { + id: string; + displayName: string; + jobTitle?: string; + officeLocation?: string; + imAddress?: string; + scoredEmailAddresses?: [{ + address: string; + relevanceScore: number; + }]; + phones?: [{ + type: string; + number: string; + }]; +} + +/** + * type of result returned by the Microsoft Graph /me API + */ +interface IGraphUser { + id: string; + displayName: string; + jobTitle?: string; + mail: string; + officeLocation?: string; + userPrincipalName: string; + businessPhones?: string[]; +} + +/** + * Converts a graph person to a person + */ +const convertGraphPersonToPerson = (graphPerson: IGraphPerson): IPerson => { + const { + id, + displayName, + jobTitle, + officeLocation, + imAddress, + scoredEmailAddresses, + phones + } = graphPerson; + + return { + id, + displayName, + jobTitle: jobTitle || '', + officeLocation: officeLocation || '', + picture: `/_layouts/15/userphoto.aspx?size=S&accountname=${imAddress.replace('sip:', '')}`, + emailAddress: scoredEmailAddresses?.length ? scoredEmailAddresses[0].address : '', + phone: phones?.length ? phones[0].number : '' + }; +}; + +/** + * Converts a graph user to a person + */ +const convertGraphUserToPerson = (graphUser: IGraphUser): IPerson => { + const { + id, + displayName, + jobTitle, + mail, + officeLocation, + userPrincipalName, + businessPhones + } = graphUser; + + return { + id, + displayName, + jobTitle: jobTitle || '', + officeLocation: officeLocation || '', + picture: `/_layouts/15/userphoto.aspx?size=S&accountname=${userPrincipalName}`, + emailAddress: mail, + phone: businessPhones?.length ? businessPhones[0] : '' + }; +}; + +export class PeopleSearchService implements IPeopleSearchService { + // Create a ServiceKey to register in the Service Scope + public static readonly serviceKey: ServiceKey = ServiceKey.create('PeopleSearchTutorial:PeopleSearchService', PeopleSearchService); + + private _msGraphClientFactory: MSGraphClientFactory; + + public constructor(serviceScope: ServiceScope) { + serviceScope.whenFinished(() => { + // Get the MSGraphClientFactory service instance from the service scope + this._msGraphClientFactory = serviceScope.consume(MSGraphClientFactory.serviceKey); + }); + } + + public search(queryString: string): Promise { + return this._msGraphClientFactory.getClient('3') + .then((client: MSGraphClientV3) => { + // search for people, order by display name, return persons only (no groups, etc.), return top 25 results + return client.api(`/me/people?$search="${queryString}"&orderBy=displayName&$filter=personType/class eq 'Person'&$top=25`).version('v1.0').get(); + }) + .then ((results: { value: IGraphPerson[] }) => { + const people: IGraphPerson[] = results.value; + + return people.map((person: IGraphPerson) => { + return convertGraphPersonToPerson(person); + }); + }) + .catch((err) => { + console.log(err); + throw new Error('Error searching people'); + }); + } + + public getSuggested(): Promise { + // we will return the current user as a suggestion for simplicity + return this._msGraphClientFactory.getClient('3') + .then((client: MSGraphClientV3) => { + return client.api('/me').version('beta').get(); + }) + .then((user: IGraphUser) => { + return convertGraphUserToPerson(user); + }) + .catch((err) => { + console.log(err); + throw new Error('Error getting suggested person'); + }); + } +} +``` + +### Update ACE's logic to use the service + +- Locate and open **./src/adaptiveCardExtensions/peopleSearch/PeopleSearchAdaptiveCardExtension.ts** file. +- Update the `IPeopleSearchAdaptiveCardExtensionState` to add properties for a suggestion and search results. + + ```typescript + export interface IPeopleSearchAdaptiveCardExtensionState { + queryString?: string; + suggested?: IPerson; + results?: IPerson[]; + } + ``` + +- Update `onInit` to request the service from the Service Scope get the suggestion to display on the card. + + ```typescript + public onInit(): Promise { + this.state = { }; + + // request suggestion + this.context.serviceScope.whenFinished(() => { + // get the people search service + const peopleSearchService: IPeopleSearchService = this.context.serviceScope.consume(PeopleSearchService.serviceKey); + // request suggestion + peopleSearchService.getSuggested() + .then((suggested: IPerson) => { + this.setState({ + suggested: suggested + }); + }) + .catch((error: any) => { + // TODO: handle error + }); + }); + // ... + } + ``` + +### Update the Search Results Quick View to use the service and display the results + +- Locate and open **./src/adaptiveCardExtensions/peopleSearch/quickView/template/SearchResultsQuickViewTemplate.json**. Update it to display search results. + + ```json + { + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "Input.Text", + "id": "queryString", + "inlineAction": { + "type": "Action.Submit", + "title": "${searchActionTitle}", + "data": { + "id": "search" + } + }, + "value": "${queryString}", + "placeholder": "${placeholder}" + }, + { + "type": "TextBlock", + "text": "Loading...", + "size": "small", + "separator": true, + "spacing": "extraLarge", + "$when": "${isLoading}" + }, + { + "type": "TextBlock", + "text": "We found ${numberOfResults} result(s)", + "size": "small", + "isSubtle": true, + "separator": true, + "spacing": "extraLarge", + "$when": "${!isLoading}" + }, + { + "type": "Container", + "$data": "${results}", + "items": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "Image", + "style": "Person", + "url": "${picture}", + "size": "Small", + "height": "48px", + "width": "48px" + } + ], + "width": "auto" + }, + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "${displayName}", + "wrap": false, + "size": "medium" + }, + { + "type": "TextBlock", + "spacing": "None", + "text": "${if(length(jobTitle)!=0,jobTitle,emailAddress)}", + "isSubtle": true, + "wrap": false, + "size": "default" + } + ], + "width": "stretch" + } + ], + "bleed": true, + "spacing": "none" + } + ], + "style": "default", + "separator": true, + "spacing": "Medium" + } + ] + } + ``` + +- Locate and open **./src/adaptiveCardExtensions/peopleSearch/quickView/SearchResultsQuickView.ts**. +- Update the `ISearchResultsQuickViewData` interface to add properties for the search results. + + ```typescript + export interface ISearchResultsQuickViewData { + searchActionTitle: string; + placeholder: string; + queryString: string; + /** + * The number of results returned by the search + */ + numberOfResults: number; + /** + * The results returned by the search + */ + results: IPerson[]; + /** + * Indicates if the search is in progress + */ + isLoading: boolean; + } + ``` + +- Add `_lastQueryString` field to the `SearchResultsQuickView` class to store the last processed query string. + + ```typescript + private _lastQueryString: string | undefined; + ``` + +- Implement `_performSearch` method to request search results from the service. + + ```typescript + private _performSearch = (queryString: string): void => { + // initiate search + this.context.serviceScope.consume(PeopleSearchService.serviceKey).search(queryString) + .then((results: IPerson[]) => { + // storing the last processed query string + this._lastQueryString = queryString; + this.setState({ + results: results + }); + }) + .catch(() => { + // TODO: handle error + }); + }; + ``` + +- Update `data` getter to initiate search if needed and return the data to display. + + ```typescript + public get data(): ISearchResultsQuickViewData { + const isNewSearch: boolean = this._lastQueryString !== this.state.queryString; + // initiate search if the query string has changed + if (isNewSearch) { + this._performSearch(this.state.queryString); + } + + const { + results + } = this.state; + + return { + searchActionTitle: strings.SearchAction, + placeholder: strings.Placeholder, + queryString: this.state.queryString || '', + numberOfResults: isNewSearch ? 0 : results?.length, + results: isNewSearch ? [] : results, + isLoading: isNewSearch + }; + } + ``` + +- Run **gulp serve** to test the extension. Enter some text in the search box and select search icon button. You should see the following results. + +![Search Results Quick View](../../../../docs/images/viva-extensibility/people-search/search-results.png) + +### Perform search for the Search Results Quick View + +1. Locate and open **./src/adaptiveCardExtensions/peopleSearch/quickView/SearchResultsQuickView.ts**. Implement `onAction` method to handle `Submit` action with `id` set to `search`: + + ```typescript + public onAction(action: IActionArguments): void { + if (action.type !== 'Submit' || !action.data) { + return; + } + const { + data + } = action; + switch (data.id) { + case 'search': + // update query string + this.setState({ + queryString: data.queryString + }); + break; + } + } + ``` + +Now if you select on **Search** button in the Search Results Quick View, the results are refreshed. + +### Open Person card from the Search Results Quick View + +The next step is to open the Person card (`ItemQuickView`) when selecting a search result from the Search Results Quick View. + +- Locate and open **./src/adaptiveCardExtensions/peopleSearch/PeopleSearchAdaptiveCardExtension.ts**. Update `IPeopleSearchAdaptiveCardExtensionState` to store the selected person: + + ```typescript + export interface IPeopleSearchAdaptiveCardExtensionState { + queryString?: string; + suggested?: IPerson; + results?: IPerson[]; + selectedPerson?: IPerson; + } + ``` + +- Locate and open **./src/adaptiveCardExtensions/peopleSearch/quickView/template/SearchResultsQuickViewTemplate.json**. +- Add `selectAction` property to the `ColumnSet` (see comment in the code) + + ```json + { + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.5", + "body": [ + { + "type": "Input.Text", + "id": "queryString", + "inlineAction": { + "type": "Action.Submit", + "title": "${searchActionTitle}", + "data": { + "id": "search" + } + }, + "value": "${queryString}", + "placeholder": "${placeholder}" + }, + { + "type": "TextBlock", + "text": "Loading...", + "size": "small", + "separator": true, + "spacing": "extraLarge", + "$when": "${isLoading}" + }, + { + "type": "TextBlock", + "text": "We found ${numberOfResults} result(s)", + "size": "small", + "isSubtle": true, + "separator": true, + "spacing": "extraLarge", + "$when": "${!isLoading}" + }, + { + "type": "Container", + "$data": "${results}", + "items": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "Image", + "style": "Person", + "url": "${picture}", + "size": "Small", + "height": "48px", + "width": "48px" + } + ], + "width": "auto" + }, + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "${displayName}", + "wrap": false, + "size": "medium" + }, + { + "type": "TextBlock", + "spacing": "None", + "text": "${if(length(jobTitle)!=0,jobTitle,emailAddress)}", + "isSubtle": true, + "wrap": false, + "size": "default" + } + ], + "width": "stretch" + } + ], + "bleed": true, + "spacing": "none", + // added select action + "selectAction": { + "type": "Action.Submit", + "data": { + "id": "selectPerson", + "personId": "${id}" + } + } + } + ], + "style": "default", + "separator": true, + "spacing": "Medium" + } + ] + } + ``` + +- Locate and open **./src/adaptiveCardExtensions/peopleSearch/quickView/SearchResultsQuickView.ts**. +- Update `onAction` method to handle `selectPerson` event: set `selectedPerson` state's property and open the Person card as follows: + + ```typescript + public onAction(action: IActionArguments): void { + if (action.type !== 'Submit' || !action.data) { + return; + } + const { + data + } = action; + switch (data.id) { + case 'search': + // update query string + this.setState({ + queryString: data.queryString + }); + break; + case 'selectPerson': { + // set selected person and open the item Quick View + const person: IPerson = this.state.results.filter(p => p.id === data.personId)[0]; + this.setState({ + selectedPerson: person + }); + this.quickViewNavigator.push(ITEM_QUICK_VIEW_REGISTRY_ID); + break; + } + } + } + ``` + +- Locate and open **./src/adaptiveCardExtensions/peopleSearch/quickView/template/ItemQuickViewTemplate.json** +- Update the markup to display selected person's information as follows + + ```json + { + "type": "AdaptiveCard", + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.5", + "$data": "${$root.person}", + "body": [ + { + "type": "Container", + "style": "emphasis", + "items": [ + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "Image", + "style": "Person", + "url": "${picture}", + "size": "Small", + "height": "48px", + "width": "48px" + } + ], + "width": "auto" + }, + { + "type": "Column", + "items": [ + { + "type": "TextBlock", + "text": "${displayName}", + "wrap": false, + "size": "medium" + }, + { + "type": "TextBlock", + "spacing": "None", + "text": "${if(length(jobTitle)!=0,jobTitle,emailAddress)}", + "isSubtle": true, + "wrap": false, + "size": "default" + } + ], + "width": "stretch" + } + ], + "bleed": true, + "spacing": "none" + } + ] + }, + { + "type": "TextBlock", + "size": "Medium", + "weight": "Bolder", + "text": "Contact" + }, + { + "type": "Table", + "gridStyle": "default", + "firstRowAsHeader": false, + "showGridLines": false, + "verticalCellContentAlignment": "center", + "columns": [ + { + "width": "20px", + "horizontalCellContentAlignment": "center", + "verticalCellContentAlignment": "center" + }, + { + "width": 1 + } + ], + "rows": [ + { + "type": "TableRow", + "cells": [ + { + "type": "TableCell", + "items": [ + { + "type": "Image", + "url": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDQ4IDIwNDgiIGNsYXNzPSJzdmdfZGQ3OTBlZTMiIGZvY3VzYWJsZT0iZmFsc2UiPjxwYXRoIGQ9Ik0yMDQ4IDM4NHYxMjgwSDBWMzg0aDIwNDh6TTE0MyA1MTJsODgxIDQ0MSA4ODEtNDQxSDE0M3ptMTc3NyAxMDI0VjY0OGwtODk2IDQ0Ny04OTYtNDQ3djg4OGgxNzkyeiI+PC9wYXRoPjwvc3ZnPg==", + "size": "Small", + "width": "16px", + "height": "16px" + } + ] + }, + { + "type": "TableCell", + "items": [ + { + "type": "TextBlock", + "text": "${emailAddress}", + "weight": "default", + "wrap": false + } + ] + } + ], + "style": "default" + }, + { + "type": "TableRow", + "cells": [ + { + "type": "TableCell", + "items": [ + { + "type": "Image", + "url": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDQ4IDIwNDgiIGNsYXNzPSJzdmdfZGQ3OTBlZTMiIGZvY3VzYWJsZT0iZmFsc2UiPjxwYXRoIGQ9Ik0xNjA3IDEyMTNxNDQgMCA4NCAxNnQ3MiA0OGwyMjAgMjIwcTMxIDMxIDQ3IDcxdDE3IDg1cTAgNDQtMTYgODR0LTQ4IDcybC0xNCAxNHEtNTQgNTQtOTkgOTZ0LTk0IDcwLTEwOSA0NC0xNDMgMTVxLTEyNSAwLTI1Ny0zOXQtMjYyLTEwOC0yNTYtMTY0LTIzNy0yMDctMjA2LTIzOC0xNjItMjU2VDM4IDc3NSAwIDUyM3EwLTgzIDE0LTE0MnQ0My0xMDggNzAtOTMgOTYtOTlsMTYtMTZxMzEtMzEgNzEtNDh0ODUtMTdxNDQgMCA4NCAxN3Q3MiA0OGwyMjAgMjIwcTMxIDMxIDQ3IDcxdDE3IDg1cTAgNDQtMTUgNzh0LTM3IDYzLTQ4IDUxLTQ5IDQ1LTM3IDQ0LTE1IDQ5cTAgMzggMjcgNjVsNTUxIDU1MXEyNyAyNyA2NSAyNyAyNiAwIDQ4LTE1dDQ1LTM3IDQ1LTQ4IDUxLTQ5IDYyLTM3IDc5LTE1em0tODMgNzA3cTcyIDAgMTIwLTEzdDg4LTM5IDc2LTY0IDg1LTg2cTI3LTI3IDI3LTY1IDAtMTgtMTQtNDJ0LTM4LTUyLTUxLTU1LTU2LTU0LTUxLTQ3LTM3LTM1cS0yNy0yNy02Ni0yNy0yNiAwLTQ4IDE1dC00NCAzNy00NSA0OC01MiA0OS02MiAzNy03OSAxNXEtNDQgMC04NC0xNnQtNzItNDhMNTcwIDkyN3EtMzEtMzEtNDctNzF0LTE3LTg1cTAtNDQgMTUtNzh0MzctNjMgNDgtNTEgNDktNDYgMzctNDQgMTUtNDhxMC0zOS0yNy02Ni0xMy0xMy0zNC0zNnQtNDctNTEtNTQtNTYtNTYtNTItNTEtMzctNDMtMTVxLTM4IDAtNjUgMjdsLTg1IDg1cS0zNyAzNy02NCA3NnQtNDAgODctMTQgMTIwcTAgMTEyIDM2IDIzMXQxMDEgMjM4IDE1MyAyMzQgMTkyIDIxOSAyMTkgMTkwIDIzNCAxNTAgMjM2IDk5IDIyNiAzNnoiPjwvcGF0aD48L3N2Zz4=", + "size": "Small", + "width": "16px", + "height": "16px" + } + ] + }, + { + "type": "TableCell", + "items": [ + { + "type": "TextBlock", + "text": "${phone}", + "wrap": false + } + ] + } + ], + "style": "default" + }, + { + "type": "TableRow", + "cells": [ + { + "type": "TableCell", + "items": [ + { + "type": "Image", + "url": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDQ4IDIwNDgiIGNsYXNzPSJzdmdfZGQ3OTBlZTMiIGZvY3VzYWJsZT0iZmFsc2UiPjxwYXRoIGQ9Ik0xMDI0IDBxODggMCAxNzAgMjN0MTUzIDY0IDEyOSAxMDAgMTAwIDEzMCA2NSAxNTMgMjMgMTcwcTAgNjktMTYgMTMxdC00OCAxMjVsLTU3NiAxMTUyTDQ0OCA4OTZxLTMxLTYyLTQ3LTEyNHQtMTctMTMycTAtODggMjMtMTcwdDY0LTE1MyAxMDAtMTI5VDcwMSA4OHQxNTMtNjUgMTcwLTIzem00NzYgODQ2di0xbDEtMXEyNS00NyAzOC05OXQxMy0xMDVxMC0xMDktNDEtMjA1dC0xMTQtMTY4LTE2OC0xMTMtMjA1LTQycS0xMDkgMC0yMDUgNDFUNjUxIDI2NyA1MzggNDM1dC00MiAyMDVxMCA1MyAxMyAxMDV0MzggOTl2MWwxIDEgNDc2IDk1MiA0NzYtOTUyem0tNDc2LTU4MnE3OCAwIDE0NiAyOXQxMjAgODEgODAgMTE5IDMwIDE0N3EwIDc4LTI5IDE0NnQtODEgMTIwLTExOSA4MC0xNDcgMzBxLTc4IDAtMTQ2LTI5dC0xMjAtODEtODAtMTE5LTMwLTE0N3EwLTc4IDI5LTE0NnQ4MS0xMjAgMTE5LTgwIDE0Ny0zMHptMCA2NDBxNTUgMCAxMDMtMjB0ODQtNTcgNTYtODQgMjEtMTAzcTAtNTUtMjAtMTAzdC01Ny04NC04NC01Ni0xMDMtMjFxLTU1IDAtMTAzIDIwdC04NCA1Ny01NiA4NC0yMSAxMDNxMCA1NSAyMCAxMDN0NTcgODQgODQgNTYgMTAzIDIxeiI+PC9wYXRoPjwvc3ZnPg==", + "size": "Small", + "width": "16px", + "height": "16px" + } + ] + }, + { + "type": "TableCell", + "items": [ + { + "type": "TextBlock", + "text": "${officeLocation}", + "wrap": false + } + ] + } + ], + "style": "default" + } + ] + } + ] + } + ``` + +- Locate and open **./src/adaptiveCards/peopleSearch/quickView/ItemQuickView.ts** +- Update `IItemQuickViewData` as follows + + ```typescript + export interface IItemQuickViewData { + person: IPerson; + } + ``` + +- Update `data` getter to get `selectedPerson` from the state as follows + + ```typescript + public get data(): IItemQuickViewData { + return { + person: this.state.selectedPerson || this.state.suggested // we can open either selected Person or suggested Person + }; + } + ``` + +Now if you select on a person in the list, you should see a Quick View of the person's details: + +![Person card](../../../../docs/images/viva-extensibility/people-search/qv-person.png) + +## Display Suggested person in the Card View + +- Locate and open **./src/adaptiveCards/peopleSearch/cardView/CardView.ts** +- Update `cardViewParameters` getter to use `suggested` value from the state as follows + + ```typescript + public get cardViewParameters(): ISearchCardViewParameters { + // default value for the footer + const footer: ICardSearchFooterConfiguration = { + componentName: 'searchFooter', + title: strings.Suggested, + text: 'No suggestions found', + imageInitials: 'NA' + }; + + // if there is a suggested person, update the footer + const { suggested } = this.state; + if (suggested) { + footer.text = suggested.displayName; + footer.secondaryText = suggested.jobTitle || suggested.emailAddress; + footer.imageUrl = suggested.picture; + footer.imageInitials = `${suggested.givenName.charAt(0)}${suggested.surname.charAt(0)}`; + footer.onSelection = { + type: 'QuickView', + parameters: { + view: ITEM_QUICK_VIEW_REGISTRY_ID + } + }; + } + + return SearchCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + header: { + componentName: 'text', + text: strings.PrimaryText + }, + body: { + componentName: 'searchBox', + placeholder: strings.Placeholder, + id: SEARCH_BOX_ID, + button: { + action: { + type: 'QuickView', + parameters: { + view: SEARCH_RESULTS_QUICK_VIEW_REGISTRY_ID + } + } + } + }, + footer: footer + }); + ``` + +Now you see the current user in the Suggested section of the Card View. If you select on the user information, you see the Quick View of the person's details. + +![Suggested card](../../../../docs/images/viva-extensibility/people-search/qv-suggested.png) diff --git a/docs/spfx/viva/get-started/fluent-icons-limitations.md b/docs/spfx/viva/get-started/fluent-icons-limitations.md new file mode 100644 index 000000000..0cd1655b3 --- /dev/null +++ b/docs/spfx/viva/get-started/fluent-icons-limitations.md @@ -0,0 +1,217 @@ +--- +title: Adaptive Card Extensions Iconography Limitations +description: The article describes existing limitations for using Fluent Icons in Adaptive Card Extensions. +ms.date: 09/12/2023 +ms.localizationpriority: high +--- + +# Adaptive Card Extensions Iconography Limitations + +Some existing limitations exist for using Fluent UI Iconography in Adaptive Card Extensions. + +Currently, ACEs support the "Card Designer" set of icons listed in this article. This set of icons is a subset of [Fluent 2 (Fluent UI v9) iconography](https://github.com/microsoft/fluentui-system-icons/blobl/main/icons_filled.md). It means using ["Fluent 1" (Fluent UI v8 and mentioned) icons](https://developer.microsoft.com/fluentui#/styles/web/icons) is limited. + +## Manifests value officeFabricIconFontName is partially supported + +The `officeFabricIconFontName` manifest's property allows developers to use the Fluent icon displayed for the ACE in the Toolbox during an operator's editing session. By default (if not overridden in the code), the same icon is used in the card bar: + +![Card bar](../../../images/viva-extensibility/icons-limitations-card-bar.png) + +There are two limitations to this property: + +1. Viva Connections for Mobile doesn't support arbitrary Fluent UI icons. Therefore, the icon could be missing in the card bar on mobile. +![Card bar on mobile](../../../images/viva-extensibility/icons-limitations-card-bar-mobile.png) +1. The toolbox doesn't support the "Card Designer" icons. Therefore, the icon could be missing in the toolbox. +![Missing icon in the Toolbox](../../../images/viva-extensibility/icons-limitations-toolbox.png) + +The workaround is to override the [card bar's icon](/javascript/api/sp-adaptive-card-extension-base/icardbarparameters#@microsoft-sp-adaptive-card-extension-base-icardbarparameters-icon-member) property in the code. + +## "Fluent 1" icons aren't supported for Text Input + +In the SharePoint Framework (SPFx) v1.18, we introduced the ability to add a "text input" component to the Card View. This component allows developers to specify iconBefore, iconAfter, and button icons. + +All these icons (names) should be either from the "Card Designer" set or a URL to a custom image (preferably an \*.svg). + +## "Card Designer" Icons' Set + +Here's the set of icons that ACEs fully support. This is a subset of [Fluent 2 iconography](https://github.com/microsoft/fluentui-system-icons/blob/main/icons_filled.md). + +![Supported icons](../../../../docs/images/viva-extensibility/icons-limitations-supported-icons.png) + +| Icon Name | +| --- | +| airplane_take_off | +| alert | +| alert_urgent | +| approvals_app | +| apps | +| apps_add_in | +| archive | +| attach | +| backpack | +| balloon | +| beach | +| bed | +| block | +| board | +| bookmark | +| bug | +| building | +| building_bank | +| building_shop | +| building_skyscraper | +| calendar_checkmark | +| calendar_clock | +| calendar_edit | +| calendar_question_mark | +| calendar_reply | +| calendar_sync | +| calendar_work_week | +| call | +| camera | +| cart | +| channel | +| channel_add | +| channel_alert | +| channel_share | +| chat | +| city | +| clipboard | +| clipboard_paste | +| clock | +| cloud_download | +| comment_mention | +| comment_multiple | +| communication | +| compass_northwest | +| compose | +| conference_room | +| contact_card_group | +| copy | +| cube | +| currency_dollar_euro | +| dentist | +| desktop | +| desktop_mac | +| doctor | +| document | +| document_add | +| document_catch_up | +| document_question_mark | +| drafts | +| drink_beer | +| drink_coffee | +| dumbbell | +| emoji | +| emoji_add | +| error_circle | +| filter | +| flag | +| flag_off | +| flash | +| flash_checkmark | +| glasses | +| globe | +| grid | +| guest | +| hat_graduation | +| headset | +| heart | +| highlight | +| home | +| home_checkmark | +| image | +| image_edit | +| important | +| info | +| inking_tool | +| inprivate_account | +| key | +| laptop | +| leaf_two | +| library | +| lightbulb | +| link | +| location | +| location_off | +| lock_closed | +| mail | +| mail_inbox | +| map_drive | +| math_formula | +| meet_now | +| megaphone | +| mic_off | +| mic_on | +| mic_prohibited | +| money | +| movies_and_tv | +| music_note_2 | +| my_location | +| options | +| page_fit | +| paint_brush | +| paint_bucket | +| payment | +| people | +| people_add | +| people_call | +| people_community | +| people_team | +| person | +| person_add | +| person_available | +| person_call | +| person_clock | +| person_mail | +| person_prohibited | +| person_question_mark | +| person_support | +| premium | +| reading_list | +| record | +| remote | +| reward | +| ribbon | +| rocket | +| ruler | +| run | +| savings | +| search | +| send | +| settings | +| shield | +| shifts | +| slide_text | +| snooze | +| speaker_0 | +| speaker_1 | +| sport | +| star | +| stop | +| store_microsoft | +| sync_off | +| table | +| table_simple | +| tab | +| tag | +| target | +| tasks | +| tent | +| tetris_app | +| thumb_like | +| timer | +| trophy | +| tv | +| vault | +| vehicle_bicycle | +| vehicle_bus | +| vehicle_cab | +| vehicle_car | +| vehicle_subway | +| video | +| video_person | +| voicemail | +| warning | +| weather_moon | +| weather_moon_off | diff --git a/docs/spfx/viva/get-started/making-quickview-compatable-darkmode-mobile.md b/docs/spfx/viva/get-started/making-quickview-compatable-darkmode-mobile.md new file mode 100644 index 000000000..71e26a4fc --- /dev/null +++ b/docs/spfx/viva/get-started/making-quickview-compatable-darkmode-mobile.md @@ -0,0 +1,156 @@ +--- +title: Making Quick View compatible with dark mode in mobile devices +description: Making Adaptive Card Extension Quick View compatible for both dark and light mode by using different resources for both scenarios. +ms.date: 08/28/2024 +ms.localizationpriority: high +--- +# Making Quick View compatible with dark mode in mobile devices + +> [!IMPORTANT] +> The following tutorial is targeted specifically for Quick View in Mobile for Viva Connections iOS and Android. + +An API ([`context.sdks.microsoftTeams.teamsJs.app.getContext()`](/javascript/api/sp-adaptive-card-extension-base/ipartialsdks)) is available staring with the SPFx 1.18.1 version, to get the information about the theme of the mobile app. This helps with using associated assets like images compliant to the theme. If you want to use two different sets of data while keeping the existing view style, follow these steps: + +- Let’s create a basic card with an image in Quick View. Locate and open the following file: **./src/adaptiveCardExtensions/helloWorld/quickView/template/QuickViewTemplate.json**. +- Replace the contents of this file with the following JSON: + + ```json + { + "type": "AdaptiveCard", + "body": [ + { + "type": "TextBlock", + "weight": "Bolder", + "text": "${title}" + }, + { + "type": "ColumnSet", + "columns": [ + { + "type": "Column", + "items": [ + { + "type": "Image", + "url": "${imageUrl}" + }, + { + "type": "TextBlock", + "weight": "Bolder", + "text": "${subTitle}", + "wrap": true, + "horizontalAlignment": "Center" + } + ], + "width": "stretch" + } + ] + } + ], + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.3" + } + ``` + +- Locate and open the following file: **./src/adaptiveCardExtensions/helloWorld/helloWorldAdaptiveCardExtension.ts**. +- Add a new state variable **theme** to the existing interface **IHelloWorldAdaptiveCardExtensionState**.Since the theme API returns a promise, we need to use a state variable to determine the current theme. + +```typescript +export interface IHelloWorldAdaptiveCardExtensionState { + theme: string; +} +``` + +- For making the theme available to the card we are using API in the **onInit()** function. + +```typescript + +export default class helloWorldAdaptiveCardExtension extends BaseAdaptiveCardExtension< + IHelloWorldAdaptiveCardExtensionProps, + IHelloWorldAdaptiveCardExtensionState +> { + // ... + + public onInit(): Promise { + this.state = { + theme: "light" + } + + this.context.sdks?.microsoftTeams?.teamsJs.app.getContext().then((context) => { + this.setState({ + theme: context.app.appInfo.theme + }); + }); + + // registers the Card View to be shown in a dashboard + this.cardNavigator.register(CARD_VIEW_REGISTRY_ID, () => new CardView()); + // registers the Quick View to open via QuickView action + this.quickViewNavigator.register(QUICK_VIEW_REGISTRY_ID, () => new QuickView()); + + return Promise.resolve(); + } + // ... +} +``` + +- Add a variable **imageUrl** to the existing interface **IQuickViewData** and add **imageUrl value** to **data()** function. + +```typescript +import { ISPFxAdaptiveCard, BaseAdaptiveCardView } from '@microsoft/sp-adaptive-card-extension-base'; +import { ITestCardDmAdaptiveCardExtensionProps, ITestCardDmAdaptiveCardExtensionState } from '../TestCardDmAdaptiveCardExtension'; +import * as strings from 'TestCardDmAdaptiveCardExtensionStrings'; + +export interface IQuickViewData { + subTitle: string; + title: string; + imageUrl: string; +} + +export class QuickView extends BaseAdaptiveCardView< + ITestCardDmAdaptiveCardExtensionProps, + ITestCardDmAdaptiveCardExtensionState, + IQuickViewData +> { + public get data(): IQuickViewData { + return { + subTitle: strings.SubTitle, + title: strings.Title, + imageUrl: require('../assets/LightModeImage.png') + }; + } + + public get template(): ISPFxAdaptiveCard { + return require('./template/QuickViewTemplate.json'); + } +} +``` + +- Quick View in mobile iOS looks like this: + +:::image type="content" source="../../../images/viva-design/img_quickview_tutorial_light.png" alt-text="Screenshot that shows how an image in Quick View viewed on mobile appears in light mode."::: + +- When we switch to dark mode, the image conflicts with the background. + +:::image type="content" source="../../../images/viva-design/img_quickview_tutorial_dark.png" alt-text="Screenshot that shows how the same image in Quick View viewed on mobile appears in dark mode."::: + +- To avoid this issue, we can assign different images for light and dark theme in **QuickView.ts**. Replace the existing code in the **data()** function with this snippet: + +```typescript +public get data(): IQuickViewData { + // only two options are available for theme: 'dark' and 'default' + const isDarkTheme = this.state.theme === 'dark' ? true : false; + return { + subTitle: strings.SubTitle, + title: strings.Title, + imageUrl: isDarkTheme ? require('../assets/DarkModeImage.png') : require('../assets/LightModeImage.png') + } +} +``` + +- Now when we switch to dark mode, on opening the same Quick View we see for light and dark theme respectively. + +:::image type="content" source="../../../images/viva-design/img_quickview_tutorial_light_and_dark.png" alt-text="Screenshot that shows how a card Quick View viewed on mobile appears in light mode and dark mode with different images assigned."::: + +Similarly, we can customize our icons, images, and other elements of Quick View to support both light and dark theme. + +> [!NOTE] +> Please note that the value for ‘this.context.sdks.microsoftTeams.teamsJs.app.getContext()’ is undefined for web and Teams app as they do not support dark theme and is only available for Viva Connections Mobile iOS and Android. diff --git a/docs/spfx/viva/get-started/migrate-to-spfx-1-18.md b/docs/spfx/viva/get-started/migrate-to-spfx-1-18.md new file mode 100644 index 000000000..b3fd22c93 --- /dev/null +++ b/docs/spfx/viva/get-started/migrate-to-spfx-1-18.md @@ -0,0 +1,265 @@ +--- +title: Migrate Adaptive Card Extensions to SharePoint Framework v1.18 +description: SharePoint Framework v1.18 introduces new base classes and modified approach for building Adaptive Card Extensions (ACEs) for Microsoft Viva Connections. This article explains how to migrate your existing ACEs to the new approach. +ms.date: 09/12/2023 +ms.localizationpriority: high +--- + +# Migrate Adaptive Card Extensions to SharePoint Framework v1.18 + +SharePoint Framework (SPFx) v1.18 introduces new base classes and a modified approach for building Adaptive Card Extensions (ACEs) for Microsoft Viva Connections. + +The changes allow us to switch from "templates"-based to more granular "components"-based Card Views. It enables more flexibility for developers and increases the number of supported Card Views variants, or [permutations](../design/designing-card.md). + +This article explains how to migrate your existing ACEs to the new approach. + +> [!NOTE] +> All the changes described in this article are backward compatible. You can continue using your existing ACEs without any changes. However, we recommend migrating your ACEs to the new approach to take advantage of the new features and capabilities. + +## Migrate Quick Views to the new base class + +With SPFx 1.18, we deprecate the `BaseAdaptiveCardView` class and introduce `BaseAdaptiveCardQuickView` as a new base class for all Quick Views. + +The new base class provides the same functionality as the old one, so the migration is straightforward. +Update the definition of your Quick View class to inherit from the new base class: + +```typescript +import { BaseAdaptiveCardQuickView } from '@microsoft/sp-adaptive-card-extension-base'; +// ... +export class QuickView extends BaseAdaptiveCardQuickView< + ISlashNAdaptiveCardExtensionProps, + ISlashNAdaptiveCardExtensionState, + IQuickViewData +> { + // ... +``` + +## Migrate Card Views to new base class and configuration model + +With SPFx v1.18, we introduce a new base class and configuration model for Card Views. Instead of having a separate base class for each Card View "template", we provide a new single base class `BaseComponentsCardView`. + +Instead of specifying `cardButtons` and `data`, you must override the `cardViewParameters` getter to provide both look and data for the Card View. + +As part of the `cardViewParameters` property, you can specify the as follows: + +- **image**: Image parameters for the Card View. +- **cardBar**: Card bar component for the Card View (title and icon). +- **header**: Header components for the Card View. +- **body**: Body components for the Card View. +- **footer**: Footer components for the Card View. + +We also provide helper functions to simplify the creation of the predefined views: + +```typescript +function BasicCardView(configuration: IBasicTextCardViewConfiguration): ITextCardViewParameters; +function PrimaryTextCardView(configuration: IPrimaryTextCardViewConfiguration): ITextCardViewParameters; +function ImageCardView(configuration: IImageCardViewConfiguration): ITextCardViewParameters; +``` + +These helpers can also be used to migrate your existing Card Views to the new model easily. + +So, the migration steps are: + +- Update the definition of your Card View class to inherit from the new base class: + + ```typescript + import { BaseComponentsCardView } from '@microsoft/sp-adaptive-card-extension-base'; + // ... + export class CardView extends BaseComponentsCardView< + ISlashNAdaptiveCardExtensionProps, + ISlashNAdaptiveCardExtensionState, + ITextCardViewParameters + > { + // ... + } + ``` + +- Override the `cardViewParameters` getter to provide both look and data for the Card View. You can use one of the helper functions to simplify the migration: + + ```typescript + import { BaseComponentsCardView, BasicCardView } from '@microsoft/sp-adaptive-card-extension-base'; + + // ... + public get cardViewParameters(): ITextCardViewParameters { + return BasicCardView({ + // ... + }); + } + ``` + +- Remove the `cardButtons` and `data` properties from your Card View class. + +## Examples + +Here are examples of `cardViewParameters` getters for the default scaffolded Basic, Primary Text, and Image Card Views. + +### Basic Card View + +`cardButtons` and `data` properties for the scaffolded Basic Card View look like this: + +```typescript +public get cardButtons(): [ICardButton] | [ICardButton, ICardButton] | undefined { + return [ + { + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + ]; +} + +public get data(): IBasicCardParameters { + return { + primaryText: strings.PrimaryText, + title: this.properties.title + }; +} +``` + +The same configuration using `cardViewParameters`: + +```typescript +public get cardViewParameters(): ITextCardViewParameters { + return BasicCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + header: { + componentName: 'text', + text: strings.PrimaryText + }, + footer: { + componentName: 'cardButton', + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + }); +} +``` + +### Primary Text Card View + +`cardButtons` and `data` properties for the scaffolded Primary Text Card View look like this: + +```typescript +public get cardButtons(): [ICardButton] | [ICardButton, ICardButton] | undefined { + return [ + { + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + ]; +} + +public get data(): IPrimaryTextCardParameters { + return { + primaryText: strings.PrimaryText, + description: strings.Description, + title: this.properties.title + }; +} +``` + +The same configuration using `cardViewParameters`: + +```typescript +public get cardViewParameters(): ITextCardViewParameters { + return PrimaryTextCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + header: { + componentName: 'text', + text: strings.PrimaryText + }, + body: { + componentName: 'text', + text: strings.Description + }, + footer: { + componentName: 'cardButton', + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + }); +} +``` + +### Image Card View + +`cardButtons` and `data` properties for the scaffolded Image Card View look like this: + +```typescript +public get cardButtons(): [ICardButton] | [ICardButton, ICardButton] | undefined { + return [ + { + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + ]; +} + +public get data(): IImageCardParameters { + return { + primaryText: strings.PrimaryText, + imageUrl: require('../assets/MicrosoftLogo.png'), + title: this.properties.title + }; +} +``` + +The same configuration using `cardViewParameters`: + +```typescript +public get cardViewParameters(): ITextCardViewParameters { + return ImageCardView({ + cardBar: { + componentName: 'cardBar', + title: this.properties.title + }, + image: { + url: require('../assets/MicrosoftLogo.png') + }, + header: { + componentName: 'text', + text: strings.PrimaryText + }, + footer: { + componentName: 'cardButton', + title: strings.QuickViewButton, + action: { + type: 'QuickView', + parameters: { + view: QUICK_VIEW_REGISTRY_ID + } + } + } + }); +} +``` diff --git a/docs/spfx/viva/images/viva-connections-desktop.png b/docs/spfx/viva/images/viva-connections-desktop.png new file mode 100644 index 000000000..884808484 Binary files /dev/null and b/docs/spfx/viva/images/viva-connections-desktop.png differ diff --git a/docs/spfx/viva/images/viva-connections-mobile-and-tablet.png b/docs/spfx/viva/images/viva-connections-mobile-and-tablet.png new file mode 100644 index 000000000..1a5bfb572 Binary files /dev/null and b/docs/spfx/viva/images/viva-connections-mobile-and-tablet.png differ diff --git a/docs/spfx/viva/images/viva-connections-mobile.png b/docs/spfx/viva/images/viva-connections-mobile.png new file mode 100644 index 000000000..2bd3c7013 Binary files /dev/null and b/docs/spfx/viva/images/viva-connections-mobile.png differ diff --git a/docs/spfx/viva/known-issues-adaptive-cards.md b/docs/spfx/viva/known-issues-adaptive-cards.md new file mode 100644 index 000000000..8abb18302 --- /dev/null +++ b/docs/spfx/viva/known-issues-adaptive-cards.md @@ -0,0 +1,15 @@ +--- +title: Known issues for Adaptive Cards in Viva Connections Mobile +description: Known issues for Adaptive Cards in Viva Connections Mobile. +ms.date: 10/29/2021 +ms.localizationpriority: high +--- +# Known issues for Adaptive Cards in Viva Connections Mobile + +There are some known issues around the Adaptive Cards rendering on the Viva Connections Mobile experiences. These known issues are being actively worked on. + +1. When Image with Size value `small`, `medium` or `large` is used, it would render as square Image on mobile. A square image is recommended to be used so it maintains the aspect ratio on mobile, or other Size value “auto” might work. +1. When Image with Style value `person` is used, it's recommended that image is a square so it maintains the aspect ratio on mobile. +1. When `Input.ChoiceSet` is used, the first choice would appear to be selected on Mobile. It’s recommended to use a placeholder value as the first choice so that the user make right selection and do not end up submitting a blank value. +1. Format date-time functions, `formatDateTime`, `formatTicks`, `formatNumber` do not work on Android. The workaround is to use JavaScript methods in Adaptive Card itself or on server. +1. `RichTextBlock` is not yet supported. diff --git a/docs/spfx/viva/overview-viva-connections.md b/docs/spfx/viva/overview-viva-connections.md new file mode 100644 index 000000000..d201914ff --- /dev/null +++ b/docs/spfx/viva/overview-viva-connections.md @@ -0,0 +1,44 @@ +--- +title: Overview of Viva Connections Extensibility +description: Build engaging experiences for Microsoft Viva Connections with the SharePoint Framework. +ms.date: 08/28/2024 +ms.localizationpriority: high +--- +# Overview of Viva Connections Extensibility + +[Microsoft Viva Connections](https://www.microsoft.com/microsoft-viva) is available as a desktop via the installable Microsoft Teams client, tablet and as mobile app in Microsoft Teams. All of these experiences, desktop & mobile, use the **SharePoint Framework (SPFx) for all customizations and extensibility opportunities**. + +Viva Connections has a set of out of the box cards that are exposed through the dashboard feature. This dashboard **can be adjusted and configured based on the company requirements**. You can introduce new cards and experiences based on your business requirements. + +Viva Connections dashboard is available in the desktop, tablet and mobile experiences. It enables end users to easily access the most relevant information and applications directly for their role in the dashboard. You can personalize or introduce separate dashboards based on audiences, which can be created using your company requirements. + +> [!TIP] +> See the [Extend Microsoft Viva Connections learning path](https://aka.ms/m365/dev/learn/connections) for a structured way to learn how you can extend Viva Connections, what tools you need, and how to get started. + +## Extensibility opportunities + +Viva Connections personalization and extensibility model is based on the **Adaptive Card Extensions (ACEs)** which can be created using the widely adopted SharePoint Framework (SPFx) as client-side extensibility. + +To learn more about customizing modern pages in SharePoint with SPFx, see [Overview of SPFx client-side web parts](../web-parts/overview-client-side-web-parts.md) & [Overview of SPFx Extensions](../extensions/overview-extensions.md). + +### Viva Connections desktop experience + +The Viva Connections desktop experience can be extended and customized using Adaptive Card Extensions (ACEs). Developers can use SPFx to introduce new Viva Connections Adaptive Card extensions to customize the dashboard based on the business requirements. + +![Example Viva Connections desktop layout as available in 2024](./images/viva-connections-desktop.png) + +### Viva Connections mobile & tablet experience + +The Viva Connections mobile experience is aligned with the desktop experience and is exposing by default the same ACEs as configured for the desktop area, optimized for the mobile experiences. + +![Example Viva Connections mobile layout as available in 2024](./images/viva-connections-mobile-and-tablet.png) + +## Start building for Microsoft Viva Connections + +Here are the resources to get started on creating your first Adaptive Card Extension (ACE) depending on your chosen path: + +- [Build your first SharePoint Adaptive Card Extension with SPFx](get-started/build-first-sharepoint-adaptive-card-extension.md) +- [Advanced Card View Functionality](get-started/advanced-card-view-functionality.md) +- [Advanced Quick View Functionality](get-started/advanced-quick-view-functionality.md) +- [Adaptive Card Extensions and Teams Apps](get-started/adaptive-card-extensions-and-teams.md) +- [Microsoft Learning: Create Adaptive Card Extensions (ACE) for Microsoft Viva Connections](/training/modules/sharepoint-spfx-adaptive-card-extension-card-types) diff --git a/docs/spfx/web-parts/basics/add-an-external-library.md b/docs/spfx/web-parts/basics/add-an-external-library.md index 9c81cef15..426256847 100644 --- a/docs/spfx/web-parts/basics/add-an-external-library.md +++ b/docs/spfx/web-parts/basics/add-an-external-library.md @@ -2,8 +2,7 @@ title: Add an external library to your SharePoint client-side web part description: Bundle a JavaScript external library and share libraries. ms.date: 01/25/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Add an external library to your SharePoint client-side web part diff --git a/docs/spfx/web-parts/basics/configure-web-part-icon.md b/docs/spfx/web-parts/basics/configure-web-part-icon.md index ed49ac463..cb3676ce4 100644 --- a/docs/spfx/web-parts/basics/configure-web-part-icon.md +++ b/docs/spfx/web-parts/basics/configure-web-part-icon.md @@ -1,9 +1,8 @@ --- title: Configure web part icon description: The available options for configuring the icon for your SharePoint client-side web parts. -ms.date: 06/16/2018 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 12/05/2023 +ms.localizationpriority: high --- # Configure web part icon @@ -51,9 +50,9 @@ For a list of available Fluent UI icons, see [Icons](https://developer.microsoft "requiresCustomScript": false, "preconfiguredEntries": [ { - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced "group": { - "default": "Other" + "default": "Advanced" }, "title": { "default": "Weather" @@ -99,9 +98,9 @@ In addition to using Fluent UI icons, the SharePoint Framework also allows you t "requiresCustomScript": false, "preconfiguredEntries": [ { - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced "group": { - "default": "Other" + "default": "Advanced" }, "title": { "default": "Weather" @@ -148,9 +147,9 @@ A number of services are available online that you can use to base64-encode your "requiresCustomScript": false, "preconfiguredEntries": [ { - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced "group": { - "default": "Other" + "default": "Advanced" }, "title": { "default": "Weather" @@ -188,7 +187,7 @@ Starting from SharePoint Framework v1.11 you can specify the preview image for y ### To set the single part app page preview image -Specify the image's absolute URL in the `fullPageAppIconImageUrl` property in the web part manifest. +Specify the image's absolute URL in the `fullPageAppIconImageUrl` property in the web part manifest. ```json { @@ -203,9 +202,9 @@ Specify the image's absolute URL in the `fullPageAppIconImageUrl` property in th "requiresCustomScript": false, "preconfiguredEntries": [ { - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced "group": { - "default": "Other" + "default": "Advanced" }, "title": { "default": "Weather" diff --git a/docs/spfx/web-parts/basics/design-considerations-for-web-parts.md b/docs/spfx/web-parts/basics/design-considerations-for-web-parts.md index d1a49bd20..81c5d366c 100644 --- a/docs/spfx/web-parts/basics/design-considerations-for-web-parts.md +++ b/docs/spfx/web-parts/basics/design-considerations-for-web-parts.md @@ -2,14 +2,13 @@ title: Design considerations for SharePoint client-side web parts description: Use Office UI Fabric React components to build and style your web parts. ms.date: 01/24/2018 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Design considerations for SharePoint client-side web parts -To get started designing web parts, you need to be familiar with [Office UI Fabric](https://developer.microsoft.com/fabric). All of the styles from [Fabric Core](https://github.com/OfficeDev/office-ui-fabric-core), including icons, typography, color usage, animation, and the responsive grid, are loaded by default and available to your web part. +To get started designing web parts, you need to be familiar with [Office UI Fabric](https://developer.microsoft.com/fabric). All of the styles from [Fabric Core](https://github.com/OfficeDev/office-ui-fabric-core), including icons, typography, color usage, animation, and the responsive grid, are loaded by default and available to your web part. Do not import a copy of Fabric for your web part because this may conflict with the global copy. These classes provide a foundation to your web part's styling, which you can always depart from if you require different visuals to match your company's brand. @@ -26,7 +25,7 @@ You can find a complete list of the Office UI Fabric styles, typography, color, ## Responsive behavior -Pages in the new SharePoint authoring experience use the Office UI Fabric responsive grid to help ensure that each page looks great. +Pages in the new SharePoint authoring experience use the Office UI Fabric responsive grid to help ensure that each page looks great. ### Maximum width diff --git a/docs/spfx/web-parts/basics/determine-web-part-width.md b/docs/spfx/web-parts/basics/determine-web-part-width.md index ef2ef2000..8888dfe33 100644 --- a/docs/spfx/web-parts/basics/determine-web-part-width.md +++ b/docs/spfx/web-parts/basics/determine-web-part-width.md @@ -2,8 +2,7 @@ title: Determine the rendered web part width description: Learn how to determine the rendered width of a web part and handle when the web part is resized. ms.date: 03/30/2021 -ms.prod: sharepoint -localization_priority: Normal +ms.localizationpriority: medium --- # Determine the rendered web part size diff --git a/docs/spfx/web-parts/basics/hide-web-part-from-toolbox.md b/docs/spfx/web-parts/basics/hide-web-part-from-toolbox.md index 8a32cb6a7..0cfcb96ac 100644 --- a/docs/spfx/web-parts/basics/hide-web-part-from-toolbox.md +++ b/docs/spfx/web-parts/basics/hide-web-part-from-toolbox.md @@ -1,9 +1,8 @@ --- title: Hide a web part from the toolbox description: How to hide a web part from showing up in the web part toolbox on a modern page -ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 12/05/2023 +ms.localizationpriority: high --- # Hide a web part from the toolbox @@ -31,8 +30,8 @@ By default a SharePoint Framework client-side web part will be displayed in the "hiddenFromToolbox": true, "preconfiguredEntries": [{ - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other - "group": { "default": "Other" }, + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced + "group": { "default": "Advanced" }, "title": { "default": "HelloWorld" }, "description": { "default": "HelloWorld description" }, "officeFabricIconFontName": "Page", diff --git a/docs/spfx/web-parts/basics/integrate-with-property-pane.md b/docs/spfx/web-parts/basics/integrate-with-property-pane.md index f31efd280..17ec58c16 100644 --- a/docs/spfx/web-parts/basics/integrate-with-property-pane.md +++ b/docs/spfx/web-parts/basics/integrate-with-property-pane.md @@ -1,9 +1,8 @@ --- title: Make your SharePoint client-side web part configurable description: Configure custom properties in your web part by using the property pane. -ms.date: 06/22/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 04/06/2022 +ms.localizationpriority: high --- # Make your SharePoint client-side web part configurable @@ -106,7 +105,7 @@ This is then available in your web part by using `this.properties.targetProperty

    ${escape(this.properties.targetProperty)}

    ``` -When the properties are defined, you can access them in your web part by using the `this.properties.[property-name]`. For more information, see [Build a HellowWorld web part: Web part render() method](../get-started/build-a-hello-world-web-part.md#web-part-render-method). +When the properties are defined, you can access them in your web part by using the `this.properties.[property-name]`. For more information, see [Build a HelloWorld web part: Web part render() method](../get-started/build-a-hello-world-web-part.md#web-part-render-method). ## Handle field changes diff --git a/docs/spfx/web-parts/basics/notes-on-solution-packaging.md b/docs/spfx/web-parts/basics/notes-on-solution-packaging.md index 2014020bd..485579157 100644 --- a/docs/spfx/web-parts/basics/notes-on-solution-packaging.md +++ b/docs/spfx/web-parts/basics/notes-on-solution-packaging.md @@ -2,8 +2,7 @@ title: SharePoint solution packaging description: The package-solution gulp task looks at /config/package-solution.json for various configuration details in SharePoint Framework, including ISolution and IFeature definitions. ms.date: 10/26/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # SharePoint solution packaging diff --git a/docs/spfx/web-parts/basics/use-web-parts-full-width-column.md b/docs/spfx/web-parts/basics/use-web-parts-full-width-column.md index 3b4d6176a..b4462e028 100644 --- a/docs/spfx/web-parts/basics/use-web-parts-full-width-column.md +++ b/docs/spfx/web-parts/basics/use-web-parts-full-width-column.md @@ -2,8 +2,7 @@ title: Use web parts with the full-width column description: Build web parts that can be used in the full-width column ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Use web parts with the full-width column diff --git a/docs/spfx/web-parts/basics/working-with-requestdigest.md b/docs/spfx/web-parts/basics/working-with-requestdigest.md index fc7dd826d..6e5fcaf63 100644 --- a/docs/spfx/web-parts/basics/working-with-requestdigest.md +++ b/docs/spfx/web-parts/basics/working-with-requestdigest.md @@ -2,8 +2,7 @@ title: Work with __REQUESTDIGEST description: Add a valid request digest to your request when executing non-GET REST requests to the SharePoint API. ms.date: 06/29/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Work with __REQUESTDIGEST diff --git a/docs/spfx/web-parts/get-started/add-jqueryui-accordion-to-web-part.md b/docs/spfx/web-parts/get-started/add-jqueryui-accordion-to-web-part.md index 7881097bc..b447a8e45 100644 --- a/docs/spfx/web-parts/get-started/add-jqueryui-accordion-to-web-part.md +++ b/docs/spfx/web-parts/get-started/add-jqueryui-accordion-to-web-part.md @@ -1,9 +1,8 @@ --- title: Add the jQueryUI Accordion to your SharePoint client-side web part description: Adding the jQueryUI Accordion to your web part project involves creating a new web part. -ms.date: 07/17/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 10/21/2021 +ms.localizationpriority: high ms.custom: scenarios:getting-started --- @@ -17,7 +16,7 @@ Ensure that you've completed the following steps before you start: - [Build your first web part](build-a-hello-world-web-part.md) -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Communtiy (PnP) YouTube Channel: > [!Video https://www.youtube.com/embed/N0C9azIyiTo] @@ -41,24 +40,23 @@ The developer toolchain uses Webpack & SystemJS to bundle and load your web part cd jquery-webpart ``` -1. Create a new jQuery web part by running the Yeoman SharePoint Generator: +1. Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: ```console yo @microsoft/sharepoint ``` -1. When prompted: -1. When prompted, enter the following values (*select the default option for all prompts omitted below*): + The Yeoman SharePoint Generator will prompt you with a series of questions. For all questions, accept the default options except for the following questions: - - **What is your solution name?**: jquery-webpart - **Which type of client-side component to create?**: WebPart - - **What is your Web part name?**: jQuery - **Which framework would you like to use?**: No JavaScript framework -At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your **jQueryWebPart** as well. +At this point, Yeoman installs the required dependencies and scaffolds the solution files, including the web part. This might take a few minutes. ## Install jQuery and jQuery UI NPM Packages +The web part uses jQuery and the Accordion included in the jQuery UI project. To use these, add them to the project's dependencies: + 1. In the console, execute the following to install the jQuery NPM package: ```console @@ -71,26 +69,20 @@ At this point, Yeoman installs the required dependencies and scaffolds the solut npm install jqueryui ``` -1. Next, we need to install the TypeScript type declarations for our project. +1. Next, we need to install the TypeScript type declarations for our project to simplify the development process. - Open your console and install the needed types: + In the console, execute the following commands to install the type declaration packages: ```console npm install @types/jquery@2 --save-dev npm install @types/jqueryui --save-dev ``` -### To unbundle external dependencies from web part bundle - -By default, all dependencies referenced in your project's code are bundled into the resulting web part bundle. In most cases, this isn't ideal because it unnecessarily increases the file size. You can configure the project to exclude the dependencies from the web part bundle. - -1. Enter the following to open the web part project in Visual Studio Code: +### Exclude external dependencies from web part bundle - ```console - code . - ``` +By default, all dependencies referenced in your project's code are included in the resulting web part bundle. In most cases, this isn't ideal because it unnecessarily increases the file size. You can configure the project to exclude the dependencies from the web part bundle and instead, instruct the SharePoint Framework runtime to load them as dependencies before the web part's bundle is loaded. -1. In Visual Studio Code, open the file **config\config.json**. +1. In Visual Studio Code (VS Code), open the file **config\config.json**. This file contains information about your bundle(s) and external dependencies. @@ -115,24 +107,20 @@ By default, all dependencies referenced in your project's code are bundled into "externals": {}, ``` -1. To exclude `jQuery` and `jQueryUI` from the generated bundle, add the following two modules to the `externals` property: +1. Exclude `jQuery` and `jQueryUI` from the generated bundle by adding the following two modules to the `externals` property: ```json { - //... - "externals": { "jquery": "node_modules/jquery/dist/jquery.min.js", "jqueryui": "node_modules/jqueryui/jquery-ui.min.js" }, - - //... } ``` Now when you build your project, `jQuery` and `jQueryUI` are not bundled into your default web part bundle. - The full content of the **config.json** file is currently as follows: + The completed **config.json** file should look similar to the following: ```json { @@ -160,81 +148,83 @@ By default, all dependencies referenced in your project's code are bundled into ## Build the Accordion -Open the project folder **jquery-webpart** in Visual Studio Code. Your project should have the jQuery web part that you added earlier under the **/src/webparts/jQuery** folder. +At this point, the project is configured to depend on jQuery and jQueryUI, but to not include the in the resulting solution's bundle. The next step is to implement the web part by adding the Accordion to the web part. -### To add the Accordion HTML +### Add the Accordion HTML -1. Add a new file **MyAccordionTemplate.ts** in the **src/webparts/jQuery** folder. -1. Create and export (as a module) a class `MyAccordionTemplate` that holds the HTML code for the accordion: +1. In VS Code, Add a new file **MyAccordionTemplate.ts** in the **./src/webparts/jQuery** folder. +1. Add class `MyAccordionTemplate` that contains the HTML for the accordion. Add the following code to the **MyAccordionTemplate.ts** file: ```typescript export default class MyAccordionTemplate { - public static templateHtml: string = ` -
    -

    Section 1

    -
    -

    - Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer - ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit - amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut - odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate. -

    -
    -

    Section 2

    -
    -

    - Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet - purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor - velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In - suscipit faucibus urna. -

    -
    -

    Section 3

    -
    -

    - Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. - Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero - ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis - lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui. -

    -
      -
    • List item one
    • -
    • List item two
    • -
    • List item three
    • -
    -
    -

    Section 4

    -
    -

    - Cras dictum. Pellentesque habitant morbi tristique senectus et netus - et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in - faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia - mauris vel est. -

    -

    - Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. - Class aptent taciti sociosqu ad litora torquent per conubia nostra, per - inceptos himenaeos. -

    -
    -
    `; + public static templateHtml: string = ` +
    +

    Section 1

    +
    +

    + Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer + ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit + amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut + odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate. +

    +
    +

    Section 2

    +
    +

    + Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet + purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor + velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In + suscipit faucibus urna. +

    +
    +

    Section 3

    +
    +

    + Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis. + Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero + ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis + lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui. +

    +
      +
    • List item one
    • +
    • List item two
    • +
    • List item three
    • +
    +
    +

    Section 4

    +
    +

    + Cras dictum. Pellentesque habitant morbi tristique senectus et netus + et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in + faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia + mauris vel est. +

    +

    + Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus. + Class aptent taciti sociosqu ad litora torquent per conubia nostra, per + inceptos himenaeos. +

    +
    +
    `; } ``` 1. Save the file. -### To import the Accordion HTML +### Import the Accordion HTML -1. In Visual Studio Code, open **src\webparts\jQuery\JQueryWebPart.ts**. -1. Add the following `import` statement after the existing `import` statements at the top of the file: +1. In VS Code, open **./src/webparts/jQuery/JQueryWebPart.ts**. +1. Add the following `import` statement immediately after the existing `import` statements at the top of the file: ```typescript import MyAccordionTemplate from './MyAccordionTemplate'; ``` -### To import jQuery and jQueryUI +### Import jQuery and jQueryUI + +1. Import jQuery to your web part in the same way that you imported `MyAccordionTemplate`. -1. You can import jQuery to your web part in the same way that you imported `MyAccordionTemplate`. Add the following `import` statement after the existing `import` statements: + Add the following `import` statement after the existing `import` statements: ```typescript import * as jQuery from 'jquery'; @@ -243,13 +233,17 @@ Open the project folder **jquery-webpart** in Visual Studio Code. Your project s 1. The jQueryUI project uses an external CSS file to implement it's user experience. Your web part needs to load this CSS file at runtime: - 1. To load a CSS file at runtime, use the SharePoint module loader by utilizing the `SPComponentLoader` object. Add the following `import` statement. + 1. To load a CSS file at runtime, use the SharePoint module loader by utilizing the `SPComponentLoader` object. + + Add the following `import` statement. ```typescript import { SPComponentLoader } from '@microsoft/sp-loader'; ``` - 1. Load the jQueryUI styles in the `JQueryWebPart` web part class by adding a constructor and use the `SPComponentLoader`. Add the following constructor to your web part: + 1. Load the jQueryUI styles in the `JQueryWebPart` web part class by adding a constructor and use the `SPComponentLoader`. + + Add the following constructor to your web part: ```typescript public constructor() { @@ -259,15 +253,15 @@ Open the project folder **jquery-webpart** in Visual Studio Code. Your project s } ``` - This code does the following: + This code does the following: - Calls the parent constructor with the context to initialize the web part. - Asynchronously loads the accordion styles in the CSS file from a CDN. -### To render Accordion +### Render the Accordion -1. In the **jQueryWebPart.ts** file, go to the `render()` method. -1. Set the web part's inner HTML to render the accordion HTML: +1. In the **jQueryWebPart.ts** file, locate the `render()` method. +1. Set the web part's inner HTML to render the accordion HTML by replacing the contents of the `render()` method with the following: ```typescript this.domElement.innerHTML = MyAccordionTemplate.templateHtml; @@ -288,7 +282,7 @@ Open the project folder **jquery-webpart** in Visual Studio Code. Your project s The jQueryUI typed declaration allows you to create a typed variable called `JQueryUI.AccordionOptions` and specify the supported properties. - If you play around with the IntelliSense, you notice that you get full support for available methods under `JQueryUI.` as well as the method parameters. + If you play around with the IntelliSense, you'll notice that you'll get full support for available methods under `JQueryUI.` as well as the method parameters. 1. Finally, initialize the accordion: @@ -324,15 +318,12 @@ Open the project folder **jquery-webpart** in Visual Studio Code. Your project s 1. In your console, ensure that you're still in the **jquery-webpart** folder, and execute the following to build and preview your web part: ```console - gulp serve + gulp serve --nobrowser ``` - > [!NOTE] - > Visual Studio Code provides built-in support for gulp and other task runners. You can select CTRL+SHIFT+B in Windows or CMD+SHIFT+B in macOS to debug and preview your web part. - - Gulp executes the tasks and opens the local SharePoint web part Workbench. + Once the web server starts, open a browser and navigate to a SharePoint site's hosted workbench to test your project. For example: `https://contoso.sharepoint.com/sites/devsite/_layouts/workbench.aspx`. -1. On the workbench page that loads in the browser, select the **+** (plus sign) to show the list of web parts, and add the jQuery web part. You should now see the jQueryUI Accordion! +1. On the workbench, select the **+** (plus sign) to show the list of web parts, and add the jQuery web part. You should now see the jQueryUI Accordion! ![Screenshot of a web part that includes a jQuery Accordion](../../../images/jquery-accordion-wb.png) diff --git a/docs/spfx/web-parts/get-started/build-a-hello-world-web-part.md b/docs/spfx/web-parts/get-started/build-a-hello-world-web-part.md index 9e6ef6ea8..855fed792 100644 --- a/docs/spfx/web-parts/get-started/build-a-hello-world-web-part.md +++ b/docs/spfx/web-parts/get-started/build-a-hello-world-web-part.md @@ -1,9 +1,8 @@ --- title: Build your first SharePoint client-side web part (Hello World part 1) description: Create a new web part project and preview it. -ms.date: 07/31/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 04/23/2025 +ms.localizationpriority: high ms.custom: scenarios:getting-started --- @@ -19,103 +18,110 @@ Client-side web parts support: > [!NOTE] > Before following the steps in this article, be sure to [Set up your development environment](../../set-up-your-development-environment.md). -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Community (PnP) YouTube Channel: -> [!Video https://www.youtube.com/embed/_O2Re5uRLoo] +> [!Video https://www.youtube.com/embed/6WTtjXP5yW4] ## Create a new web part project -1. Create a new project directory in your favorite location. +Create a new project directory for your project and change your current folder to that directory. - ```console - md helloworld-webpart - ``` - -1. Go to the project directory. - - ```console - cd helloworld-webpart - ``` - -1. Create a new HelloWorld web part by running the Yeoman SharePoint Generator. - - ```console - yo @microsoft/sharepoint - ``` +Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: -1. When prompted: - - - **What is your solution name?**: helloworld-webpart - - **Which baseline packages do you want to target for your component(s)?**: SharePoint Online only (latest) - - **Where do you want to place the files?**: Use the current folder - - **Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites?**: N - - **Will the components in the solution require permissions to access web APIs that are unique and not shared with other components in the tenant?**: N - - **Which type of client-side component to create?**: WebPart +```console +yo @microsoft/sharepoint +``` -1. The next set of prompts ask for specific information about your web part: +The Yeoman SharePoint Generator will prompt you with a series of questions. For all questions, accept the default options except for the following questions: - - **What is your Web part name?**: HelloWorld - - **What is your Web part description?**: HelloWorld description - - **Which framework would you like to use?**: No JavaScript framework +- **Which type of client-side component to create?**: WebPart +- **What is your Web part name?**: HelloWorld +- **Which template would you like to use?**: No framework At this point, Yeoman creates the project scaffolding (folders & files) and installs the required dependencies by running `npm install`. This usually takes 1-3 minutes depending on your internet connection. -When the project scaffolding and dependency install process is complete, Yeoman will display a message similar to the following indicating it was successful: +When the project scaffolding and dependency install process are complete, Yeoman will display a message similar to the following indicating it was successful: -![SharePoint client-side solution scaffolded successfully](../../../images/yeoman-sp-complete.png) +```console +_=+#####! +###########| .-----------------------------------. +###/ (##|(@) | Congratulations! | +### ######| \ | Solution webpart-1 is created. | +###/ /###| (@) | Run gulp serve to play with it! | +####### ##| / '-----------------------------------' +### /##|(@) +###########| +**=+####! +``` > [!IMPORTANT] > NPM may display warnings and error messages during the installation of dependencies while it runs the `npm install` command. You can safely ignore these log warnings & error messages. > > NPM may display a message about running `npm audit` at the end of the process. Don't run this command as it will upgrade packages and nested dependencies that may not have been tested by the SharePoint Framework. -For information about troubleshooting any errors, see [Known issues](../../known-issues-and-common-questions.md). +For information about troubleshooting any errors, see [Known issues](../../known-issues-and-common-questions.yml). ### Use your favorite code editor Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your web part, such as: - [Visual Studio Code](https://code.visualstudio.com/) -- [Atom](https://atom.io) - [Webstorm](https://www.jetbrains.com/webstorm) -The SharePoint Framework documentation uses Visual Studio Code in the steps and examples. Visual Studio Code (VS Code) is a lightweight but powerful source code editor from Microsoft that runs on your desktop. VS Code available for Windows, macOS, and Linux. It comes with built-in support for JavaScript, TypeScript, Node.js, and has a rich ecosystem of extensions for other languages (such as C++, C#, Python, PHP) and runtimes. +The SharePoint Framework documentation uses Visual Studio Code in the steps and examples. Visual Studio Code (VS Code) is a lightweight but powerful source code editor from Microsoft that runs on your desktop. VS Code available for Windows, macOS, and Linux. It comes with built-in support for JavaScript, TypeScript, Node.js, and has a rich ecosystem of extensions for other languages (such as C++, C#, Python, PHP). ## Preview the web part -You can preview and test your client-side web part locally on your workstation. The client-side toolchain uses HTTPS endpoint by default. Part of the [Set up your development environment](../../set-up-your-development-environment.md) process included trusting the development SSL certificate included in the toolchain on your local environment. This is required so your browser will trust the certificate. +You can preview and test your client-side web part in the SharePoint hosted workbench without deploying your solution to SharePoint. This is done by starting a local web server the hosted workbench can load files from using the gulp task **serve**. + +The client-side toolchain uses HTTPS endpoints by default. Part of the [Set up your development environment](../../set-up-your-development-environment.md) process included trusting the development SSL certificate included in the toolchain on your local environment. This is required so your browser will trust the certificate. > [!IMPORTANT] > Trusting the developer certificate is required. This is a one-time process and is only required when you run your first SharePoint Framework project on a new workstation. You don't need to do this for every SharePoint Framework project. > > If you didn't trust the dev cert, follow the steps outlined on this page: [Set up your development environment: Trusting the self-signed developer certificate](../../set-up-your-development-environment.md#trusting-the-self-signed-developer-certificate). -Now that we've installed the developer certificate, enter the following command in the console to build and preview your web part: +### Start the local web server & launch the hosted workbench + +Assuming you've installed & trusted developer certificate, execute the following command in the console to build and preview your web part: ```console gulp serve ``` -This command executes a series of gulp tasks to create and start a local webserver hosting the endpoints **localhost:4321** and **localhost:5432**. It will then open your default browser and load the workbench preview web parts from your local dev environment. +This command executes a series of gulp tasks to create and start a local webserver hosting the endpoints **localhost:4321** and **localhost:5432**. It will then open your default browser and load the hosted workbench preview web parts from your local dev environment. -> [!NOTE] -> If you're seeing issues with the certificate in browser, please see details on installing a developer certificate: [Set up your development environment: Trusting the self-signed developer certificate](../../set-up-your-development-environment.md#trusting-the-self-signed-developer-certificate). -> -> If you're still seeing issues, see: [SharePoint Framework known issues and frequently asked questions](../../known-issues-and-common-questions.md) - -![Gulp serve web part project](../../../images/helloworld-wp-gulp-serve.png) +```console +gulp serve +Build target: DEBUG +[12:13:24] Using gulpfile d:\pnp\helloworld-webpart\gulpfile.js +[12:13:24] Starting 'serve'... +[12:13:24] Starting gulp +[12:13:24] Starting subtask 'spfx-serve'... +[12:13:24] [spfx-serve] To load your scripts, use this query string: ?debug=true&noredir=true&debugManifestsFile=https://localhost:4321/temp/build/manifests.js +[12:13:25] Starting server... +[12:13:25] Finished subtask 'spfx-serve' after 1.24 s +[12:13:25] Starting subtask 'pre-copy'... +[12:13:26] Finished subtask 'pre-copy' after 533 ms +[12:13:26] Starting subtask 'copy-static-assets'... +[12:13:26] Starting subtask 'sass'... +[12:13:26] Server started https://localhost:4321 +[12:13:26] LiveReload started on port 35729 +[12:13:26] Running server +[12:13:26] Opening https://sppnp.sharepoint.com/_layouts/workbench.aspx using the default OS app +``` SharePoint client-side development tools use [gulp](http://gulpjs.com/) as the task runner to handle build process tasks such as: -- Compiling TypeScript files to JavaScript. -- Compiling SASS files to CSS. -- Bundling and minifying JavaScript and CSS files. +- Transpile TypeScript files to JavaScript. +- Compile SASS files to CSS. +- Bundle and minify JavaScript and CSS files. VS Code provides built-in support for gulp and other task runners. Select CTRL+SHIFT+B on Windows or CMD+SHIFT+B on macOS to debug and preview your web part. The SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Workbench includes the client-side page and the client-side canvas in which you can add, delete, and test your web parts in development. -![SharePoint Workbench running locally](../../../images/sp-workbench.png) +![SharePoint Workbench running locally](../../../images/sp-workbench-o365.png) ### Use SharePoint Workbench to preview and test your web part @@ -143,7 +149,7 @@ One of the capabilities of the property pane is to configure its update behavior ## Web part project structure -### To use Visual Studio Code to explore the web part project structure +### Use Visual Studio Code to explore the web part project structure 1. In the console, stop the local web server by terminating the process. Selecting CTRL+C on Windows or macOS. 1. Enter the following command to open the web part project in VS Code (or use your favorite editor): @@ -184,20 +190,30 @@ The DOM element where the web part should be rendered is available in the `rende ```typescript public render(): void { this.domElement.innerHTML = ` -
    -
    -
    -
    - Welcome to SharePoint! -

    Customize SharePoint experiences using web parts.

    -

    ${escape(this.properties.description)}

    - - Learn more - -
    -
    -
    -
    `; +
    +
    + +

    Well done, ${escape(this.context.pageContext.user.displayName)}!

    +
    ${this._environmentMessage}
    +
    Web part property value: ${escape(this.properties.description)}
    +
    +
    +

    Welcome to SharePoint Framework!

    +

    + The SharePoint Framework (SPFx) is a extensibility model for Microsoft Viva, Microsoft Teams and SharePoint. It's the easiest way to extend Microsoft 365 with automatic Single Sign On, automatic hosting and industry standard tooling. +

    +

    Learn more about SPFx development:

    + +
    +
    `; } ``` @@ -210,7 +226,7 @@ The property pane is defined in the `HelloWorldWebPart` class. The `getPropertyP When the properties are defined, you can access them in your web part by using `this.properties.`, as shown in the `render()` method: ```typescript -

    ${escape(this.properties.description)}

    +
    Web part property value: ${escape(this.properties.description)}
    ``` Notice that we're executing an HTML escape on the property's value to ensure a valid string. To learn more about how to work with the property pane and property pane field types, see [Make your SharePoint client-side web part configurable](../basics/integrate-with-property-pane.md). @@ -301,17 +317,17 @@ Let's now add a few more properties to the property pane: a checkbox, a drop-dow Locate the following line: - ```typescript -

    ${escape(this.properties.description)}

    + ```html +
    Web part property value: ${escape(this.properties.description)}
    ``` Add the following immediately after the previously mentioned line: - ```typescript -

    ${escape(this.properties.test)}

    -

    ${this.properties.test1}

    -

    ${escape(this.properties.test2)}

    -

    ${this.properties.test3}

    + ```html +

    ${escape(this.properties.test)}

    +

    ${this.properties.test1}

    +

    ${escape(this.properties.test2)}

    +

    ${this.properties.test3}

    ``` To set the default value for the properties, you need to update the web part manifest's `properties` property bag. @@ -349,11 +365,12 @@ The **HelloWorldWebPart.manifest.json** file defines the web part metadata such // Components that allow authors to embed arbitrary script code should set this to true. // https://support.office.com/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f "requiresCustomScript": false, - "supportedHosts": ["SharePointWebPart"], + "supportedHosts": ["SharePointWebPart", "TeamsPersonalApp", "TeamsTab", "SharePointFullPage"], + "supportsThemeVariants": true, "preconfiguredEntries": [{ - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other - "group": { "default": "Other" }, + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced + "group": { "default": "Advanced" }, "title": { "default": "HelloWorld" }, "description": { "default": "HelloWorld description" }, "officeFabricIconFontName": "Page", @@ -374,31 +391,6 @@ Now that we have introduced new properties, ensure that you're again hosting the gulp serve ``` -### Preview the web part in SharePoint's hosted workbench - -SharePoint Workbench is also hosted in SharePoint to preview and test your local web parts in development. The key advantage is that now you're running in SharePoint context and you're able to interact with SharePoint data. - -1. Go to the following URL: **https://your-sharepoint-tenant.sharepoint.com/_layouts/workbench.aspx** - - > [!NOTE] - > If you do not have the SPFx developer certificate installed, Workbench notifies you that it is configured not to load scripts from localhost. Stop the currently running process in the console window, and execute the **gulp trust-dev-cert** command in your project directory console to install the developer certificate before running the **gulp serve** command again. For more information, see [Trusting the self-signed developer certificate](../../set-up-your-development-environment.md#trusting-the-self-signed-developer-certificate) - - ![SharePoint Workbench running in a SharePoint Online site](../../../images/sp-workbench-o365.png) - -1. Notice that the SharePoint Workbench now has the Office 365 Suite navigation bar. -1. Select the **add** icon in the canvas to reveal the toolbox. The toolbox now shows the web parts available on the site where the SharePoint Workbench is hosted along with your **HelloWorldWebPart**. - - ![Toolbox in SharePoint Workbench running in SharePoint Online site](../../../images/sp-workbench-o365-toolbox.png) - -1. Add **HelloWorld** from the toolbox. Now you're running your web part in a page hosted in SharePoint! - - ![HelloWorld web part running in SharePoint Workbench running in a SharePoint Online site](../../../images/sp-workbench-o365-helloworld-wp.png) - -> [!NOTE] -> The color of the web part depends on the colors of the site. By default, web parts inherit the core colors from the site by dynamically referencing Office UI Fabric Core styles used in the site where the web part is hosted. - -Because you're still developing and testing your web part, there is no need to package and deploy your web part to SharePoint. - ## Next steps Congratulations on getting your first Hello World web part running! diff --git a/docs/spfx/web-parts/get-started/build-web-part-microsoft-graph-toolkit.md b/docs/spfx/web-parts/get-started/build-web-part-microsoft-graph-toolkit.md index 3bb9835d4..1e795905e 100644 --- a/docs/spfx/web-parts/get-started/build-web-part-microsoft-graph-toolkit.md +++ b/docs/spfx/web-parts/get-started/build-web-part-microsoft-graph-toolkit.md @@ -2,8 +2,7 @@ title: Build a SharePoint web part with the Microsoft Graph Toolkit description: Get started using the Microsoft Graph Toolkit to build a SharePoint web part. ms.date: 06/01/2021 -localization_priority: Priority -ms.prod: sharepoint +ms.localizationpriority: high --- # Build a SharePoint web part with the Microsoft Graph Toolkit @@ -41,13 +40,13 @@ The Microsoft Graph Toolkit providers enable authentication and access to Micros First, add the provider to your web part. Locate the `src\webparts\\.ts` file in your project folder, and add the following line to the top of your file, right below the existing `import` statements: -```ts +```typescript import { Providers, SharePointProvider } from '@microsoft/mgt-spfx'; ``` Next, you need to initialize the provider with the authenticated context inside the `onInit()` method of your web part. In the same file, add the following code right before the `public render(): void {` line: -```ts +```typescript protected async onInit() { if (!Providers.globalProvider) { Providers.globalProvider = new SharePointProvider(this.context); @@ -59,7 +58,7 @@ protected async onInit() { Now, you can start adding components to your web part. Simply add the components to the HTML inside of the `render()` method, and the components will use the SharePoint context to access Microsoft Graph. For example, to add the [Person component](/graph/toolkit/components/person), your code will look like: -```ts +```typescript public render(): void { this.domElement.innerHTML = ` diff --git a/docs/spfx/web-parts/get-started/connect-to-sharepoint.md b/docs/spfx/web-parts/get-started/connect-to-sharepoint.md index b6078d088..a9d21062b 100644 --- a/docs/spfx/web-parts/get-started/connect-to-sharepoint.md +++ b/docs/spfx/web-parts/get-started/connect-to-sharepoint.md @@ -1,18 +1,20 @@ --- title: Connect your client-side web part to SharePoint (Hello World part 2) description: Access functionality and data in SharePoint and provide a more integrated experience for end users. -ms.date: 06/22/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 11/22/2022 +ms.localizationpriority: high ms.custom: scenarios:getting-started --- # Connect your client-side web part to SharePoint (Hello World part 2) -Connect your web part to SharePoint to access functionality and data in SharePoint and provide a more integrated experience for end users. This article continues building the Hello World web part built in the previous article [Build your first web part](./build-a-hello-world-web-part.md). +Connect your web part to SharePoint to access functionality and data in SharePoint and provide a more integrated experience for end users. -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Community (PnP) YouTube Channel: -> [!Video https://www.youtube.com/embed/4F65TmsHucY] +> [!Video https://www.youtube.com/embed/5M3zDpgxIMs] + +> [!NOTE] +> This article continues building the Hello World web part built in the previous article [Build your first web part](./build-a-hello-world-web-part.md). ## Run gulp serve @@ -25,9 +27,7 @@ gulp serve ## Get access to page context -When the workbench is hosted locally, you don't have the SharePoint page context. You can still test your web part in many different ways. For example, you can concentrate on building the web part's UX and use mock data to simulate SharePoint interaction when you don't have the SharePoint context. - -However, when the workbench is hosted in SharePoint, you get access to the page context, which provides various key properties such as: +The hosted workbench in SharePoint enables access to the page context, which exposes the following key properties such as: - Web title - Web absolute URL @@ -36,51 +36,41 @@ However, when the workbench is hosted in SharePoint, you get access to the page ### To get access to the page context -To access contextual information in your web part, you'll be using the following object in your code: +To access contextual information in your web part, you'll use the following object in your code: ```typescript this.context.pageContext ``` -1. Switch to Visual Studio code (or your preferred IDE) and open **src\webparts\helloWorld\HelloWorldWebPart.ts**. -1. Inside the `render()` method, replace the **innerHTML** code block with the following code: +1. Within Visual Studio Code, locate & open **.\src\webparts\helloWorld\HelloWorldWebPart.ts**. +1. Inside the `render()` method, replace the `innerHTML` code block with the following: ```tsx this.domElement.innerHTML = ` -
    -
    -
    -
    - Welcome to SharePoint! -

    Customize SharePoint experiences using web parts.

    -

    ${escape(this.properties.description)}

    -

    ${escape(this.properties.test)}

    -

    Loading from ${escape(this.context.pageContext.web.title)}

    - - Learn more - -
    -
    -
    -
    `; +
    +
    + +

    Well done, ${escape(this.context.pageContext.user.displayName)}!

    +
    ${this._environmentMessage}
    +
    +
    +

    Welcome to SharePoint Framework!

    +
    Web part description: ${escape(this.properties.description)}
    +
    Web part test: ${escape(this.properties.test)}
    +
    Loading from: ${escape(this.context.pageContext.web.title)}
    +
    +
    `; ``` -1. Notice how `${ }` is used to output the variable's value in the HTML block. An extra HTML `p` is used to display `this.context.pageContext.web.title`. Because this web part loads from the local environment, the title is **Local workbench**. +1. Notice how `${ }` is used to output the variable's value in the HTML block. An extra HTML `div` is used to display `this.context.pageContext.web.title`. 1. Save the file. The **gulp serve** running in your console detects this save operation and: - - Builds and bundles the updated code automatically. - - Refreshes your local workbench page (as the web part code needs to be reloaded). + - builds and bundles the updated code automatically > [!NOTE] > Keep the console window and Visual Studio Code side-by-side to see gulp automatically compile as you save changes in Visual Studio Code. -1. In your browser, switch to the local **SharePoint workbench** tab. If you've already closed the tab, the URL is `https://localhost:4321/temp/workbench.html`. - - You should see the following in the web part: - - ![SharePoint page context in localhost](../../../images/sp-mock-localhost-wp.png) - -1. Navigate to the SharePoint workbench hosted in SharePoint. The full URL is `https://your-sharepoint-site-url/_layouts/workbench.aspx`. Notice that on the SharePoint Online side, you need to refresh the page to see the changes. +1. Navigate to your SharePoint site's hosted workbench hosted. The full URL is `https://your-sharepoint-site-url/_layouts/workbench.aspx`. Refresh the hosted workbench to pick up the changes from the rebuilt code bundle. You should now see your SharePoint site title in the web part now that page context is available to the web part. @@ -90,8 +80,8 @@ this.context.pageContext You need a list model to start working with SharePoint list data. To retrieve the lists, you need two models. -1. Switch to Visual Studio Code and go to **src\webparts\helloWorld\HelloWorldWebPart.ts**. -1. Define the following `interface` models just above the `HelloWorldWebPart` class: +1. Within Visual Studio Code, locate and open **.\src\webparts\helloWorld\HelloWorldWebPart.ts**. +1. Define the following interfaces immediately before the `HelloWorldWebPart` class declaration: ```typescript export interface ISPLists { @@ -106,76 +96,16 @@ You need a list model to start working with SharePoint list data. To retrieve th The **ISPList** interface holds the SharePoint list information that we're connecting to. -## Retrieve lists from mock store - -To test in the local workbench, you need a mock store that returns mock data. - -### To create a mock store - -1. Create a new file inside the **src\webparts\helloWorld** folder named **MockHttpClient.ts**. -1. Copy the following code into **MockHttpClient.ts**: - - ```typescript - import { ISPList } from './HelloWorldWebPart'; - - export default class MockHttpClient { - - private static _items: ISPList[] = [{ Title: 'Mock List', Id: '1' }, - { Title: 'Mock List 2', Id: '2' }, - { Title: 'Mock List 3', Id: '3' }]; - - public static get(): Promise { - return new Promise((resolve) => { - resolve(MockHttpClient._items); - }); - } - } - ``` - - Things to note about the code: - - - Because there are multiple exports in **HelloWorldWebPart.ts**, the specific one to import is specified by using `{ }`. In this case, only the data model `ISPList` is required. - - You don't need to type the file extension when importing from the default module, which in this case is `HelloWorldWebPart`. - - It exports the `MockHttpClient` class as a default module so that it can be imported in other files. - - It builds the initial `ISPList` mock array and returns. - -1. Save the file. - -You can now use the `MockHttpClient` class in the `HelloWorldWebPart` class. You first need to import the `MockHttpClient` module. - -### To import the **MockHttpClient** module - -1. Open the **HelloWorldWebPart.ts** file. -1. Copy and paste the following code just under `import * as strings from 'HelloWorldWebPartStrings';`. - - ```typescript - import MockHttpClient from './MockHttpClient'; - ``` - -1. Add the following private method that mocks the list retrieval inside the `HelloWorldWebPart` class. - - ```typescript - private _getMockListData(): Promise { - return MockHttpClient.get() - .then((data: ISPList[]) => { - var listData: ISPLists = { value: data }; - return listData; - }) as Promise; - } - ``` - -1. Save the file. - ## Retrieve lists from SharePoint site -Next you need to retrieve lists from the current site. You'll use SharePoint REST APIs to retrieve the lists from the site, which are located at **https://yourtenantprefix.sharepoint.com/_api/web/lists**. +Next you need to retrieve lists from the current site. You'll use SharePoint REST APIs to retrieve the lists from the site, which are located at **`https://yourtenantprefix.sharepoint.com/_api/web/lists`**. SharePoint Framework includes a helper class `spHttpClient` to execute REST API requests against SharePoint. It adds default headers, manages the digest needed for writes, and collects telemetry that helps the service to monitor the performance of an application. ### To use this helper class, import them from the @microsoft/sp-http module 1. Scroll to the top of the **HelloWorldWebPart.ts** file. -1. Copy and paste the following code just under `import MockHttpClient from './MockHttpClient';`: +1. Locate the line `import * as strings from 'HelloWorldWebPartStrings';` and add the following code immediately after it: ```typescript import { @@ -184,25 +114,26 @@ SharePoint Framework includes a helper class `spHttpClient` to execute REST API } from '@microsoft/sp-http'; ``` -1. Add the following private method to retrieve lists from SharePoint inside the **HelloWorldWebPart** class. +1. Add the following method to retrieve lists from SharePoint inside the **HelloWorldWebPart** class. ```typescript private _getListData(): Promise { - return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/web/lists?$filter=Hidden eq false`, SPHttpClient.configurations.v1) + return this.context.spHttpClient.get(`${this.context.pageContext.web.absoluteUrl}/_api/web/lists?$filter=Hidden eq false`, SPHttpClient.configurations.v1) .then((response: SPHttpClientResponse) => { return response.json(); - }); + }) + .catch(() => {}); } ``` - The method uses the `spHttpClient` helper class and issues an HTTP **GET** request. It uses the `ISPLists` model and also applies a filter to not retrieve hidden lists. + The method uses the `spHttpClient` helper class and issues an HTTP **GET** request. It uses the `ISPLists` interface and also applies a filter to not retrieve hidden lists. 1. Save the file. 1. Switch to the console window that is running **gulp serve** and check if there are any errors. If there are errors, gulp reports them in the console, and you need to fix them before proceeding. ## Add new styles -The SharePoint Framework uses [Sass](http://sass-lang.com/) as the CSS pre-processor, and specifically uses the [SCSS syntax](http://sass-lang.com/documentation/file.SCSS_FOR_SASS_USERS.html), which is fully compliant with normal CSS syntax. Sass extends the CSS language and allows you to use features such as variables, nested rules, and inline imports to organize and create efficient style sheets for your web parts. The SharePoint Framework already comes with a SCSS compiler that converts your Sass files to normal CSS files, and also provides a typed version to use during development. +The SharePoint Framework uses [Sass](http://sass-lang.com/) as the CSS pre-processor, and specifically uses the [SCSS syntax](http://sass-lang.com/documentation/file.SCSS_FOR_SASS_USERS.html), which is fully compliant with normal CSS syntax. Sass extends the CSS language and allows you to use features such as variables, nested rules, and inline imports to organize and create efficient style sheets for your web parts. The SharePoint Framework already comes with an SCSS compiler that converts your Sass files to normal CSS files, and also provides a typed version to use during development. ### To add new styles @@ -210,7 +141,7 @@ The SharePoint Framework uses [Sass](http://sass-lang.com/) as the CSS pre-proce By default, the styles are scoped to your web part. You can see that as the styles are defined under `.helloWorld`. -1. Add the following styles after the `.button` style, but still inside the main `.helloWorld` style section: +1. Add the following styles after the `.links` style: ```css .list { @@ -252,25 +183,15 @@ The SharePoint Framework uses [Sass](http://sass-lang.com/) as the CSS pre-proce You can see that in the `render()` method of the web part: ```html -
    +
    ``` ## Render lists information Open the `HelloWorldWebPart` class. -SharePoint workbench gives you the flexibility to test web parts in your local environment and from a SharePoint site. SharePoint Framework aids this capability by helping you understand which environment your web part is running from by using the `EnvironmentType` module. - -### To use the EnvironmentType module - -1. Import the `Environment` and the `EnvironmentType` modules from the **\@microsoft/sp-core-library** bundle. Add it to the `import` section at the top as shown in the following code: - - ```typescript - import { - Environment, - EnvironmentType - } from '@microsoft/sp-core-library'; - ``` +> [!NOTE] +> SharePoint Framework provides you options to detect environment details and host location using the `isServedFromLocalhost` property or with EnvironmentType details. In this case we'll focus on connecting to the data in the site which is hosting the online workbench. 1. Add the following private method inside the `HelloWorldWebPart` class: @@ -286,39 +207,27 @@ SharePoint workbench gives you the flexibility to test web parts in your local e `; }); - const listContainer: Element = this.domElement.querySelector('#spListContainer'); - listContainer.innerHTML = html; + if(this.domElement.querySelector('#spListContainer') != null) { + this.domElement.querySelector('#spListContainer')!.innerHTML = html; + } } ``` This method references the new CSS styles added earlier by using the `styles` variable and is used to render list information that will be received from REST API. 1. Save the file. -1. Add the following private method inside the `HelloWorldWebPart` class to call the respective methods to retrieve list data: +1. Add the following private method inside the `HelloWorldWebPart` class to call the method to retrieve list data: ```typescript private _renderListAsync(): void { - // Local environment - if (Environment.type === EnvironmentType.Local) { - this._getMockListData().then((response) => { + this._getListData() + .then((response) => { this._renderList(response.value); - }); - } - else if (Environment.type == EnvironmentType.SharePoint || - Environment.type == EnvironmentType.ClassicSharePoint) { - this._getListData() - .then((response) => { - this._renderList(response.value); - }); - } + }) + .catch(() => {}); } ``` - Things to note about `EnvironmentType` in the `_renderListAsync()` method: - - - The `Environment.type` property helps you check if you are in a local or SharePoint environment. - - The correct method is called depending on where your workbench is hosted. - 1. Save the file. ## Retrieve list data @@ -327,23 +236,20 @@ SharePoint workbench gives you the flexibility to test web parts in your local e ```typescript this.domElement.innerHTML = ` -
    -
    -
    -
    - Welcome to SharePoint! -

    Customize SharePoint experiences using web parts.

    -

    ${escape(this.properties.description)}

    -

    ${escape(this.properties.test)}

    -

    Loading from ${escape(this.context.pageContext.web.title)}

    - - Learn more - -
    -
    -
    -
    -
    `; +
    +
    + +

    Well done, ${escape(this.context.pageContext.user.displayName)}!

    +
    ${this._environmentMessage}
    +
    +
    +

    Welcome to SharePoint Framework!

    +
    Web part description: ${escape(this.properties.description)}
    +
    Web part test: ${escape(this.properties.test)}
    +
    Loading from: ${escape(this.context.pageContext.web.title)}
    +
    +
    +
    `; this._renderListAsync(); ``` @@ -352,17 +258,11 @@ SharePoint workbench gives you the flexibility to test web parts in your local e Notice in the **gulp serve** console window that it rebuilds the code. Make sure you don't see any errors. -1. Switch to your local workbench and add the HelloWorld web part. - - You should see the mock data returned. - - ![Render lists data from localhost](../../../images/sp-lists-render-localhost.png) - -1. Switch to the workbench hosted in SharePoint. Refresh the page and add the HelloWorld web part. +1. If you're using the SharePoint Framework v1.12.1 or earlier, for instance if you're on SharePoint Server on-premises, switch to your local workbench and add the HelloWorld web part. - You should see lists returned from the current site. + You should see the list data returned. - ![Render lists data from SharePoint](../../../images/sp-lists-render-spsite.png) + ![Render lists data from localhost](../../../images/sp-lists-render-online-workbench.png) 1. Now you can stop the server from running. Switch to the console and stop **gulp serve**. Select CTRL+C to stop the gulp task. @@ -370,4 +270,4 @@ SharePoint workbench gives you the flexibility to test web parts in your local e Congratulations on connecting your web part to SharePoint list data! -You can continue building out your Hello World web part in the next topic [Deploy your web part to a SharePoint page](./serve-your-web-part-in-a-sharepoint-page.md). You'll learn how to deploy and preview the Hello World web part in a SharePoint page. +You can continue building out your Hello World web part in the next article [Deploy your web part to a SharePoint page](./serve-your-web-part-in-a-sharepoint-page.md). You'll learn how to deploy and preview the Hello World web part in a SharePoint page. diff --git a/docs/spfx/web-parts/get-started/deploy-web-part-to-cdn.md b/docs/spfx/web-parts/get-started/deploy-web-part-to-cdn.md index 5c0098bc7..f4180434a 100644 --- a/docs/spfx/web-parts/get-started/deploy-web-part-to-cdn.md +++ b/docs/spfx/web-parts/get-started/deploy-web-part-to-cdn.md @@ -1,8 +1,7 @@ --- title: Deploy your SharePoint client-side web part to Azure CDN description: Create a new sample web part and deploy its assets to an Azure CDN instead of using the default Office 365 CDN as the hosting solution. -ms.date: 04/17/2021 -ms.prod: sharepoint +ms.date: 03/08/2023 --- # Deploy your SharePoint client-side web part to Azure CDN @@ -59,13 +58,17 @@ Create a new CDN profile and associate the CDN endpoint with this BLOB container ![Screenshot of create a new CDN profile](../../../images/deploy-create-cdn-profile.png) -1. Create a CDN endpoint as described in [Step 2: Enable CDN for the storage account](/azure/cdn/cdn-create-a-storage-account-with-cdn#step-2-enable-cdn-for-the-storage-account). The CDN endpoint is created with the following URL: **http://spfxsamples.azureedge.net** +1. Create a CDN endpoint as described in [Step 2: Enable CDN for the storage account](/azure/cdn/cdn-create-a-storage-account-with-cdn#step-2-enable-cdn-for-the-storage-account). The CDN endpoint is created with the following URL: **`http://spfxsamples.azureedge.net`** For example, in the following screenshot, **spfxsamples** is the endpoint name, **Storage** is the origin type, and **spfxsamples.blob.core.windows.net** is the storage account. ![Screenshot of create CDN endpoint](../../../images/deploy-create-cdn-endpoint.png) -Because you associated the CDN endpoint with your storage account, you can also access the BLOB container at the following URL: **http://spfxsamples.azureedge.net/azurehosted-webpart/** +1. To allow scripts to be cached by the SharePoint service worker, add an appropriate Cache-Control response header to the CDN endpoint. + + ![Screenshot of add a cache control header](../../../images/deploy-create-cdn-cache-control-header.png) + +Because you associated the CDN endpoint with your storage account, you can also access the BLOB container at the following URL: **`http://spfxsamples.azureedge.net/azurehosted-webpart/`** Note, however, that you have not yet deployed the files. diff --git a/docs/spfx/web-parts/get-started/hosting-webpart-from-office-365-cdn.md b/docs/spfx/web-parts/get-started/hosting-webpart-from-office-365-cdn.md index dd18fe82d..3d7a22cb1 100644 --- a/docs/spfx/web-parts/get-started/hosting-webpart-from-office-365-cdn.md +++ b/docs/spfx/web-parts/get-started/hosting-webpart-from-office-365-cdn.md @@ -1,9 +1,8 @@ --- title: Host your client-side web part from Microsoft 365 CDN (Hello World part 4) description: An easy solution to host your assets directly from your own Microsoft 365 tenant. Can be used for hosting any static assets that are used in SharePoint Online. -ms.date: 06/29/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 11/02/2023 +ms.localizationpriority: high ms.custom: scenarios:getting-started --- @@ -15,7 +14,7 @@ Microsoft 365 Content Delivery Network (CDN) provides you an easy solution to ho > There are multiple different hosting options for your web part assets. This tutorial concentrates on showing the Microsoft 365 CDN option, but you could also use the [Azure CDN](./deploy-web-part-to-cdn.md) or simply host your assets from SharePoint library from your tenant. In the latter case, you would not benefit from the CDN performance improvements, but that would also work from the functionality perspective. Any location that end users can access using HTTP(S) would be technically suitable for hosting the assets for end users. > [!IMPORTANT] -> This article uses the `includeClientSideAssets` attribute, which was introduced in the SharePoint Framework (SPFx) v1.4. This version is not supported with **SharePoint 2016 Feature Pack 2**.> +> This article uses the `includeClientSideAssets` attribute introduced in the [SharePoint Framework (SPFx) v1.4](../../release-1.4.md). This version is not supported with **SharePoint 2016 Feature Pack 2**. > If you're using an on-premises setup, you need to decide the CDN hosting location separately. You can also simply host the JavaScript files from a centralized library in your on-premises SharePoint to which your users have access. Please see additional considerations in the [SharePoint 2016 specific guidance](../../sharepoint-2016-support.md). Make sure that you've completed the following tasks before you begin: @@ -24,9 +23,9 @@ Make sure that you've completed the following tasks before you begin: - [Connect your client-side web part to SharePoint](./connect-to-sharepoint.md) - [Deploy your client-side web part to a SharePoint page](./serve-your-web-part-in-a-sharepoint-page.md) -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Communtiy (PnP) YouTube Channel: -> [!Video https://www.youtube.com/embed/wl2ur1SBp3Q] +> [!Video https://www.youtube.com/embed/N-KowN-UwTM] ## Enable CDN in your Microsoft 365 tenant @@ -35,7 +34,8 @@ For information on enabling and configuring the Microsoft 365 CDN in your ShareP ## Finalize solution for deployment 1. Switch to the console and make sure you're still in the project directory that you used to set up your web part project. -1. End the possible **gulp serve** task by selecting CTRL+C, and ensure that you're in your project directory: +1. If you are still running the local webserver by executing **gulp serve** in the previous tutorial, press CTRL+C to terminate it. +1. Ensure you're in your project directory: ```console cd helloworld-webpart @@ -49,19 +49,47 @@ For information on enabling and configuring the Microsoft 365 CDN in your ShareP The **package-solution.json** file defines the package metadata as shown in the following code: ```json - { - "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", - "solution": { - "name": "helloword-webpart-client-side-solution", - "id": "3c1af394-bbf0-473c-bb7d-0798f0587cb7", - "version": "1.0.0.0", - "includeClientSideAssets": true, - "isDomainIsolated": false - }, - "paths": { - "zippedPackage": "solution/helloword-webpart.sppkg" - } + { + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", + "solution": { + "name": "hello-world-client-side-solution", + "id": "e8905bc9-2718-4bc8-aea6-03a2b5cf8e76", + "version": "1.0.0.0", + "includeClientSideAssets": true, + "skipFeatureDeployment": true, + "isDomainIsolated": false, + "developer": { + "name": "", + "websiteUrl": "", + "privacyUrl": "", + "termsOfUseUrl": "", + "mpnId": "Undefined-1.18.0" + }, + "metadata": { + "shortDescription": { + "default": "HelloWorld description" + }, + "longDescription": { + "default": "HelloWorld description" + }, + "screenshotPaths": [], + "videoUrl": "", + "categories": [] + }, + "features": [ + { + "title": "hello-world Feature", + "description": "The feature that activates elements of the hello-world solution.", + "id": "45108667-812b-46ee-a8c3-7edc40b6a933", + "version": "1.0.0.0" + } + ] + }, + "paths": { + "zippedPackage": "solution/hello-world.sppkg" + } } + ``` The default value for the `includeClientSideAssets` is `true`, which means that static assets are packaged automatically in the **\*.sppkg** files, and you don't need to separately host your assets from an external system. @@ -88,15 +116,15 @@ If Microsoft 365 CDN *is enabled*, it's used automatically with default settings > If you're interested in what actually got packaged inside of the **\*.sppkg** file, you can look in the content of the **sharepoint/solution/debug** folder. 1. Upload or drag and drop the newly created client-side solution package to the app catalog in your tenant. -1. Because you already deployed the package, you're prompted as to whether to replace the existing package. Select **Replace It**. +1. Because you already deployed the package, you're prompted as to whether to replace the existing package. Select **Replace**. ![Override existing solution](../../../images/cdn-override-helloworld-webpart-package.png) -1. Notice how the **domain** list in the prompt says *SharePoint Online*. This is because the content is either served from the Microsoft 365 CDN or from the app catalog, depending on the tenant settings. Select **Deploy**. +1. Notice how the **domain** list in the prompt says *SharePoint Online*. This is because the content is either served from the Microsoft 365 CDN or from the app catalog, depending on the tenant settings. Select **Enable app**. ![Installation popup from app catalog for the SPFx solution](../../../images/cnd-trust-helloworld-webpart-solution.png) -1. Open the site where you previously installed the **helloworld-webpart-client-side-solution** or installed the solution to a new site. +1. Open the site where you previously installed the **helloworld-webpart-client-side-solution** or install the solution to a new site. 1. After the solution has been installed, select **Add a page** from the *gear* menu, and select **HelloWorld** from the modern page web part picker to add your custom web part to page. ![HelloWorld web part visible in web part picker for modern page](../../../images/cdn-web-part-picker.png) @@ -112,7 +140,7 @@ If Microsoft 365 CDN *is enabled*, it's used automatically with default settings ![HelloWorld web part bundle coming from public CDN URL in the sources tab of Chrome developer tools](../../../images/cdn-web-part-f12-source.png) > [!NOTE] -> If you would not have CDN enabled in your tenant, and the `includeClientSideAssets` setting would be `true`in the **package-solution.json**, the loading URL for the assets would be dynamically updated and pointing directly to the ClientSideAssets folder located in the app catalog site collection. In this example case, the URL would be **https://sppnp.microsoft.com/sites/apps/ClientSideAssets/**. This change is automatic depending on your tenant settings and it does not require any changes in the actual solution package. +> If you would not have CDN enabled in your tenant, and the `includeClientSideAssets` setting would be `true`in the **package-solution.json**, the loading URL for the assets would be dynamically updated and pointing directly to the ClientSideAssets folder located in the app catalog site collection. In this example case, the URL would be `https://sppnp.microsoft.com/sites/apps/ClientSideAssets/`. This change is automatic depending on your tenant settings and it does not require any changes in the actual solution package. Now you've deployed your custom web part to SharePoint Online and it's being hosted automatically from the Microsoft 365 CDN. diff --git a/docs/spfx/web-parts/get-started/office-addins-tutorial.md b/docs/spfx/web-parts/get-started/office-addins-tutorial.md deleted file mode 100644 index ce659e029..000000000 --- a/docs/spfx/web-parts/get-started/office-addins-tutorial.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -title: Tutorial for creating Outlook Web Access extension using SharePoint Framework -description: Creating Outlook add-ins using SharePoint Framework -ms.date: 08/19/2020 -ms.prod: sharepoint -localization_priority: Priority ---- - -# Tutorial for creating Outlook Web Access extension using SharePoint Framework - -Starting with the SharePoint Framework v1.10, you can also implement your Office add-ins using SharePoint Framework. This significantly simplifies add-in development process as SharePoint Framework web parts are automatically hosted within SharePoint without any need for external services. In preview time frame, this model is only supported for the Outlook Web Access, but will be extended across all Office web and desktop clients. - -* [Build your first web part](build-a-hello-world-web-part.md) -* [Connect your web part to SharePoint](connect-to-sharepoint.md) -* [Deploy your client-side web part to a SharePoint page](provision-sp-assets-from-package.md) - -> [!IMPORTANT] -> This lab requires that you are using at least version 1.10 of the SharePoint Framework as these capabilities are not available in earlier versions. - -> [!NOTE] -> This feature was introduced as a developer preview feature. In order to use features in developer preview, ensure you use the `--plusbeta` version of the library (*see [Try SharePoint Framework preview capabilities](../../try-preview-capabilities.md) for more information*). - -> [!Video https://www.youtube.com/embed/QtGjTAjbIKU] - -## Create a new solution - -1. Create a new project directory in your favorite location: - - ```console - md outlook-add-in - ``` - -1. Go to the project directory: - - ```console - cd outlook-add-in - ``` - -1. Create a new client-side web part solution by running the Yeoman SharePoint Generator: - - ```console - yo @microsoft/sharepoint --plusbeta - ``` - -1. When prompted: - - * Accept the default **outlook-add-in** as your solution name, and then select Enter. - * Select **SharePoint Online only (latest)**, and then select Enter. - * Select **Use the current folder** as the location for the files. - * Select **y** to ensure that your web part is automatically deployed tenant-wide when it's added to the tenant App Catalog. - * Select **N** on the question if solution contains unique permissions. - * Select **WebPart** as the client-side component type to be created. - -1. The next set of prompts asks for specific information about your web part: - - * Enter **MyFirstOWAaddin** for the web part name, and then select Enter. - * Enter **My first Outlook add-in** as the description of the web part, and then select Enter. - * Accept the default **No JavaScript web framework** option for the framework, and then select Enter to continue. - - ![Yeoman prompts](../../../images/add-in-yeoman.png) - - At this point, Yeoman installs the required dependencies and scaffolds the solution files. Creation of the solution might take a few minutes. Yeoman scaffolds the project to include your **MyFirstOWAaddin** web part, which will act as the add-in in Outlook Web App. - -1. Next, enter the following to open the web part project in Visual Studio Code: - - ```console - code . - ``` - -Starting with the SharePoint Framework v1.10, scaffolding will also include additional **./officeAddin** folder in the solution structure, with a default manifest file for your solution to get published as a Outlook Web App add-in. - - ![Solution structure](../../../images/add-in-solution-structure.png) - -**officeAddin** folder contains the following file: - - * **[componentId]_outlookManifest.xml** - Default manifest definition for your solution - -Manifest file contains by default definition to expose your add-in as a tool pane add-in the Outlook Web App with default values. You can modify the structure as needed based on your business requirements. - -## Install Office types to your solution - -In the console, enter the following to install the types for the Office JavaScript SDK from the npm: - -```console -npm install @types/office-js --save-dev -``` - -This adds the needed intelligence for the Office JavaScript SDK types when you develop your solution in TypeScript. - -## Making solution aware of the Office context - -1. Open **src\webparts\myFirstOwAaddin\MyFirstOwAaddinWebPart.ts** for the needed edits on making our solution aware of the Office context, if it's used as an Outlook Web App add-in. - -1. Update the **render** method as follows. Notice how we are rendering different content dependent if the code is rendered as an Outlook Web App add-in or as a web part in SharePoint. We can detect if solution is hosted Outlook Web App by checking the `this.context.sdks.office` property. - - ```typescript - public render(): void { - - let title: string = ''; - let subTitle: string = ''; - let contextDetail: string = ''; - - if (this.context.sdks.office) { - // We have Office context for the solution - title = "Welcome to Office!"; - subTitle = "Extending Office with custom business extensions."; - contextDetail = "We are in the context of following email: " + this.context.sdks.office.context.mailbox.userProfile.emailAddress; - } - else - { - // We are rendered in normal SharePoint context - title = "Welcome to SharePoint!"; - subTitle = "Customize SharePoint experiences using Web Parts."; - contextDetail = "We are in the context of following site: " + this.context.pageContext.web.title; - } - - this.domElement.innerHTML = ` -
    -
    -
    -
    - ${title} -

    ${subTitle}

    -

    ${contextDetail}

    -

    ${escape(this.properties.description)}

    - - Learn more - -
    -
    -
    -
    `; - - } - ``` - - > [!NOTE] - > See more information around the Office JavaScript API capabilities from the [API Reference documentation](/office/dev/add-ins/reference/javascript-api-for-office). - -## Packaging and deploying your solution to SharePoint - -Ensure that your console is activated in the root folder of the solution, which was created. - -1. Execute the following commands to build bundle your solution. This executes a release build of your project by using a dynamic label as the host URL for your assets. - - ```console - gulp bundle --ship - ``` - -1. Execute the following task to package your solution. This creates an updated **outlook-add-in.sppkg** package on the **sharepoint/solution** folder. - - ```console - gulp package-solution --ship - ``` - -Next, you need to deploy the package that was generated to the tenant App Catalog. - -> [!NOTE] -> If you do not have an app catalog, a SharePoint Online Admin can create one by following the instructions in this guide: [Use the App Catalog to make custom business apps available for your SharePoint Online environment](https://support.office.com/article/use-the-app-catalog-to-make-custom-business-apps-available-for-your-sharepoint-online-environment-0b6ab336-8b83-423f-a06b-bcc52861cba0). - -1. Go to your tenant's SharePoint App Catalog. - -1. Upload or drag and drop the **outlook-add-in.sppkg** to the App Catalog. - - ![Upload solution to App Catalog](../../../images/add-in-solution-upload-catalog.png) - - This deploys the client-side solution package. Because this is a full trust client-side solution, SharePoint displays a dialog and asks you to trust the client-side solution to deploy. - - Notice how the **domain** list in the prompt says *SharePoint Online*. This is because the content is either served from the Office 365 CDN or from the App Catalog, depending on the tenant settings. - - Ensure that the **Make this solution available to all sites in the organization** option is selected, so that the web part can be used from the Outlook Web Access side. - - ![Trust client-side solution deployment](../../../images/add-in-upload-solution-deploy.png) - -1. Select **Deploy**. - - Notice that you can see if there's any exceptions or issues in the package by looking the **App Package Error Message** column in the App Catalog. - -Now the web part is deployed and is automatically available cross the SharePoint Online sites. - -> [!NOTE] -> In this tutorial case, we are using tenant wide deployment option of the SharePoint Framework solution. This will ensure that the development and usage experience is as easy as possible. You could also deploy the solution as site scope, but in that case you'd need to ensure that the solution is deployed on the SharePoint site behind of the Microsoft Teams, before you can use it. - -## Install solution to Outlook Web Access - -Next steps is to enable the add-in the Outlook Web Access. - -1. Activate one of the existing mails in your inbox -1. Select **[...]** and choose **Get Add-ins** - - ![Get add-ins context menu](../../../images/add-in-get-add-ins-context-menu.png) - -1. Choose **My add-ins** from the left menu - - ![My add-ins left menu](../../../images/add-in-my-addins-menu.png) - -1. Choose **Add from file...* under the **Custom add-ins** - - ![Add from file](../../../images/add-in-add-from-file.png) - -1. Upload the manifest xml file from your project solution under the **officeAddin** folder -1. Click **Install** on the warning message to get your add-in available on the tenant - - ![Warning - Install](../../../images/add-in-install-warning.png) - -1. Close the add-in window by clicking **X** on the top-right corner -1. Activate again the context menu from ***[...]*** and choose **SPFx template** to activate the add-in in your inbox - 1. Name can be adjusted in the manifest file as needed - -> [!IMPORTANT] -> Deployment process will include different steps when additional applications and desktop will be supported. diff --git a/docs/spfx/web-parts/get-started/provision-sp-assets-from-package.md b/docs/spfx/web-parts/get-started/provision-sp-assets-from-package.md index bc5742851..4c3f826e1 100644 --- a/docs/spfx/web-parts/get-started/provision-sp-assets-from-package.md +++ b/docs/spfx/web-parts/get-started/provision-sp-assets-from-package.md @@ -1,9 +1,8 @@ --- title: Provision SharePoint assets from your SharePoint client-side web part description: SharePoint assets can be provisioned as part of the SharePoint Framework solution, and deployed to SharePoint sites when the solution is installed on it. -ms.date: 08/19/2020 -localization_priority: Priority -ms.prod: sharepoint +ms.date: 05/03/2023 +ms.localizationpriority: high ms.custom: scenarios:getting-started --- @@ -11,14 +10,17 @@ ms.custom: scenarios:getting-started SharePoint assets can be provisioned as part of the SharePoint Framework solution, and are deployed to SharePoint sites when the solution is installed on it. +> [!NOTE] +> \*.sppkg packages that contain SharePoint assets cannot be tenant deployed from the tenant application catalog, and cannot be used in a site application catalog. + Before you start, complete the procedures in the following articles to ensure that you understand the basic flow of creating a custom client-side web part: - [Build your first web part](build-a-hello-world-web-part.md) - [Connect your web part to SharePoint](connect-to-sharepoint.md) -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Communtiy (PnP) YouTube Channel: -> [!Video https://www.youtube.com/embed/_oHjmahz4B8] +> [!Video https://www.youtube.com/embed/09uoG6Voeew] ## Create a new web part project @@ -45,7 +47,7 @@ You can also follow these steps by watching this video on the SharePoint PnP You - **What is your solution name?**: asset-deployment-webpart - **Which type of client-side component to create?**: WebPart - **What is your Web part name?**: AssetDeployment -- **Which framework would you like to use?**: No JavaScript web framework +- **Which template would you like to use?**: No JavaScript framework At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your **AssetDeployment** web part as well. @@ -75,7 +77,7 @@ To provision SharePoint assets to sites with feature framework elements, we need - List instances - List instances with custom schema -### Add an element.xml file for SharePoint definitions +### Add an elements.xml file for SharePoint definitions In the following steps, we define the needed structure to be provisioned. @@ -199,7 +201,7 @@ At this point, we've created the files for provisioning SharePoint assets using The **package-solution.json** file defines the package metadata as shown in the following code: -1. Ensure the new Feature Framework files included in the SharePoint Package. +1. Ensure the new Feature Framework files included in the SharePoint Package. Include a Feature Framework feature definition for the solution package. Include a JSON definition for the needed feature in the solution structure as demonstrated in the following code: @@ -240,7 +242,7 @@ There are a few things to take note of from this XML: - Make sure you define a **unique GUID** for the `id` property in the `feature` property. - You can technically have multiple features in the package because the `features` property is an array. However, this isn't recommended. - **elements.xml** is referenced under `elementManifests` so that it's properly packaged for the feature definition as an element manifest file. -- You can have multiple **element.xml** files in the definition, and they would be executed in the order they're mentioned in the JSON definition. Typically, you should avoid using multiple **element.xml** files because this adds unnecessary complexity. You can define all needed assets in a single **element.xml** file. +- You can have multiple **elements.xml** files in the definition, and they would be executed in the order they're mentioned in the JSON definition. Typically, you should avoid using multiple **elements.xml** files because this adds unnecessary complexity. You can define all needed assets in a single **elements.xml** file. ## Deploy and test asset provisioning @@ -420,15 +422,15 @@ With the package been updated in the app catalog, we can move to the SharePoint This presents the current details around the installed SharePoint Framework solution. This page also now shows the text as **There is a new version of this app. Get it now** to indicate that there's a new version available. - ![Context menu of existing package in site](../../../images/tutorial-feature-solution-app-details.png) + ![Details of the app package](../../../images/tutorial-feature-solution-app-details.png) 1. Select the **GET IT** button to start the update process for the package. - ![App status updated to updating in the site contents page](../../../images/tutorial-feature-solution-updating-app.png) + ![App status updated to updating in the site contents page (modern)](../../../images/tutorial-feature-solution-updating-app.png) If you move to the classic experience, you can see more details on the actual upgrade action being applied for the SharePoint Framework solution. - ![App status updated to updating in the site contents page](../../../images/tutorial-feature-solution-updating-app-classic.png) + ![App status updated to updating in the site contents page (classic)](../../../images/tutorial-feature-solution-updating-app-classic.png) > [!NOTE] > Because the SharePoint Framework uses the same app infrastructure as SharePoint Add-ins, the status for the upgrade indicates that the update can happen for an add-in or an app. diff --git a/docs/spfx/web-parts/get-started/serve-your-web-part-in-a-sharepoint-page.md b/docs/spfx/web-parts/get-started/serve-your-web-part-in-a-sharepoint-page.md index 598a702f7..b1f6047ea 100644 --- a/docs/spfx/web-parts/get-started/serve-your-web-part-in-a-sharepoint-page.md +++ b/docs/spfx/web-parts/get-started/serve-your-web-part-in-a-sharepoint-page.md @@ -1,9 +1,8 @@ --- title: Deploy your client-side web part to a SharePoint page (Hello World part 3) description: Deploy your client-side web part to SharePoint and see it working on a modern SharePoint page. -ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 11/02/2023 +ms.localizationpriority: high ms.custom: scenarios:getting-started --- @@ -14,9 +13,9 @@ Ensure that you've completed the procedures in the following articles before you - [Build your first SharePoint client-side web part](./build-a-hello-world-web-part.md) - [Connect your client-side web part to SharePoint](./connect-to-sharepoint.md) -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Communtiy (PnP) YouTube Channel: -> [!Video https://www.youtube.com/embed/CMJEp8TS4aU] +> [!Video https://www.youtube.com/embed/FkFg32NSTM0] ## Package the HelloWorld web part @@ -37,20 +36,51 @@ You can also follow these steps by watching this video on the SharePoint PnP You ```json { - "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", - "solution": { - "name": "helloworld-webpart-client-side-solution", - "id": "3c1af394-bbf0-473c-bb7d-0798f0587cb7", - "version": "1.0.0.0", - "includeClientSideAssets": true, - "isDomainIsolated": false - }, - "paths": { - "zippedPackage": "solution/helloworld-webpart.sppkg" - } + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", + "solution": { + "name": "hello-world-client-side-solution", + "id": "e8905bc9-2718-4bc8-aea6-03a2b5cf8e76", + "version": "1.0.0.0", + "includeClientSideAssets": true, + "skipFeatureDeployment": true, + "isDomainIsolated": false, + "developer": { + "name": "", + "websiteUrl": "", + "privacyUrl": "", + "termsOfUseUrl": "", + "mpnId": "Undefined-1.18.0" + }, + "metadata": { + "shortDescription": { + "default": "HelloWorld description" + }, + "longDescription": { + "default": "HelloWorld description" + }, + "screenshotPaths": [], + "videoUrl": "", + "categories": [] + }, + "features": [ + { + "title": "hello-world Feature", + "description": "The feature that activates elements of the hello-world solution.", + "id": "45108667-812b-46ee-a8c3-7edc40b6a933", + "version": "1.0.0.0" + } + ] + }, + "paths": { + "zippedPackage": "solution/hello-world.sppkg" + } } ``` +1. In the console window, enter the following command to bundle your client-side solution: + ```console + gulp bundle + ``` 1. In the console window, enter the following command to package your client-side solution that contains the web part: ```console @@ -80,6 +110,10 @@ Next, you need to deploy the package that was generated to the app catalog. > If you do not have an app catalog, a SharePoint Online Admin can create one by following the instructions in this guide: [Use the App Catalog to make custom business apps available for your SharePoint Online environment](https://support.office.com/article/use-the-app-catalog-to-make-custom-business-apps-available-for-your-sharepoint-online-environment-0b6ab336-8b83-423f-a06b-bcc52861cba0). 1. Go to your site's app catalog. +1. If you see classic experience in the app catalog, choose to move the new experience by clicking **Try the new Manage Apps page** in the header + + ![New app catalog experience notice](../../../images/new-app-catalog-experience-notice.png) + 1. Upload or drag and drop the **helloworld-webpart.sppkg** to the app catalog. ![Upload solution to app catalog](../../../images/upload-solution-app-catalog.png) @@ -88,7 +122,7 @@ Next, you need to deploy the package that was generated to the app catalog. ![Trust client-side solution deployment](../../../images/sp-app-deploy-trust.png) -1. Select **Deploy**. +1. Select **Enable app**. Notice that you can see if there's any exceptions or issues in the package by looking the **App Package Error Message** column in the app catalog. @@ -102,24 +136,25 @@ Notice that you can see if there's any exceptions or issues in the package by lo 1. Select the **helloworld-webpart-client-side-solution** app to install the app on the site. - ![Trust app](../../../images/app-installed-your-site.png) + ![Installed app](../../../images/app-installed-your-site.png) The client-side solution and the web part are installed on your developer site. + The **Site Contents** page shows you the installation status of your client-side solution. Make sure the installation is complete before going to the next step. ## Preview the web part on a SharePoint page Now that you've deployed and installed the client-side solution, add the web part to a SharePoint page. Remember that resources such as JavaScript and CSS are available from the local computer, so rendering of the web parts will fail unless your localhost is running. -1. Open the **.manifest.json** from the **dist** folder. +1. Open the **{{your-webpart-guid}}.manifest.json** from the **dist** folder. Notice that the `internalModuleBaseUrls` property in the `loaderConfig` entry still refers to your local computer: ```json "internalModuleBaseUrls": [ - "https://`your-local-machine-name`:4321/" - ] + "https://localhost:4321/dist/" + ], ``` 1. *Before* adding the web part to a SharePoint server-side page, run the local server. @@ -158,7 +193,7 @@ You should see the **HelloWorld** web part you built in the previous article tha 1. Edit the **Description** property, and enter **Client-side web parts are awesome!** - ![Hello World web part in modern page](../../../images/sp-wp-modern-page-pp.png) + ![Hello World web part in modern page with property pane](../../../images/sp-wp-modern-page-pp.png) 1. Notice that you still have the same behaviors such as a reactive pane where the web part is updated as you type. 1. Select the **x** icon to close the client-side property pane. diff --git a/docs/spfx/web-parts/get-started/use-fabric-react-components.md b/docs/spfx/web-parts/get-started/use-fabric-react-components.md index 9828c6e20..d033fef8e 100644 --- a/docs/spfx/web-parts/get-started/use-fabric-react-components.md +++ b/docs/spfx/web-parts/get-started/use-fabric-react-components.md @@ -1,9 +1,8 @@ --- title: Use Office UI Fabric React components in your SharePoint client-side web part description: Build a web part that uses the DocumentCard component of Office UI Fabric React. -ms.date: 06/22/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 02/14/2022 +ms.localizationpriority: high ms.custom: scenarios:getting-started --- @@ -15,7 +14,7 @@ This article describes how to build a web part like in the following image, that ![Image of a DocumentCard Fabric component in a SharePoint workbench](../../../images/fabric-components-doc-card-view-ex.png) -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Communtiy (PnP) YouTube Channel: > [!Video https://www.youtube.com/embed/kNrYd8nYaZY] @@ -50,23 +49,16 @@ This page will continue to refer to the Office UI Fabric packages until Microsof cd documentcardexample-webpart ``` -1. Make sure you have the latest version of **\@microsoft/generator-sharepoint** installed and create a new web part by running the Yeoman SharePoint generator: +1. Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: ```console yo @microsoft/sharepoint ``` -1. When prompted, enter the following values (*select the default option for all prompts omitted below*): + The Yeoman SharePoint Generator will prompt you with a series of questions. For all questions, accept the default options except for the following questions: - - **What is your solution name?**: documentcardexample-webpart - - **Which baseline packages do you want to target for your component(s)?**: SharePoint Online only (latest) - - **Where do you want to place the files?**: Use the current folder - - **Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites?**: Yes - - **Will the components in the solution require permissions to access web APIs that are unique and not shared with other components in the tenant?**: No - **Which type of client-side component to create?**: Web Part - - **What is your Web part name?**: DocumentCardExample - - **What is your Web part description?**: DocumentCardExample description - - **Which framework would you like to use?**: React + - **Which template would you like to use?**: React At this point, Yeoman installs the required dependencies and scaffolds the solution files. @@ -210,14 +202,15 @@ Copy the following images to your **src\webparts\documentCardExample\components* > [!NOTE] > In the code, we were referencing these images using relative path from the root location. As your reference the images in the code, it will cause them to be included in the **\*.sppkg** solution package as long as you have the `includeClientSideAssets` set as `true` in the **package-solution.json** file. -## Preview the web part in workbench +## Preview the web part in the hosted workbench -1. In the console, enter the following to preview your web part in workbench: +1. In the console, enter the following to preview your web part in the SharePoint hosted workbench: ```console - gulp serve + gulp serve --nobrowser ``` +1. Open a browser and navigate to your SharePoint site's hosted workbench: `https://enter-your-SharePoint-site/_layouts/workbench.aspx`. 1. In the toolbox, select your `DocumentCardExample` web part to add: ![Image of a DocumentCard Fabric component in a SharePoint workbench](../../../images/fabric-components-doc-card-view-ex.png) diff --git a/docs/spfx/web-parts/get-started/using-microsoft-graph-apis.md b/docs/spfx/web-parts/get-started/using-microsoft-graph-apis.md index ecc090be9..91f7ae728 100644 --- a/docs/spfx/web-parts/get-started/using-microsoft-graph-apis.md +++ b/docs/spfx/web-parts/get-started/using-microsoft-graph-apis.md @@ -1,9 +1,8 @@ --- title: Building SharePoint Framework solutions, which use Microsoft Graph description: Getting started tutorial on using Microsoft Graph with SharePoint Framework solutions -ms.date: 08/19/2020 -localization_priority: Priority -ms.prod: sharepoint +ms.date: 11/24/2022 +ms.localizationpriority: high --- # Use Microsoft Graph in your solution @@ -17,7 +16,7 @@ Before you start, complete the procedures in the following articles to ensure th - [Deploy your client-side web part to a SharePoint page](provision-sp-assets-from-package.md) -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Communtiy (PnP) YouTube Channel: > [!Video https://www.youtube.com/embed/tHzbh5JoC-A] @@ -35,19 +34,18 @@ You can also follow these steps by watching this video on the SharePoint PnP You cd graph-apis ``` -1. Create a new solution by running the Yeoman SharePoint Framework Generator: +1. Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: ```console yo @microsoft/sharepoint ``` -1. When prompted, enter the following values (*select the default option for all prompts omitted below*): + The Yeoman SharePoint Generator will prompt you with a series of questions. For all questions, accept the default options except for the following questions: - - **What is your solution name?**: graph-apis - **Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites?**: Yes - **Which type of client-side component to create?**: WebPart - **What is your Web part name?**: MyFirstGraphWebPart - - **Which framework would you like to use?**: No JavaScript framework + - **Which framework would you like to use?**: No framework At this point, Yeoman installs the required dependencies and scaffolds the solution files. Creation of the solution might take a few minutes. Yeoman scaffolds the project to include your **MyFirstGraphWebPart** web part as well. @@ -103,17 +101,17 @@ In this case, we'll modify the code to use Microsoft Graph to get access on the 1. Add the following `import` statements after the existing `import` statements at the top fo the file: ```typescript - import { MSGraphClient } from '@microsoft/sp-http'; + import { MSGraphClientV3 } from '@microsoft/sp-http'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; ``` -1. Update the `render()` method as follows. Notice how we're using the `MSGraphClient` object for the Microsoft Graph calls. This object abstracts the access token handling, so that as a developer, you can concentrate on your business logic. +1. Update the `render()` method as follows. Notice how we're using the `MSGraphClientV3` object for the Microsoft Graph calls. This object abstracts the access token handling, so that as a developer, you can concentrate on your business logic. ```typescript public render(): void { this.context.msGraphClientFactory - .getClient() - .then((client: MSGraphClient): void => { + .getClient('3') + .then((client: MSGraphClientV3): void => { // get information about the current user from the Microsoft Graph client .api('/me/messages') @@ -122,21 +120,18 @@ In this case, we'll modify the code to use Microsoft Graph to get access on the .get((error, messages: any, rawResponse?: any) => { this.domElement.innerHTML = ` -
    -
    -
    -
    - Welcome to SharePoint! -

    Use Microsoft Graph in SharePoint Framework.

    -
    -
    +
    +
    +

    Welcome to SharePoint Framework!

    +

    + The SharePoint Framework (SPFx) is a extensibility model for Microsoft Viva, Microsoft Teams and SharePoint. It's the easiest way to extend Microsoft 365 with automatic Single Sign On, automatic hosting and industry standard tooling. +

    -
    +
    `; // List the latest emails based on what we got from the Graph this._renderEmailList(messages.value); - }); }); } @@ -148,7 +143,7 @@ In this case, we'll modify the code to use Microsoft Graph to get access on the private _renderEmailList(messages: MicrosoftGraph.Message[]): void { let html: string = ''; for (let index = 0; index < messages.length; index++) { - html += `

    Email ${index + 1} - ${escape(messages[index].subject)}

    `; + html += `

    Email ${index + 1} - ${escape(messages[index].subject)}

    `; } // Add the emails to the placeholder @@ -199,7 +194,7 @@ Now the web part is deployed and is automatically available cross the SharePoint ## Approve the requested Microsoft Graph permissions -1. Move to the SharePoint tenant administrative UIs located at **https://-admin.sharepoint.com**. +1. Move to the SharePoint tenant administrative UIs located at **https://{{tenant}}-admin.sharepoint.com**. 1. Move to **Advanced > API management** in the left menu option to see the currently pending permission requests. Notice that the request for **Mail.Read** permission for Microsoft Graph is pending for approval. ![API management](../../../images/graph-helloworld-api-admin.png) @@ -227,11 +222,11 @@ At this point, the requested permissions needed for the web part have been appro 1. Choose **MyFirstGraphWebPart** from the list and notice how the web part renders the latest five emails from the current user using information from the Microsoft Graph API - ![web part picker](../../../images/graph-helloworld-webpart-on-page.png) + ![Rendered web part](../../../images/graph-helloworld-webpart-on-page.png) ## See also -- [Use the MSGraphClient to connect to Microsoft Graph](https://docs.microsoft.com/sharepoint/dev/spfx/use-msgraph) -- [Consume the Microsoft Graph in the SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/use-aad-tutorial) +- [Use the MSGraphClient to connect to Microsoft Graph](/sharepoint/dev/spfx/use-msgraph) +- [Consume the Microsoft Graph in the SharePoint Framework](/sharepoint/dev/spfx/use-aad-tutorial) - [Graph Explorer](https://developer.microsoft.com/graph/graph-explorer) - [Get started with Microsoft Graph and JavaScript](https://developer.microsoft.com/graph/get-started/javascript) diff --git a/docs/spfx/web-parts/get-started/using-web-part-as-ms-teams-tab.md b/docs/spfx/web-parts/get-started/using-web-part-as-ms-teams-tab.md index 554015622..576821d0e 100644 --- a/docs/spfx/web-parts/get-started/using-web-part-as-ms-teams-tab.md +++ b/docs/spfx/web-parts/get-started/using-web-part-as-ms-teams-tab.md @@ -1,9 +1,8 @@ --- title: Build Microsoft Teams tab using SharePoint Framework - Tutorial description: Tutorial on how to build Microsoft Teams tabs using SharePoint Framework. Capability was released to general availability in SharePoint Framework v1.8. -ms.date: 05/18/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 10/21/2021 +ms.localizationpriority: high --- # Build Microsoft Teams tab using SharePoint Framework - Tutorial @@ -19,7 +18,7 @@ Before you start, complete the procedures in the following articles to ensure th > [!IMPORTANT] > This tutorials requires that you are using the SharePoint Framework v1.10 or higher as some capabilities and framework properties are not available in earlier versions. -You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel: +You can also follow these steps by watching this video on the Microsoft 365 Platform Communtiy (PnP) YouTube Channel: > [!Video https://www.youtube.com/embed/JoTAC2i-XeU] @@ -37,20 +36,18 @@ You can also follow these steps by watching this video on the SharePoint PnP You cd teams-tab ``` -1. Create a new solution by running the Yeoman SharePoint Framework Generator: +1. Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: ```console yo @microsoft/sharepoint ``` -1. When prompted, enter the following values (*select the default option for all prompts omitted below*): + The Yeoman SharePoint Generator will prompt you with a series of questions. For all questions, accept the default options except for the following questions: - - **What is your solution name?**: teams-tab - **Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites?**: Yes - **Which type of client-side component to create?**: WebPart - **What is your Web part name?**: MyFirstTeamsTab - **What is your Web part description?**: My first Teams tab - - **Which framework would you like to use?**: No JavaScript web framework At this point, Yeoman installs the required dependencies and scaffolds the solution files. Creation of the solution might take a few minutes. Yeoman scaffolds the project to include your **MyFirstTeamsTab** web part as well. diff --git a/docs/spfx/web-parts/guidance/build-client-side-web-parts-with-angular-1-x.md b/docs/spfx/web-parts/guidance/build-client-side-web-parts-with-angular-1-x.md index f8b292f37..4f73b1ba1 100644 --- a/docs/spfx/web-parts/guidance/build-client-side-web-parts-with-angular-1-x.md +++ b/docs/spfx/web-parts/guidance/build-client-side-web-parts-with-angular-1-x.md @@ -2,8 +2,7 @@ title: Tutorial - Build SharePoint Framework client-side web parts with AngularJS description: Use AngularJS to build a client-side web part to manage To Do items and style it using Office UI Fabric. ms.date: 05/18/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Build SharePoint Framework client-side web parts with AngularJS diff --git a/docs/spfx/web-parts/guidance/build-custom-property-pane-controls.md b/docs/spfx/web-parts/guidance/build-custom-property-pane-controls.md index c314dc53e..5fc45f8d6 100644 --- a/docs/spfx/web-parts/guidance/build-custom-property-pane-controls.md +++ b/docs/spfx/web-parts/guidance/build-custom-property-pane-controls.md @@ -1,9 +1,8 @@ --- title: Build custom controls for the property pane description: Build a custom dropdown control that loads its data asynchronously from an external service without blocking the user interface of the SharePoint client-side web part. -ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 02/11/2022 +ms.localizationpriority: high --- # Build custom controls for the property pane @@ -40,15 +39,11 @@ The source of the working web part is available on GitHub at [sp-dev-fx-webparts 1. When prompted, enter the following values (*select the default option for all prompts omitted below*): - - **What is your solution name?** react-custompropertypanecontrol - - **Which baseline packages do you want to target for your component(s)?** SharePoint Online only (latest) - - **Where do you want to place the files?** Use the current folder - **Which type of client-side component to create?** WebPart - **What is your Web part name?** List items - - **What is your Web part description?** Shows list items from the selected list - - **Which framework would you like to use?** React + - **Which template would you like to use?** React -1. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer. +1. Open your project folder in your code editor. ## Define web part property for storing the selected list @@ -68,10 +63,11 @@ The web part you're building shows list items from the selected SharePoint list. } ``` -1. Open the **src/webparts/listItems/IListItemsWebPartProps.ts** file and replace its contents with the following +1. Open the **src/webparts/listItems/ListItemsWebPart.ts** file and update the `IListItemsWebPartProps` interface to the following: ```typescript export interface IListItemsWebPartProps { + description: string; listName: string; } ``` @@ -83,9 +79,17 @@ The web part you're building shows list items from the selected SharePoint list. // ... public render(): void { - const element: React.ReactElement = React.createElement(ListItems, { - listName: this.properties.listName - }); + const element: React.ReactElement = React.createElement( + ListItems, + { + listName: this.properties.listName, + description: this.properties.description, + isDarkTheme: this._isDarkTheme, + environmentMessage: this._environmentMessage, + hasTeamsContext: !!this.context.sdks.microsoftTeams, + userDisplayName: this.context.pageContext.user.displayName + } + ); ReactDom.render(element, this.domElement); } @@ -127,61 +131,71 @@ The web part you're building shows list items from the selected SharePoint list. } ``` -1. In the **src/webparts/listItems/loc/mystrings.d.ts** file, change the `IListItemsWebPartStrings` interface to: +1. In the **src/webparts/listItems/loc/mystrings.d.ts** file, add a new property `ListFieldLabel` of type `string` to the existing `IListItemsWebPartStrings` interface: ```typescript declare interface IListItemsWebPartStrings { PropertyPaneDescription: string; BasicGroupName: string; + .. ListFieldLabel: string; } ``` -1. In the **src/webparts/listItems/loc/en-us.js** file, add the missing definition for the `ListFieldLabel` string. +1. In the **src/webparts/listItems/loc/en-us.js** file, add a new property `ListFieldLabel` to the returned object: ```javascript define([], function() { return { "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", + ... "ListFieldLabel": "List" } }); ``` +1. Open the **src/webparts/listItems/components/IListItemsProps.ts** file, add the `listName` property to the list interface: + + ```typescript + export interface IListItemsProps { + description: string; + isDarkTheme: boolean; + environmentMessage: string; + hasTeamsContext: boolean; + userDisplayName: string; + listName: string; + } + ``` + 1. In the **src/webparts/listItems/components/ListItems.tsx** file, change the contents of the `render()` method to: - ```tsx + ```typescript export default class ListItems extends React.Component { public render(): React.ReactElement { + const { + description, + isDarkTheme, + environmentMessage, + hasTeamsContext, + userDisplayName, + listName + } = this.props; + return ( -
    -
    -
    -
    - Welcome to SharePoint! -

    Customize SharePoint experiences using web parts.

    -

    {escape(this.props.listName)}

    - - Learn more - -
    -
    +
    +
    + +

    Well done, {escape(userDisplayName)}!

    +
    {environmentMessage}
    +
    List name: {escape(listName)}
    -
    + ); } } ``` -1. Open the **src/webparts/listItems/components/IListItemsProps.ts** file, and replace its contents with: - - ```typescript - export interface IListItemsProps { - listName: string; - } - ``` - 1. Run the following command to verify that the project is running: ```console @@ -227,7 +241,7 @@ When creating a custom property pane control that uses React in the SharePoint F - The `selectedKey` property specifies the selected value, which can be a string or a number. - The `disabled` property specifies if the dropdown control is disabled or not. - The `stateKey` property is used to force the React component to re-render. - + 1. Define asynchronous dropdown React component interface. In the **src/controls/PropertyPaneAsyncDropdown/components** folder, create a new file named **IAsyncDropdownState.ts**, and enter the following code: ```typescript @@ -247,7 +261,7 @@ When creating a custom property pane control that uses React in the SharePoint F 1. Define the asynchronous dropdown React component. In the **src/controls/PropertyPaneAsyncDropdown/components** folder, create a new file named **AsyncDropdown.tsx**, and enter the following code: - ```tsx + ```typescript import * as React from 'react'; import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown'; import { Spinner } from 'office-ui-fabric-react/lib/components/Spinner'; @@ -499,43 +513,34 @@ export interface IListInfo { import { update, get } from '@microsoft/sp-lodash-subset'; ``` -1. Add method to load available lists. In the `ListItemsWebPart` class, add a method to load available lists. In this article, you use mock data, but you could also call the SharePoint REST API to retrieve the list of available lists from the current web. To simulate loading options from an external service, the method uses a two-second delay. +1. Add a method to load available lists. In the `ListItemsWebPart` class, add the following `loadLists()` method to load available lists. In this article, you use mock data, but you could also call the SharePoint REST API to retrieve the list of available lists from the current web. To simulate loading options from an external service, the method uses a two-second delay. ```typescript - export default class ListItemsWebPart extends BaseClientSideWebPart { - // ... - - private loadLists(): Promise { - return new Promise((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => { - setTimeout(() => { - resolve([{ - key: 'sharedDocuments', - text: 'Shared Documents' - }, - { - key: 'myDocuments', - text: 'My Documents' - }]); - }, 2000); - }); - } - - // ... + private loadLists(): Promise { + return new Promise((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => { + setTimeout(() => { + resolve([{ + key: 'sharedDocuments', + text: 'Shared Documents' + }, + { + key: 'myDocuments', + text: 'My Documents' + }]); + }, 2000); + }); } ``` 1. Add method to handle the change of the value in the dropdown. In the `ListItemsWebPart` class, add a new method named `onListChange()`. ```typescript - export default class ListItemsWebPart extends BaseClientSideWebPart { - // ... - private onListChange(propertyPath: string, newValue: any): void { - const oldValue: any = get(this.properties, propertyPath); - // store new value in web part properties - update(this.properties, propertyPath, (): any => { return newValue; }); - // refresh web part - this.render(); - } + private onListChange(propertyPath: string, newValue: any): void { + const oldValue: any = get(this.properties, propertyPath); + // store new value in web part properties + update(this.properties, propertyPath, (): any => { return newValue; }); + // refresh web part + this.render(); } ``` @@ -600,6 +605,7 @@ When building SharePoint Framework web parts, you might need to implement a conf "preconfiguredEntries": [{ ... "properties": { + "description": "List items", "listName": "", "item": "" } @@ -607,25 +613,27 @@ When building SharePoint Framework web parts, you might need to implement a conf } ``` -1. Change the code in the **src/webparts/listItems/IListItemsWebPartProps.ts** file to: +1. Change the code in the **IListItemsWebPartProps** interface in the **src/webparts/listItems/ListItemsWebPart.ts** file to: ```typescript export interface IListItemsWebPartProps { + description: string; listName: string; item: string; } ``` -1. Change the contents of the **src/webparts/listItems/components/IListItemsProps.ts** file to: +1. Update the contents of the **src/webparts/listItems/components/IListItemsProps.ts** file to add the `item` property: ```typescript export interface IListItemsProps { + ... listName: string; - item: string; + itemName: string; } ``` -1. In the **src/webparts/listItems/ListItemsWebPart.ts** file, change the code of the `render()` method to: +1. In the **src/webparts/listItems/ListItemsWebPart.ts** file, change the code of the `render()` method to include the `item` property: ```typescript export default class ListItemsWebPart extends BaseClientSideWebPart { @@ -634,7 +642,8 @@ When building SharePoint Framework web parts, you might need to implement a conf public render(): void { const element: React.ReactElement = React.createElement(ListItems, { listName: this.properties.listName, - item: this.properties.item + itemName: this.properties.item, + ... }); ReactDom.render(element, this.domElement); @@ -644,10 +653,11 @@ When building SharePoint Framework web parts, you might need to implement a conf } ``` -1. In the **src/webparts/listItems/loc/mystrings.d.ts** file, change the `IListItemsWebPartStrings` interface to: +1. In the **src/webparts/listItems/loc/mystrings.d.ts** file, change the `IListItemsWebPartStrings` interface to include the `ItemFieldLabel` property: ```typescript declare interface IListItemsWebPartStrings { + ... PropertyPaneDescription: string; BasicGroupName: string; ListFieldLabel: string; @@ -660,6 +670,7 @@ When building SharePoint Framework web parts, you might need to implement a conf ```javascript define([], function() { return { + ... "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", "ListFieldLabel": "List", @@ -672,25 +683,29 @@ When building SharePoint Framework web parts, you might need to implement a conf In the **src/webparts/listItems/components/ListItems.tsx** file, change the `render()` method to: -```tsx +```typescript export default class ListItems extends React.Component { public render(): React.ReactElement { + const { + description, + isDarkTheme, + environmentMessage, + hasTeamsContext, + userDisplayName, + listName, + itemName + } = this.props; + return ( -
    -
    -
    -
    - Welcome to SharePoint! -

    Customize SharePoint experiences using web parts.

    -

    {escape(this.props.listName)}

    -

    {escape(this.props.item)}

    - - Learn more - -
    -
    +
    +
    + +

    Well done, {escape(userDisplayName)}!

    +
    {environmentMessage}
    +
    List name: {escape(listName)}
    +
    Item name: {escape(itemName)}
    -
    + ); } } @@ -701,46 +716,41 @@ export default class ListItems extends React.Component { In the **src/webparts/listItems/ListItemsWebPart.ts** file, in the `ListItemsWebPart` class, add a new method to load available list items from the selected list. Like the method for loading available lists, you use mock data. Depending on the previously selected list, the `loadItems()` method returns mock list items. When no list has been selected, the method resolves the promise without any data. ```typescript -export default class ListItemsWebPart extends BaseClientSideWebPart { - // ... - - private loadItems(): Promise { - if (!this.properties.listName) { - // resolve to empty options since no list has been selected - return Promise.resolve(); - } - - const wp: ListItemsWebPart = this; - - return new Promise((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => { - setTimeout(() => { - const items = { - sharedDocuments: [ - { - key: 'spfx_presentation.pptx', - text: 'SPFx for the masses' - }, - { - key: 'hello-world.spapp', - text: 'hello-world.spapp' - } - ], - myDocuments: [ - { - key: 'isaiah_cv.docx', - text: 'Isaiah CV' - }, - { - key: 'isaiah_expenses.xlsx', - text: 'Isaiah Expenses' - } - ] - }; - resolve(items[wp.properties.listName]); - }, 2000); - }); +private loadItems(): Promise { + if (!this.properties.listName) { + // resolve to empty options since no list has been selected + return Promise.resolve([]); } + const wp: ListItemsWebPart = this; + + return new Promise((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => { + setTimeout(() => { + const items = { + sharedDocuments: [ + { + key: 'spfx_presentation.pptx', + text: 'SPFx for the masses' + }, + { + key: 'hello-world.spapp', + text: 'hello-world.spapp' + } + ], + myDocuments: [ + { + key: 'isaiah_cv.docx', + text: 'Isaiah CV' + }, + { + key: 'isaiah_expenses.xlsx', + text: 'Isaiah Expenses' + } + ] + }; + resolve(items[wp.properties.listName]); + }, 2000); + }); } ``` @@ -749,15 +759,12 @@ export default class ListItemsWebPart extends BaseClientSideWebPart { - // ... - private onListItemChange(propertyPath: string, newValue: any): void { - const oldValue: any = get(this.properties, propertyPath); - // store new value in web part properties - update(this.properties, propertyPath, (): any => { return newValue; }); - // refresh web part - this.render(); - } +private onListItemChange(propertyPath: string, newValue: any): void { + const oldValue: any = get(this.properties, propertyPath); + // store new value in web part properties + update(this.properties, propertyPath, (): any => { return newValue; }); + // refresh web part + this.render(); } ``` @@ -826,28 +833,22 @@ Initially when no list is selected, the items dropdown is disabled and becomes e 1. To implement this logic, extend the previously defined `onListChange()` method to: ```typescript - export default class ListItemsWebPart extends BaseClientSideWebPart { - // ... - - private onListChange(propertyPath: string, newValue: any): void { - const oldValue: any = get(this.properties, propertyPath); - // store new value in web part properties - update(this.properties, propertyPath, (): any => { return newValue; }); - // reset selected item - this.properties.item = undefined; - // store new value in web part properties - update(this.properties, 'item', (): any => { return this.properties.item; }); - // refresh web part - this.render(); - // reset selected values in item dropdown - this.itemsDropDown.properties.selectedKey = this.properties.item; - // allow to load items - this.itemsDropDown.properties.disabled = false; - // load items and re-render items dropdown - this.itemsDropDown.render(); - } - - // ... + private onListChange(propertyPath: string, newValue: any): void { + const oldValue: any = get(this.properties, propertyPath); + // store new value in web part properties + update(this.properties, propertyPath, (): any => { return newValue; }); + // reset selected item + this.properties.item = undefined; + // store new value in web part properties + update(this.properties, 'item', (): any => { return this.properties.item; }); + // refresh web part + this.render(); + // reset selected values in item dropdown + this.itemsDropDown.properties.selectedKey = this.properties.item; + // allow to load items + this.itemsDropDown.properties.disabled = false; + // load items and re-render items dropdown + this.itemsDropDown.render(); } ``` @@ -879,7 +880,7 @@ Initially when no list is selected, the items dropdown is disabled and becomes e ![Selected list and item rendered in the web part](../../../images/custom-property-pane-control-cascading-selected-list-item.png) -1. Stop the local webserver by pressing CTRL+C in the console. +1. Stop the local webserver by pressing CTRL+C in the console. ## See also diff --git a/docs/spfx/web-parts/guidance/connect-to-api-secured-with-aad.md b/docs/spfx/web-parts/guidance/connect-to-api-secured-with-aad.md deleted file mode 100644 index 5c8da8919..000000000 --- a/docs/spfx/web-parts/guidance/connect-to-api-secured-with-aad.md +++ /dev/null @@ -1,449 +0,0 @@ ---- -title: Connect to API secured with Azure Active Directory (Azure AD) -description: Guidance about connecting to APIs secured with Azure AD. -ms.date: 02/11/2020 -ms.prod: sharepoint -localization_priority: Priority ---- - -# Connect to API secured with Azure Active Directory - -When building SharePoint Framework solutions, you might need to connect to your custom API to retrieve some data or to communicate with line-of-business applications. Securing custom APIs with Microsoft Azure Active Directory (Azure AD) offers you many benefits and can be done in a number of ways. After you have built the API, there are several ways in which you can access it. These ways vary in complexity and each have their specific considerations. - -This article discusses the different approaches and describes the step-by-step process of securing and connecting to an API secured with Azure AD. - -> [!IMPORTANT] -> When connecting to Azure AD-secured APIs, we recommend that you use the **MSGraphClient** and **AadHttpClient** classes, which are now generally available. For more information about the recommended models, see [Connect to Azure AD-secured APIs in SharePoint Framework solutions](../../use-aadhttpclient.md) and [Use the MSGraphClient to connect to Microsoft Graph](../../use-msgraph.md). - -## Secure an API with Azure AD - -If you're using Office 365, securing custom APIs using Azure AD is an architectural option that you should definitely consider. First and foremost, it allows you to secure the access to the API using existing organizational credentials that are already managed through Office 365 and Azure AD. Users with an active account can seamlessly work with applications that leverage APIs secured with Azure AD. Azure AD administrators can centrally manage access to the API, the same way they manage access to all other applications registered with Azure AD. - -As the API developer, using Azure AD to secure your API frees you from managing a proprietary set of user credentials and implementing a custom security layer for your API. Additionally, Azure AD supports the OAuth protocol, which allows you to connect to the API from a range of application types varying from mobile apps to client-side solutions. - -When building custom APIs, there are two main ways in which you can secure your API with Azure AD. If you host the API in Microsoft Azure App Service, you can benefit from the App Service Authentication option. If you look for more hosting flexibility for your API, such as hosting it on your own infrastructure or in Docker containers, you need to secure it in code. In such cases, the implementation depends on your programming language and framework. - -In this article, when discussing this option, you'll use C# and the [ASP.NET Web API](https://www.asp.net/web-api) as the framework. - -### Secure the API using Azure App Service Authentication - -When deploying custom APIs to Azure App Service, you can benefit from the App Service Authentication option to secure the API with Azure AD. The biggest benefit of using App Service Authentication is its simplicity: by following the configuration steps available in the [Azure portal](https://ms.portal.azure.com/), you can have the wizard set up the authentication configuration for you. If you choose the basic setup, the wizard creates a new Azure AD application in Azure AD associated with the current subscription. In the advanced configuration, you can choose which Azure AD application should be used to secure the access to the App Service hosting the API. - -![App Service Authentication settings displayed in the Azure portal](../../../images/api-aad-azure-app-service-authentication.png) - -After App Service Authentication has been configured, users trying to access your API are prompted to sign in with their organizational account that belongs to the same Azure AD as the Azure AD application used to secure the API. After signing in, you're able to access the information about the current user through the `HttpContext.Current.User` property. When using Azure App Service Authentication, there's no additional configuration required in your application. - -Azure App Service Authentication is a feature available only in Azure App Service. While this capability significantly simplifies implementing authentication in your API, it ties it to running inside Azure App Service. If you want to host the API with another cloud provider or inside a Docker container, you need to implement the authentication layer first. - -### Secure the API using ASP.NET authentication - -If you want to have the maximum flexibility with regards to where your API is hosted and how its deployed, you should consider implementing the support for Azure AD authentication in ASP.NET. Visual Studio simplifies the implementation process significantly, and after completing the authentication setup wizard, your API requires users to sign in by using their organizational account. - -![Visual Studio authentication setup wizard](../../../images/api-aad-visual-studio-authentication-wizard.png) - -During the configuration process, Visual Studio adds all the necessary references and settings to your ASP.NET Web API project, including registering a new Azure AD application to secure your API. - -## Access an API secured with Azure AD from SharePoint Framework solutions - -SharePoint Framework solutions are fully client-side and as such are incapable of securely storing secrets required to connect to secured APIs. To support secure communication with client-side solutions, Azure AD supports a number of mechanisms such as authentication cookies or the OAuth implicit flow. - -Typically, when building SharePoint Framework solutions, you would use the [MSGraphClient](../../use-msgraph.md) to connect to the Microsoft Graph and the [AadHttpClient](../../use-aadhttpclient.md) to connect to an enterprise API secured with Azure AD. If you however work with a JavaScript framework that has its own service for executing web requests, such as AngularJS or jQuery or your solution is built on an older version of the SharePoint Framework, you might need to use other approaches to obtain an access token to APIs secured with Azure AD. - -### Azure AD authorization flows - -Office 365 uses Azure Active Directory (Azure AD) to secure its APIs, which are accessed through Microsoft Graph. Azure AD uses OAuth as the authorization protocol. When an application completes the OAuth authorization flow, it gets a temporary access token. The token provides access to specific resources on behalf of the user by using permissions granted to the application by that user. - -There are different types of OAuth flows depending on the kind of application. Web applications use an OAuth flow where Azure AD redirects to the URL where the application is hosted. The redirect is an additional security measure to verify the authenticity of that application. - -Client applications, such as Android and iOS apps, don't have a URL and can't use a redirect. So they complete the OAuth flow without the redirect. Both web applications and client applications use a publicly known client ID and a privately held client secret known only to Azure AD and the application. - -Client-side web applications are similar to web applications but are implemented using JavaScript and run in the context of a browser. These applications are incapable of using a client secret without revealing it to users. Therefore these applications use an authorization flow named **OAuth implicit flow** to access resources secured with Azure AD. In this flow, the contract between the application and Azure AD is established based on the publicly known client ID and the URL where the application is hosted. This is the flow that SharePoint Framework client-side web parts must use in order to connect to resources secured with Azure AD. - -### Use the AadTokenProvider to retrieve access token - -When working with JavaScript libraries that have their own services for executing web requests, the recommended way to obtain an access token to an API secured with Azure AD is by using the **AadTokenProvider** available from SharePoint Framework v1.6.0. Compared to other solutions, the AadTokenProvider takes away all intricacies of implementing OAuth implicit flow in SharePoint Framework solutions, allowing you to focus on building your application. - -> [!NOTE] -> It's recommended to regularly update your SharePoint Framework solutions to the most recent version of the SharePoint Framework to benefit of the improvements and new capabilities added by Microsoft. - -#### Request permissions to API secured with Azure AD - -If your SharePoint Framework solution requires permissions to specific resources secured with Azure AD, such as enterprise API, you should specify these resources along with the necessary permissions in the configuration of your solution. - -1. In your SharePoint Framework project, open the **config/package-solution.json** file. - -2. To the **solution** property, add the **webApiPermissionRequests** property that lists all the resources and corresponding permissions that your solution needs. - - Following is an example of a SharePoint Framework solution requesting access to enterprise API: - - ```json - { - "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", - "solution": { - "name": "spfx-client-side-solution", - "id": "5d16587c-5e87-44d7-b658-1148988f212a", - "version": "1.0.0.0", - "includeClientSideAssets": true, - "skipFeatureDeployment": true, - "webApiPermissionRequests": [ - { - "resource": "Enterprise-API-Name", - "scope": "user_impersonation" - } - ] - }, - "paths": { - "zippedPackage": "solution/spfx-api.sppkg" - } - } - ``` - - > [!NOTE] - > For the value of the **resource** property, you can specify either the **displayName** or the **objectId** of the application to which you want to request permissions. Using the displayName not only is more readable but also allows you to build your solution once and reuse it across multiple tenants. While the objectId of an Azure AD application is different on each tenant, the displayName stays the same. - -3. When this solution is deployed to the SharePoint App Catalog, it prompts the administrator to verify the requested permissions and either grant or deny them. Read [Manage permission requests](../../use-aadhttpclient.md#manage-permission-requests) article to learn more about different ways of managing permission requests. - -#### Acquire an access token - -Following is how you would use the AadTokenProvider to retrieve an access token for an enterprise API secured with Azure AD and use it to do a web request using jQuery: - -```typescript -// ... -import * as $ from 'jquery'; -import { AadTokenProvider } from '@microsoft/sp-http'; - -export default class OrdersWebPart extends BaseClientSideWebPart { - // ... - - public render(): void { - this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'orders'); - - this.context.aadTokenProviderFactory - .getTokenProvider() - .then((tokenProvider: AadTokenProvider): Promise => { - // retrieve access token for the enterprise API secured with Azure AD - // the parameter passed into getToken()is the Application ID URI - return tokenProvider.getToken('https://contoso.azurewebsites.net'); - }) - .then((accessToken: string): void => { - // call the enterprise API using jQuery passing the access token - $.get({ - url: 'https://contoso.azurewebsites.net/api/Orders', - headers: { - authorization: `Bearer ${accessToken}`, - accept: 'application/json' - } - }) - .done((orders: any): void => { - this.context.statusRenderer.clearLoadingIndicator(this.domElement); - this.domElement.innerHTML = ` -
    -
    -
    -
    - Orders -

    -

      - ${orders.map(o => `
    • ${o.Rep} $${o.Total}
    • `).join('')} -
    -

    - - Learn more - -
    -
    -
    -
    `; - }); - }); - } - - // ... -} -``` - -You start, by retrieving an instance of the `AadTokenProvider` using the `aadTokenProviderFactory`. Next, you use the `AadTokenProvider` to retrieve the access token for your API secured with Azure AD. Once you've obtained the access token, you execute the AJAX request to the enterprise API including the access token in the request headers. - -### Use ADAL JS to handle authorization and retrieve access token - -If you're using an older version of the SharePoint Framework that v1.6.0 and can't use the `AadTokenProvider`, you can use the [ADAL JS](https://github.com/AzureAD/azure-activedirectory-library-for-js) library to handle the OAuth implicit flow and retrieve the access token for the specific API secured with Azure AD. For applications built using AngularJS, ADAL JS offers an HTTP request interceptor that automatically adds required access tokens to headers of outgoing web requests. By using this requestor, developers don't need to modify web requests to APIs secured with Azure AD and can focus on building the application instead. - -#### Limitations when using ADAL JS with client-side web parts - -The ADAL JS library significantly simplifies implementing the OAuth flow for Azure AD in client-side web applications. But it has a number of limitations when used with SharePoint Framework client-side web parts. These limitations are due to the fact that ADAL JS is designed to be used by client-side web applications that own the whole page and don't share the page with other applications. - -##### Shared storage - -Depending on how you configured the ADAL JS library in your project, it stores its data either in the browser's local storage or in the session storage. Either way, the information stored by ADAL JS is accessible to any component on the same page. For example, if one web part retrieves an access token for Microsoft Graph, any other web part on the same page can reuse that token and call Microsoft Graph. - -##### ADAL JS as a singleton - -ADAL JS is designed to work as a singleton service registered in the global scope of the page. When processing OAuth flow callbacks in IFrames, ADAL JS code uses the registered singleton reference from the main window to resolve the token flow. Because each web part is registered with a different Azure AD application, reusing the same instance of ADAL JS leads to undesirable results where every web part uses the same configuration as the one registered by the first web part loaded on the page. - -##### Resource-based storage - -By default, the ADAL JS library stores information such as the current access token or its expiration time in a set of keys associated with the particular resource, for example Microsoft Graph or SharePoint. If there are multiple components on one page accessing the same resource with different permissions, the first retrieved token is served by ADAL JS to all components. If different components require access to the same resource, they might fail. To illustrate this limitation, consider the following example. - -Imagine that there are two web parts on the page: one that lists upcoming meetings, and one that creates a new meeting. To get upcoming meetings, the upcoming meetings web part uses a Microsoft Graph access token with permissions to read users' calendars. The web part that creates new meetings, on the other hand, requires a Microsoft Graph access token with permissions to write to users' calendars. - -If the upcoming meetings web part loads first, ADAL JS retrieves its token with only the read permission. The same token is then served by ADAL JS to the web part creating new meetings. As you can see, when the web part attempts to create a new meeting, the web part fails with an access denied error. Because of the resource-based storage, ADAL JS wouldn't retrieve a new token for Microsoft Graph until the previously retrieved token expired. - -##### Processing authorization callbacks - -OAuth implicit flow is based on redirects between Azure AD and the application participating in the flow. When the authentication process starts, the application redirects you to the Azure AD sign-in page. After the authentication completes, Azure AD redirects you back to the application, and sends the identity token in the URL hash for the application to process. From the perspective of a web part placed on a SharePoint page, this behavior has two drawbacks. - -Even though you're signed in to SharePoint, you need to separately authenticate with Azure AD in order for your web part to can access resources secured with Azure AD. The web part is a small part of the overall page, but to complete the authentication process, you need to leave the whole page, which is a poor user experience. - -After the authentication completes, Azure AD redirects you back to your application. In the URL hash, it includes the identity token that your application needs to process. Unfortunately, because the identity token doesn't contain any information about its origin, if you had multiple web parts on one page, all of them would try to process the identity token from the URL. - -#### Considerations when using ADAL JS to communicate with APIs secured with Azure AD - -Aside the limitations, there are some considerations that you should take into account before implementing ADAL JS in your SharePoint Framework solution yourself. - -##### ADAL JS is meant to be used for single-page applications - -ADAL JS is designed to be used with single-page applications. As such, by default it doesn't work correctly when used with SharePoint Framework solutions. By applying a patch however, it can be successfully used in SharePoint Framework projects. - -##### Handle all possible authentication exceptions yourself - -When using ADAL JS and OAuth to access APIs secured with Azure AD, the authentication flow is facilitated by Azure. Any errors are handled by the Azure sign-in page. After the user has signed-in with their organizational account, the application tries to retrieve a valid access token. All errors that occur at this stage have to be explicitly handled by the developer of the application because retrieving access tokens is non-interactive and doesn't present any UI to the user. - -##### Register every client-side application in Azure AD - -Every client-side application that wants to use ADAL JS needs to be registered as an Azure AD application. A part of the registration information is the URL where the application is located. Because the application is fully client-side and isn't capable of securely storing a secret, the URL is a part of the contract between the application and Azure AD to establish security. This requirement is problematic for SharePoint Framework solutions because developers can't simply know upfront all URLs where a particular web part will be used. Additionally, at this moment, Azure AD supports specifying up to 10 reply URLs, which might not be sufficient in some scenarios. - -##### Implement authorization flow in each web part - -Before a client-side application can retrieve an access token to a specific resource, it needs to authenticate the user to obtain the ID token, which can then be exchanged for an access token. Even though SharePoint Framework solutions are hosted in SharePoint, where users are already signed in using their organizational accounts, the authentication information for the current user isn't available to SharePoint Framework solutions. Instead, each solution must explicitly request the user to sign in. This can be done either by redirecting the user to the Azure sign-in page or by showing a pop-up window with the sign-in page. The latter is less intrusive in the case of a web part, which is one of the many elements on a page. If there are multiple SharePoint Framework client-side web parts on the page, each of them manages its state separately and requires the user to explicitly sign in to that particular web part. - -##### Configure Internet Explorer security zones - -Retrieving access tokens required to communicate with APIs secured with Azure AD is facilitated by hidden IFRAMEs that handle redirects to Azure AD endpoints. There is a known limitation in Microsoft Internet Explorer were obtaining access tokens in OAuth implicit flow fails, if the Azure AD sign-in endpoints and the SharePoint Online URL are not in the same security zone. If your organization is using Internet Explorer, ensure that the Azure AD endpoint and SharePoint Online URLs are configured in the same security zone. To maintain consistency, some organizations choose to push these settings to end-users using group policies. - -##### Add access token to all AJAX requests to APIs secured with Azure AD - -APIs secured with Azure AD can't be accessed anonymously. Instead they require a valid credential to be presented by the application calling them. When using the OAuth implicit flow with client-side applications, this credential is the bearer access token obtained using ADAL JS. If you have built your SharePoint Framework solution using AngularJS, ADAL JS automatically ensures that you have a valid access token for the particular resource, and adds it to all outgoing requests executed by using the AngularJS `$http` service. When using other JavaScript libraries, you have to obtain a valid access token, and if necessary refresh it, and attach it to the outgoing web requests yourself. - -#### Use ADAL JS with client-side web parts - -You can overcome the limitations in ADAL JS to implement OAuth successfully in your SharePoint Framework client-side web part. - -> [!IMPORTANT] -> The following guidance is based on ADAL JS v1.0.12. When adding ADAL JS to your SharePoint Framework projects, ensure that you're installing ADAL JS v1.0.12, or the guidance mentioned in this article will not work as expected. - -##### Load ADAL JS in your web part - -Web parts are built using TypeScript and distributed as AMD modules. Their modular architecture allows you to isolate the different resources used by the web part. ADAL JS is designed to register itself in the global scope, but you can load it in a web part by using the following code: - -```typescript -import * as AuthenticationContext from 'adal-angular'; -``` - -This statement imports the `AuthenticationContext` class that exposes the ADAL JS functionality for use in web parts. Despite the name of the module, the `AuthenticationContext` class works with every JavaScript library. - -##### Make ADAL JS suitable for use with SharePoint Framework web parts - -The current ADAL JS functionality is unsuitable for use in web parts. Use the following patch to make ADAL JS work in your web part. - -**WebPartAuthenticationContext.js** - -```javascript -const AuthenticationContext = require('adal-angular'); - -AuthenticationContext.prototype._getItemSuper = AuthenticationContext.prototype._getItem; -AuthenticationContext.prototype._saveItemSuper = AuthenticationContext.prototype._saveItem; -AuthenticationContext.prototype.handleWindowCallbackSuper = AuthenticationContext.prototype.handleWindowCallback; -AuthenticationContext.prototype._renewTokenSuper = AuthenticationContext.prototype._renewToken; -AuthenticationContext.prototype.getRequestInfoSuper = AuthenticationContext.prototype.getRequestInfo; -AuthenticationContext.prototype._addAdalFrameSuper = AuthenticationContext.prototype._addAdalFrame; - -AuthenticationContext.prototype._getItem = function (key) { - if (this.config.webPartId) { - key = this.config.webPartId + '_' + key; - } - - return this._getItemSuper(key); -}; - -AuthenticationContext.prototype._saveItem = function (key, object) { - if (this.config.webPartId) { - key = this.config.webPartId + '_' + key; - } - - return this._saveItemSuper(key, object); -}; - -AuthenticationContext.prototype.handleWindowCallback = function (hash) { - if (hash == null) { - hash = window.location.hash; - } - - if (!this.isCallback(hash)) { - return; - } - - var requestInfo = this.getRequestInfo(hash); - if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) { - return this.handleWindowCallbackSuper(hash); - } - - var resource = this._getResourceFromState(requestInfo.stateResponse); - if (!resource || resource.length === 0) { - return; - } - - if (this._getItem(this.CONSTANTS.STORAGE.RENEW_STATUS + resource) === this.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS) { - return this.handleWindowCallbackSuper(hash); - } -} - -AuthenticationContext.prototype._renewToken = function (resource, callback) { - this._renewTokenSuper(resource, callback); - var _renewStates = this._getItem('renewStates'); - if (_renewStates) { - _renewStates = _renewStates.split(','); - } - else { - _renewStates = []; - } - _renewStates.push(this.config.state); - this._saveItem('renewStates', _renewStates); -} - -AuthenticationContext.prototype.getRequestInfo = function (hash) { - var requestInfo = this.getRequestInfoSuper(hash); - var _renewStates = this._getItem('renewStates'); - if (!_renewStates) { - return requestInfo; - } - - _renewStates = _renewStates.split(';'); - for (var i = 0; i < _renewStates.length; i++) { - if (_renewStates[i] === requestInfo.stateResponse) { - requestInfo.requestType = this.REQUEST_TYPE.RENEW_TOKEN; - requestInfo.stateMatch = true; - break; - } - } - - return requestInfo; -} - -AuthenticationContext.prototype._addAdalFrame = function (iframeId) { - var adalFrame = this._addAdalFrameSuper(iframeId); - adalFrame.style.width = adalFrame.style.height = '106px'; - return adalFrame; -} - -window.AuthenticationContext = function() { - return undefined; -} -``` - -The patch applies the following changes to ADAL JS: - -- All information is stored in a key specific to the web part (see the override of the `_getItem` and `_saveItem` functions). -- Callbacks are processed only by web parts that initiated them (see the override of the `handleWindowCallback` function). -- When verifying data from callbacks, the instance of the `AuthenticationContext` class of the specific web part is used instead of the globally registered singleton (see `_renewToken`, `getRequestInfo`, and the empty registration of the `window.AuthenticationContext` function). - -##### Use the ADAL JS patch in SharePoint Framework web parts - -For ADAL JS to work correctly in SharePoint Framework web parts, you have to configure it in a specific way. - -1. Define a custom interface that extends the standard ADAL JS `Config` interface to expose additional properties on the configuration object. - - ```typescript - export interface IAdalConfig extends adal.Config { - popUp?: boolean; - callback?: (error: any, token: string) => void; - webPartId?: string; - } - ``` - - The `popUp` property and the `callback` function are both already implemented in ADAL JS but aren't exposed in the TypeScript typings of the standard `Config` interface. You need them in order to allow users to sign in to your web parts by using a pop-up window instead of redirecting them to the Azure AD sign-in page. - -1. Load the ADAL JS patch, the custom configuration interface, and your configuration object into the main component of your web part. - - ```typescript - import * as AuthenticationContext from 'adal-angular'; - import adalConfig from '../AdalConfig'; - import { IAdalConfig } from '../../IAdalConfig'; - import '../../WebPartAuthenticationContext'; - ``` - -1. In the constructor of your component, extend the ADAL JS configuration with additional properties and use it to create a new instance of the `AuthenticationContext` class. - - ```typescript - export default class UpcomingMeetings extends React.Component { - private authCtx: adal.AuthenticationContext; - - constructor(props: IUpcomingMeetingsProps, state: IUpcomingMeetingsState) { - super(props); - - this.state = { - loading: false, - error: null, - upcomingMeetings: [], - signedIn: false - }; - - const config: IAdalConfig = adalConfig; - config.webPartId = this.props.webPartId; - config.popUp = true; - config.callback = (error: any, token: string): void => { - this.setState((previousState: IUpcomingMeetingsState, currentProps: IUpcomingMeetingsProps): IUpcomingMeetingsState => { - previousState.error = error; - previousState.signedIn = !(!this.authCtx.getCachedUser()); - return previousState; - }); - }; - - this.authCtx = new AuthenticationContext(config); - AuthenticationContext.prototype._singletonInstance = undefined; - } - } - ``` - -The code first retrieves the standard ADAL JS configuration object and casts it to the type of the newly defined configuration interface. - -It then passes the ID of the web part instance so that all ADAL JS values can be stored in a way that they won't collide with other web parts on the page. - -Next, it enables the pop-up-based authentication and defines a callback function that runs when authentication completes to update the component. - -Finally, it creates a new instance of the `AuthenticationContext` class and resets the `_singletonInstance` set in the constructor of the `AuthenticationContext` class. This is required in order to allow every web part to use its own version of the ADAL JS authentication context. - -## Considerations when using OAuth implicit flow in client-side web parts - -Before you build SharePoint Framework client-side web parts that communicate with resources secured by Azure AD, there are some constraints that you should consider. The following information helps you determine when OAuth authorization in web parts is the right choice for your solution and organization. - -### SharePoint Framework web parts are highly trusted - -Unlike SharePoint Add-ins, web parts run with the same permissions as the current user. Whatever the user can do, the web part can do as well. This is why web parts can be installed and deployed only by tenant administrators. The tenant administrator should verify that web parts they're deploying come from a trusted source and were approved for use in the tenant. - -Web parts are a part of the page and, unlike SharePoint Add-ins, share DOM and resources with other elements on the page. Access tokens that grant access to resources secured with Azure AD, are retrieved through a callback to the same page where the web part is located. That callback can be processed by any element on the page. Also, after access tokens are processed from callbacks, they're stored in the browser's local storage or session storage from where they can be retrieved by any component on the page. A malicious web part could read the token and either expose the token or the data it retrieved using that token to an external service. - -### URL is a part of the OAuth implicit flow contract - -> [!IMPORTANT] -> Information in this section doesn't apply to you if you use the `AadTokenProvider` as it handles the OAuth implicit flow for you - -Client-side applications are incapable of storing a client secret without revealing it to users. To verify the authenticity of the particular application, the URL where the application is hosted is used as a part of the trust contract between Azure AD and the application. The consequences of this are that the URL of every page with web parts using OAuth implicit flow must be registered with Azure AD. If a page isn't registered, the OAuth flow fails, and the web part is denied access to the secured resource. - -This necessary security measure is a significant limitation for organizations that allow users to add web parts to pages. We recommend that you limit the number of locations where web parts using OAuth implicit flow are used. Use a few well-known locations such as the home page or specific landing pages, and have these locations registered with Azure AD. - -### Internet Explorer security zones - -Internet Explorer uses security zones to apply security policies to websites you visit. Websites assigned to different security zones run isolated and can't cooperate. When using OAuth implicit flow in SharePoint Framework client-side web parts, the page with web parts that use OAuth and the Azure AD sign-in page (located at https://login.microsoftonline.com) must be in the same security zone. Without such configuration, the authentication process fails, and web parts won't be able to communicate with Azure AD-secured resources. - -### User must sign in regularly - -When using regular OAuth flow, web applications and client applications get a short-lived access token (60 minutes by default) and a refresh token that is valid for a longer period of time. When the access token expires, the refresh token is used to get a new access token. This approach reduces how often users need to sign in to Azure AD. - -Because client-side applications are incapable of securely storing secrets, and disclosing a refresh token is a serious security threat, they only receive the access token as part of the OAuth implicit flow. After that token expires, the application must start a new OAuth flow, which could require the user to sign in again. - -## See also - -- [Connect to Azure AD-secured APIs in SharePoint Framework solutions](../../use-aadhttpclient.md) -- [Use the MSGraphClient to connect to Microsoft Graph](../../use-msgraph.md) -- [Call custom APIs secured with Azure Active Directory without ADAL JS (code sample)](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/aad-api-spo-cookie) -- [Authentication scenarios for Azure AD](/azure/active-directory/develop/active-directory-authentication-scenarios) diff --git a/docs/spfx/web-parts/guidance/connect-to-sharepoint-using-jsom.md b/docs/spfx/web-parts/guidance/connect-to-sharepoint-using-jsom.md index a236ba0e1..c41336b0d 100644 --- a/docs/spfx/web-parts/guidance/connect-to-sharepoint-using-jsom.md +++ b/docs/spfx/web-parts/guidance/connect-to-sharepoint-using-jsom.md @@ -1,13 +1,16 @@ --- title: Connect to SharePoint using the JavaScript Object Model (JSOM) description: How to use SharePoint JSOM when building solutions on the SharePoint Framework. -ms.date: 06/29/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 19/12/2022 +ms.localizationpriority: high --- # Connect to SharePoint using the JavaScript Object Model (JSOM) +> [!IMPORTANT] +> JSOM is considered as a legacy option to operate the data in the SharePoint Online. You should be looking into using the SharePoint REST API or Microsoft Graph APIs either directly or through the [Microsoft Graph SDKs](https://learn.microsoft.com/en-us/graph/sdks/sdk-installation) or with the [PnPjs JavaScript Library](https://github.com/pnp/pnpjs). + + When building SharePoint customizations, you might have used the SharePoint [JavaScript Object Model (JSOM)](../../../sp-add-ins/complete-basic-operations-using-javascript-library-code-in-sharepoint.md) to communicate with SharePoint. This is no longer the recommended path (see [Considerations](#considerations) later in this article). However, there are still valid use cases for using the JSOM API such as code migration. To use SharePoint JSOM in your SharePoint Framework component, you must include it in your project. This wasn't previously required because it was already available on SharePoint pages for you to use. In the SharePoint Framework, you must explicitly load it into your component. @@ -42,11 +45,9 @@ Each of these approaches has advantages and disadvantages, and it's important fo 1. When prompted, enter the following values (*select the default option for all prompts omitted below*): - **What is your solution name?**: react-sharepointlists - - **Which baseline packages do you want to target for your component(s)?**: SharePoint Online only (latest) - **Which type of client-side component to create?**: WebPart - **What is your Web part name?**: SharePoint lists - - **What is your Web part description?**: Shows names of lists in the current site - - **Which framework would you like to use?**: React + - **Which template would you like to use?**: React 1. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor you prefer. diff --git a/docs/spfx/web-parts/guidance/getting-started-with-top-actions.md b/docs/spfx/web-parts/guidance/getting-started-with-top-actions.md new file mode 100644 index 000000000..5473106ec --- /dev/null +++ b/docs/spfx/web-parts/guidance/getting-started-with-top-actions.md @@ -0,0 +1,183 @@ +--- +title: Adding support for web part Top Actions +description: Top Actions is a SharePoint Framework feature that allows web part developers to add commands to a web part's toolbar. +ms.date: 04/12/2023 +ms.localizationpriority: high +--- +# Adding support for web part Top Actions + +Top Actions provide an alternative and more end user friendlier way to expose the different options and configuration capabilities for web parts in edit mode. You can use Top Actions to surface most common configurations from the web part property panel directly in web part toolbar, which is exposed when the page is in edit mode. + +![Top Actions Example](../../../images/webpart-top-actions.png) + +> [!IMPORTANT] +> Web part Top Actions were introduced in the [SharePoint Framework (SPFx) v1.17 release](../../release-1.17.md). + +## Getting started + +To add Top Actions to a web part, you'll implement two things: + +- return a collection of Top Actions to display at the top of the web part when the page is in edit mode +- implement a handler that's called by SPFx when the Top Action is selected + +Both of these steps are accomplished by providing a configuration object of type [ITopActions](/javascript/api/sp-top-actions/itopactions) to the SPFx. + +> [!TIP] +> These instructions assume you know [how to create a hello world web part](../get-started/build-a-hello-world-web-part.md). + +## Define a Top Action configuration + +Adding Top Actions to a web part follows a similar pattern to configuring the web part property pane. + +To add Top Actions to a web part, implement the `getTopActionsConfiguration()` member that returns an object of type ITopActions: + +```typescript +// existing imports omitted for brevity +import { + ITopActions, + ITopActionsField +} from '@microsoft/sp-top-actions'; + +export default class HelloWorldWebPart extends BaseClientSideWebPart { + + // existing web part members omitted for brevity + + public getTopActionsConfiguration(): ITopActions | undefined { + return { + topActions: [], + onExecute: (actionName: string, newValue: any): void { } + }; + } + +} +``` + +Notice the returned object has two properties: + +- `topActions`: this contains an array of supported Top Action controls that are rendered in the web part's toolbar when the page is in edit mode +- `onExecute`: this handler is called when one of the Top Actions is selected + +## Define the Top Actions user interface + +The `topActions` array is an ordered list of controls, or *fields* of type [ITopActionsField](/javascript/api/sp-top-actions/itopactionsfield), to render in the web part toolbar. You can choose from two types of user interface elements: + +- button +- dropdown list + +All controls must have the following properties defined: + +- `type`: this is the type of the control - *button* (`TopActionsFieldType.Button`) or *dropdown list* (`TopActionsFieldType.Dropdown) +- `targetProperty`: this is the name of the Top Action +- `properties`: properties unique to the type of Top Action control + +You can optionally specify a `title` which is used as the tooltip & value for an `aria-label` property, and the Boolean `shouldFocus` flag to indicate if the control should be focused. + +## Define the Top Actions button field + +The following code defines a button Top Action control: + +```typescript +import { + ITopActions, + TopActionsFieldType +} from '@microsoft/sp-top-actions'; + +return { + topActions: [ + { + targetProperty: 'button', + type: TopActionsFieldType.Button, + title: 'Button', + properties: { + text: 'Button', + icon: 'SharePointLogo' + } + } + ], + onExecute: (actionName: string, newValue: any): void { } +} +``` + +The `properties` for a button control are defined in the [ITopActionsButtonProps](/javascript/api/sp-top-actions/itopactionsbuttonprops) interface. + +## Define the Top Actions dropdown field + +The following code defines a dropdown Top Action control: + +```typescript +import { + ITopActions, + TopActionsFieldType +} from '@microsoft/sp-top-actions'; + +return { + topActions: [ + { + targetProperty: 'dropdown', + type: TopActionsFieldType.Dropdown, + title: 'Dropdown', + properties: { + options: [{ + key: '1', + text: 'Option 1' + }, { + key: '2', + text: 'Option 2' + }] + } + } + ], + onExecute: (actionName: string, newValue: any): void { } +} +``` + +The `properties` for a dropdown control are defined in the [ITopActionsButtonProps](/javascript/api/sp-top-actions/itopactionsdropdownoption) interface. + +## Define the handler when controls are selected + +The last step is to implement the handler when Top Action controls are selected. This is done by implementing the `onExecute()` method on the ITopActions interface. + +The `onExecute()` handler passes two arguments in that you can handle: + +- `actionName`: maps to the `targetProperty` of the Top Action control that triggered this handler to be called +- `updatedValue`: when the Top Action is of type dropdown, this is the `key` property of the selected dropdown option; otherwise when the Top Action is of type button, the value of this property is `true` + +```typescript +public getTopActionsConfiguration(): ITopActions | undefined { + return { + topActions: [{ + type: TopActionsFieldType.Button, + title: 'Button', + targetProperty: 'button', + properties: { + text: 'Button', + icon: 'SharePointLogo' + } + }, { + type: TopActionsFieldType.Dropdown, + title: 'Dropdown', + targetProperty: 'dropdown', + properties: { + options: [{ + key: '1', + text: 'Option 1' + }, { + key: '2', + text: 'Option 2' + }] + } + }], + onExecute(actionName, updatedValue) { + console.log('onExecute', actionName, updatedValue); + } + } +} +``` + +## Testing & debugging Top Actions + +Similar to the different types of SPFx extensions, Top Actions must be tested in a live SharePoint modern page. They won't render on the SharePoint hosted workbench. + +### See more + +- [Top Actions API](/javascript/api/sp-top-actions) diff --git a/docs/spfx/web-parts/guidance/governance-considerations.md b/docs/spfx/web-parts/guidance/governance-considerations.md index 007c0f2fd..61dbca6d0 100644 --- a/docs/spfx/web-parts/guidance/governance-considerations.md +++ b/docs/spfx/web-parts/guidance/governance-considerations.md @@ -2,8 +2,7 @@ title: SharePoint Framework solutions governance considerations description: To get the most benefit from SharePoint Framework solutions, your organization should have an actionable governance plan covering the most important project management considerations. ms.date: 07/01/2020 -ms.prod: sharepoint -localization_priority: Normal +ms.localizationpriority: medium --- # SharePoint Framework solutions governance considerations @@ -24,7 +23,7 @@ The most important thing that organizations should know before deploying SharePo ### Is the code-hosting location supported by the organization? -SharePoint Framework doesn't impose any restrictions where the solution's code is deployed. As a result, developers and vendors can deploy the code to a range of locations within or outside the organization's IT department. Different organizations may have different server requirements ranging from access policies to SLAs. +SharePoint Framework doesn't impose any restrictions where the solution's code is deployed. As a result, developers and vendors can deploy the code to a range of locations within or outside the organization's IT department. Different organizations may have different server requirements ranging from access policies to SLAs. Before deploying a SharePoint Framework solution package, organizations should ensure that the server used to host the code is a known server approved to be used by the organization. diff --git a/docs/spfx/web-parts/guidance/integrate-web-part-properties-with-sharepoint.md b/docs/spfx/web-parts/guidance/integrate-web-part-properties-with-sharepoint.md index f7c76b6fe..0031f2dd9 100644 --- a/docs/spfx/web-parts/guidance/integrate-web-part-properties-with-sharepoint.md +++ b/docs/spfx/web-parts/guidance/integrate-web-part-properties-with-sharepoint.md @@ -2,8 +2,7 @@ title: Integrate web part properties with SharePoint description: Use capabilities that simplify managing web part properties' values and integrate them with SharePoint Search when building SharePoint Framework client-side web parts. ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Integrate web part properties with SharePoint diff --git a/docs/spfx/web-parts/guidance/intercepting-query-changes-in-webparts.md b/docs/spfx/web-parts/guidance/intercepting-query-changes-in-webparts.md index 19c9db5ec..982ef1b82 100644 --- a/docs/spfx/web-parts/guidance/intercepting-query-changes-in-webparts.md +++ b/docs/spfx/web-parts/guidance/intercepting-query-changes-in-webparts.md @@ -3,8 +3,7 @@ title: Intercepting Query String Changes in Web Parts description: Building web parts that respond to query string changes. ms.author: bekaise ms.date: 07/01/2020 -ms.prod: sharepoint -localization_priority: Normal +ms.localizationpriority: medium --- # Intercepting Query String Changes in Web Parts diff --git a/docs/spfx/web-parts/guidance/localize-web-parts.md b/docs/spfx/web-parts/guidance/localize-web-parts.md index 1f71b18f9..84a69b9f2 100644 --- a/docs/spfx/web-parts/guidance/localize-web-parts.md +++ b/docs/spfx/web-parts/guidance/localize-web-parts.md @@ -1,9 +1,8 @@ --- title: Localize SharePoint Framework client-side web parts description: Broaden the appeal of your web part by localizing it for different languages spoken by SharePoint users all over the world. -ms.date: 8/9/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 12/05/2023 +ms.localizationpriority: high --- # Localize SharePoint Framework client-side web parts @@ -38,14 +37,9 @@ You can broaden the appeal of your SharePoint Framework client-side web part by 1. When prompted, enter the following values: - **What is your solution name?** react-localization - - **Which baseline packages do you want to target for your component(s)?** SharePoint Online only (latest) - - **Where do you want to place the files?** Use the current folder - - **Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites immediately without running any feature deployment or adding apps in sites?** Yes - - **Will the components in the solution require permissions to access web APIs that are unique and not shared with other components in the tenant?** No - **Which type of client-side component to create?** WebPart - **What is your Web part name?** Greeting - - **What is your Web part description?** Greets the user - - **Which framework would you like to use?** React + - **Which template would you like to use?** React 1. After the scaffolding completes, lock down the version of the project dependencies by running the following command: @@ -189,8 +183,8 @@ You can broaden the appeal of your SharePoint Framework client-side web part by { // ... "preconfiguredEntries": [{ - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other - "group": { "default": "Other" }, + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced + "group": { "default": "Advanced" }, "title": { "default": "Greeting" }, "description": { "default": "Greets the user" }, "officeFabricIconFontName": "Page", @@ -230,8 +224,8 @@ Properties that support localization are of type **ILocalizedString**. Each loca { // ... "preconfiguredEntries": [{ - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other - "group": { "default": "Other", "nl-NL": "Anders" }, + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced + "group": { "default": "Advanced", "nl-NL": "Anders" }, "title": { "default": "Greeting", "nl-NL": "Begroeting" }, "description": { "default": "Greets the user", "nl-NL": "Begroet de gebruiker" }, "officeFabricIconFontName": "Page", @@ -597,8 +591,8 @@ Originally, the Greeting web part had the **greeting** property defined where th // ... "preconfiguredEntries": [{ - "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other - "group": { "default": "Other", "nl-NL": "Anders" }, + "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced + "group": { "default": "Advanced", "nl-NL": "Anders" }, "title": { "default": "Greeting", "nl-NL": "Begroeting" }, "description": { "default": "Greets the user", "nl-NL": "Begroet de gebruiker" }, "officeFabricIconFontName": "Page", diff --git a/docs/spfx/web-parts/guidance/migrate-angular-1-x-applications-to-sharepoint-framework.md b/docs/spfx/web-parts/guidance/migrate-angular-1-x-applications-to-sharepoint-framework.md index be81f71e4..985d0ae12 100644 --- a/docs/spfx/web-parts/guidance/migrate-angular-1-x-applications-to-sharepoint-framework.md +++ b/docs/spfx/web-parts/guidance/migrate-angular-1-x-applications-to-sharepoint-framework.md @@ -1,16 +1,15 @@ --- title: Migrate AngularJS applications to SharePoint Framework description: Migrate an existing AngularJS application styled using ngOfficeUIFabric to a SharePoint Framework client-side web part. -ms.date: 08/19/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 03/08/2023 +ms.localizationpriority: high --- # Migrate AngularJS applications to SharePoint Framework Many organizations have been using AngularJS v1.x for building SharePoint solutions in the past. This article shows how to migrate an existing AngularJS application styled using [ngOfficeUIFabric](https://github.com/ngOfficeUIFabric/ng-officeuifabric) - AngularJS directives for Office UI Fabric, to a SharePoint Framework client-side web part. The sample application used for this tutorial manages To Do items stored in a SharePoint list. -AngularJS application for managing To Do items stored in a SharePoint list +![AngularJS application for managing To Do items stored in a SharePoint list](../../../images/ng-migration-original-angular-application.png) The source of the AngularJS application is available on GitHub at [angular-migration/angular-todo](https://github.com/pnp/sp-dev-fx-webparts/tree/master/samples/angular-migration/angular-todo). @@ -43,14 +42,12 @@ Before you start migrating your AngularJS application, create and set up a new S yo @microsoft/sharepoint ``` -1. When prompted, enter the following values (*select the default option for all prompts omitted below*): +1. When prompted, enter the following values (*select the default option for all prompts omitted from the following list*): - **What is your solution name?**: angular-todo - - **Which baseline packages do you want to target for your component(s)?**: SharePoint Online only (latest) - **Which type of client-side component to create?**: Web Part - **What is your Web part name?**: To do - - **What is your Web part description?**: Simple management of to do tasks - - **Which framework would you like to use?**: No JavaScript framework + - **Which template would you like to use?**: No JavaScript framework 1. Open your project folder in your code editor. In this tutorial, you'll use Visual Studio Code. @@ -224,7 +221,7 @@ Although the web part is working correctly, it doesn't look the same as the Angu } ``` -2. In the **./src/webparts/toDo/ToDoWebPart.ts** file, in the `render()` method, change the application rendering template to use new Office UI Fabric icons. +1. In the **./src/webparts/toDo/ToDoWebPart.ts** file, in the `render()` method, change the application rendering template to use new Office UI Fabric icons. ```typescript export default class ToDoWebPart extends BaseClientSideWebPart { @@ -668,7 +665,7 @@ Even though the way the web part works hasn't changed, your code is improved. if ## Improve integration of the AngularJS application with the SharePoint Framework -At this point, the AngularJS application works correctly and is wrapped in a SharePoint Framework client-side web part. While users can add the web part to the page, they cannot configure how the web part should work. All of the configuration is embedded in the AngularJS application's code. In this section, you'll extend the web part to allow configuration of the name of the list where the To Do items are stored and whether the web part should show finished tasks or not. +At this point, the AngularJS application works correctly and is wrapped in a SharePoint Framework client-side web part. While users can add the web part to the page, they can't configure how the web part should work. All of the configuration is embedded in the AngularJS application's code. In this section, you'll extend the web part to allow configuration of the name of the list where the To Do items are stored and whether the web part should show finished tasks or not. ### Define web part properties diff --git a/docs/spfx/web-parts/guidance/migrate-jquery-datatables-script-to-spfx.md b/docs/spfx/web-parts/guidance/migrate-jquery-datatables-script-to-spfx.md index a5d72ab2e..6762d50b5 100644 --- a/docs/spfx/web-parts/guidance/migrate-jquery-datatables-script-to-spfx.md +++ b/docs/spfx/web-parts/guidance/migrate-jquery-datatables-script-to-spfx.md @@ -2,8 +2,7 @@ title: Migrate jQuery and DataTables solution built using Script Editor web part to SharePoint Framework description: Migrate a SharePoint customization using DataTables to build powerful data overviews of data coming from SharePoint and external APIs. ms.date: 08/19/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Migrate jQuery and DataTables solution built using Script Editor web part to SharePoint Framework diff --git a/docs/spfx/web-parts/guidance/migrate-jquery-fullcalendar-script-to-spfx.md b/docs/spfx/web-parts/guidance/migrate-jquery-fullcalendar-script-to-spfx.md index 648a75a3e..d18d98525 100644 --- a/docs/spfx/web-parts/guidance/migrate-jquery-fullcalendar-script-to-spfx.md +++ b/docs/spfx/web-parts/guidance/migrate-jquery-fullcalendar-script-to-spfx.md @@ -2,8 +2,7 @@ title: Migrate jQuery and FullCalendar solution built using Script Editor web part to SharePoint Framework description: Migrate a SharePoint customization by using FullCalendar built with the Script Editor web part to the SharePoint Framework. ms.date: 08/19/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Migrate jQuery and FullCalendar solution built using Script Editor web part to SharePoint Framework diff --git a/docs/spfx/web-parts/guidance/migrate-script-editor-web-part-customizations.md b/docs/spfx/web-parts/guidance/migrate-script-editor-web-part-customizations.md index c11a34491..49789190c 100644 --- a/docs/spfx/web-parts/guidance/migrate-script-editor-web-part-customizations.md +++ b/docs/spfx/web-parts/guidance/migrate-script-editor-web-part-customizations.md @@ -2,8 +2,7 @@ title: Migrate existing Script Editor web part customizations to the SharePoint Framework description: The benefits of migrating existing client-side customizations to the SharePoint Framework and things to consider when planning the migration. ms.date: 06/27/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- diff --git a/docs/spfx/web-parts/guidance/reference-third-party-css-styles.md b/docs/spfx/web-parts/guidance/reference-third-party-css-styles.md index 65490fa45..9568130ca 100644 --- a/docs/spfx/web-parts/guidance/reference-third-party-css-styles.md +++ b/docs/spfx/web-parts/guidance/reference-third-party-css-styles.md @@ -2,8 +2,7 @@ title: Reference third-party CSS styles in SharePoint Framework web parts description: Two approaches to including third-party CSS styles in web parts, and how each approach affects the resulting web part bundle. ms.date: 12/02/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.localizationpriority: high --- # Reference third-party CSS styles in SharePoint Framework web parts diff --git a/docs/spfx/web-parts/guidance/simplify-adding-web-parts-with-preconfigured-entries.md b/docs/spfx/web-parts/guidance/simplify-adding-web-parts-with-preconfigured-entries.md index 11b003e48..a78609505 100644 --- a/docs/spfx/web-parts/guidance/simplify-adding-web-parts-with-preconfigured-entries.md +++ b/docs/spfx/web-parts/guidance/simplify-adding-web-parts-with-preconfigured-entries.md @@ -1,9 +1,8 @@ --- title: Simplify adding web parts with preconfigured entries description: Use preconfigured entries in a SharePoint Framework client-side web part to provide users with preconfigured versions of your web part. -ms.date: 06/22/2021 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 06/06/2024 +ms.localizationpriority: high --- # Simplify adding web parts with preconfigured entries @@ -13,7 +12,7 @@ More complex SharePoint Framework client-side web parts likely have many propert > Before following the steps in this article, be sure to [set up your SharePoint client-side web part development environment](../../set-up-your-development-environment.md). > [!WARNING] -> SPFx solutions targetting SharePoint Server 2016 are limited to setting only a single web part property as a preconfigured entry. For more information, see [issue #5260](https://github.com/SharePoint/sp-dev-docs/issues/5260). +> SPFx solutions targeting SharePoint Server 2016 are limited to setting only a single web part property as a preconfigured entry. For more information, see [issue #5260](https://github.com/SharePoint/sp-dev-docs/issues/5260). ## Web part preconfigured entries @@ -26,7 +25,7 @@ One of the properties specified in the web part manifest is the `preconfiguredEn ```json { - "$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json", + "$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", "id": "6737645a-4443-4210-a70e-e5e2a219133a", "alias": "GalleryWebPart", @@ -35,7 +34,7 @@ One of the properties specified in the web part manifest is the `preconfiguredEn "manifestVersion": 2, "preconfiguredEntries": [{ - "groupId": "1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489", // Discover + "groupId": "1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489", // Discovery "group": { "default": "Under Development" }, "title": { "default": "Gallery" }, "description": { "default": "Shows items from the selected list" }, @@ -55,16 +54,15 @@ If you've built classic web parts with full-trust solutions, you can think of ea Each item in the `preconfiguredEntries` array consists of several properties. The following table explains the purpose of each property. -| Property name | Value type | Required | Purpose | Sample value | -| :----------------------- | :--------------- | :------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------- | -| `title` | ILocalizedString | yes | The web part title that is displayed in the toolbox. | `"title": { "default": "Weather", "nl-nl": "Weerbericht" }` | -| `description` | ILocalizedString | yes | The web part description that is displayed in the toolbox tooltips. | `"description": { "default": "Shows weather in the given location", "nl-nl": "Toont weerbericht voor de opgegeven locatie" }` | -| `officeFabricIconFontName` | string | no | The icon for the web part that is displayed in the toolbox. Its value must be one of the [Office UI Fabric icon names](https://developer.microsoft.com/fluentui#/styles/web/icons). If this property has a value, the `iconImageUrl` property is ignored. | `"officeFabricIconFontName": "Sunny"` | -| `iconImageUrl` | string | no | The icon for the web part that is displayed in the toolbox and is represented by an image URL. The image at the URL must be exactly 40x28 px. If the `officeFabricIconName` property doesn't have a value, this property must have a value. | `"iconImageUrl": "https://cdn.contoso.com/weather.png"` | -| `groupId` | string | yes | The group ID to determine which modern group contains the web part in a modern site page. The SharePoint Framework reserves group IDs for [predefined groups](#predefined-modern-groups). The developer can pick one from those groups. If the developer fills an ID not in the predefined groups, it falls back to **Other** group. | `"groupId": "1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489"` | -| `group` | ILocalizedString | no | The group name in the web part picker to contain the web part in the classic page. If no value is provided, the web part is displayed in the **Miscellaneous** group. | `"group": { "default": "Content", "nl-nl": "Inhoud" }` | -| `dataVersion` | string | no | Use this field to specify the data version of the pre-configured data provided to the web part. The data version is different from the version field in the manifest. The manifest version is used to control the versioning of the web part code, while data version is used to control the versioning of the serialized data of the web part. Refer to the `dataVersion` field of your web part for more information. Supported values format: MAJOR.MINOR version | `"dataVersion": "1.0"` | -| `properties` | TProperties | yes | A key-value pair object with default values for web part properties. | `"properties": { "location": "Redmond", "numberOfDays": 3, "showIcon": true }` | +| Property name | Value type | Required | Purpose | Sample value | +| :------------------------- | :--------------- | :------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | +| `title` | ILocalizedString | yes | The web part title that is displayed in the toolbox. | `"title": { "default": "Weather", "nl-nl": "Weerbericht" }` | +| `description` | ILocalizedString | yes | The web part description that is displayed in the toolbox tooltips. | `"description": { "default": "Shows weather in the given location", "nl-nl": "Toont weerbericht voor de opgegeven locatie" }` | +| `officeFabricIconFontName` | string | no | The icon for the web part that is displayed in the toolbox. Its value must be one of the [Office UI Fabric icon names](https://developer.microsoft.com/fluentui#/styles/web/icons). If this property has a value, the `iconImageUrl` property is ignored. | `"officeFabricIconFontName": "Sunny"` | +| `iconImageUrl` | string | no | The icon for the web part that is displayed in the toolbox and is represented by an image URL. The image at the URL must be exactly 40x28 px. If the `officeFabricIconName` property doesn't have a value, this property must have a value. | `"iconImageUrl": "https://cdn.contoso.com/weather.png"` | +| `groupId` | string | yes | The group ID to determine which modern group contains the web part in a modern site page. The SharePoint Framework reserves group IDs for [predefined groups](#predefined-modern-groups). The developer can pick one from those groups. If the developer fills an ID not in the predefined groups, it falls back to **Other** group. | `"groupId": "1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489"` | +| `group` | ILocalizedString | no | The group name in the web part picker to contain the web part in the classic page. If no value is provided, the web part is displayed in the **Miscellaneous** group. | `"group": { "default": "Content", "nl-nl": "Inhoud" }` | +| `properties` | TProperties | yes | A key-value pair object with default values for web part properties. | `"properties": { "location": "Redmond", "numberOfDays": 3, "showIcon": true }` | Some web part properties have a value of type `ILocalizedString`. This type is a key-value pair object that allows developers to specify strings for the different locales. At a minimum, a value of type `ILocalizedString` must contain the `default` value. @@ -97,17 +95,17 @@ An `ILocalizedString` value that isn't valid because the `default` key is missin There are seven out-of-the-box groups as shown in the following table. Use the group ID in the `groupId` property. -| Group name | ID | Group includes... | +| Group name | ID | Group includes... | | ------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------ | | Text, media, and content | `cf066440-0614-43d6-98ae-0b31cf14c7c3` | Web parts that display text, multi-media, documents, information from the web, and other rich content. | -| Discover | `1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489` | Web parts that organize, group, and filter content to help users discover information. | +| Discovery | `1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489` | Web parts that organize, group, and filter content to help users discover information. | | Communication and collaboration | `75e22ed5-fa14-4829-850a-c890608aca2d` | Web parts that facilitate information sharing, team work, and social interactions. | | Planning and process | `1bc7927e-4a5e-4520-b540-71305c79c20a` | Web parts that empower team productivity with the use of planning and process tools. | | Business and intelligence | `4aca9e90-eff5-4fa1-bac7-728f5f157b66` | Web parts for tracking and analyzing data, and for integrating business flow with pages. | | Site tools | `070951d7-94da-4db8-b06e-9d581f1f55b1` | Web parts for site information and management. | -| Other | `5c03119e-3074-46fd-976b-c60198311f70` | Web parts not in other groups. | +| Advanced | `5c03119e-3074-46fd-976b-c60198311f70` | Web parts not in other groups. | -If the developer fills an ID not in the previous list, the web part falls back to the **Other** group. +If the developer fills an ID not in the previous list, the web part falls back to the **Advanced** group. To see how you can use preconfigured entries when building web parts, you'll build a sample gallery web part. Using several properties, users can configure this web part to show items from a selected list in a specific way. For brevity, you'll omit the actual implementation of the web part logic and will focus on using the `preconfiguredEntries` property to provide preconfigured versions of the gallery web part. @@ -127,19 +125,17 @@ To see how you can use preconfigured entries when building web parts, you'll bui cd react-preconfiguredentries ``` -1. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project. +1. Create a new project by running the Yeoman SharePoint Generator from within the new directory you created: ```console yo @microsoft/sharepoint ``` -1. When prompted, enter the following values (*select the default option for all prompts omitted below*): + The Yeoman SharePoint Generator will prompt you with a series of questions. For all questions, accept the default options except for the following questions: - - **What is your solution name?** react-preconfiguredentries - **Which type of client-side component to create?** WebPart - **What is your Web part name?** Gallery - - **What is your Web part description?** Shows items from the selected list - - **Which framework would you like to use?** React + - **Which template would you like to use?** React 1. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor you prefer. @@ -174,7 +170,7 @@ In the web part manifest, add web part properties so that users can configure th Web part properties specified in the manifest must also be added to the web part properties interface. -1. In the code editor, open the **./src/webparts/gallery/IGalleryWebPartProps.ts** file. Change its code to: +1. In the code editor, open the **./src/webparts/gallery/GalleryWebPart.ts** file and find **IGalleryWebPartProps** interface. Change its code to: ```typescript export interface IGalleryWebPartProps { @@ -276,7 +272,7 @@ In the web part manifest, add web part properties so that users can configure th 1. Update the main React component interface to match the web part property interface, because we're bypassing all the web part properties to this component. In the code editor, open the **./src/webparts/gallery/components/IGalleryProps.ts** file, and change its code to: ```typescript - import { IGalleryWebPartProps } from '../IGalleryWebPartProps'; + import { IGalleryWebPartProps } from '../GalleryWebPart'; export interface IGalleryProps extends IGalleryWebPartProps { } ``` diff --git a/docs/spfx/web-parts/guidance/supporting-section-backgrounds.md b/docs/spfx/web-parts/guidance/supporting-section-backgrounds.md index 658dde48b..20d6ea27e 100644 --- a/docs/spfx/web-parts/guidance/supporting-section-backgrounds.md +++ b/docs/spfx/web-parts/guidance/supporting-section-backgrounds.md @@ -1,8 +1,7 @@ --- title: Supporting section backgrounds description: The available options for implementing support in your web parts for section backgrounds. -ms.date: 06/16/2020 -ms.prod: sharepoint +ms.date: 06/13/2022 --- # Supporting section backgrounds @@ -13,11 +12,11 @@ Starting with SharePoint Framework v1.8, web parts can be made aware of any sect The section background color you can set is based upon the main color of the theme you applied. To set the background of a section open its properties: -![Setting properties of a background](../../../images/supporting-section-backgrounds-modify-section.png) +![Screenshot of a red arrow pointing to the background properties icon.](../../../images/supporting-section-backgrounds-modify-section.png) In the properties you can define which type of section background you want to set: -![Setting properties of a background](../../../images/supporting-section-backgrounds-modify-section2.png) +![Screenshot of the Layout options pane with the One column option being highlighted.](../../../images/supporting-section-backgrounds-modify-section2.png) ## Making your web part theme aware diff --git a/docs/spfx/web-parts/guidance/use-cascading-dropdowns-in-web-part-properties.md b/docs/spfx/web-parts/guidance/use-cascading-dropdowns-in-web-part-properties.md index 79cfa4b89..1331e9b44 100644 --- a/docs/spfx/web-parts/guidance/use-cascading-dropdowns-in-web-part-properties.md +++ b/docs/spfx/web-parts/guidance/use-cascading-dropdowns-in-web-part-properties.md @@ -1,9 +1,8 @@ --- title: Use cascading dropdowns in web part properties description: Create cascading dropdown controls in the SharePoint client-side web part property pane without developing a custom property pane control. -ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 09/23/2023 +ms.localizationpriority: high --- # Use cascading dropdowns in web part properties @@ -11,7 +10,7 @@ When designing the property pane for your SharePoint client-side web parts, you ![Item dropdown disabled and web part placeholder communicating loading updated list of item options](../../../images/react-cascading-dropdowns-loading-indicator-when-loading-items.png) -The source of the working web part is available on GitHub at [sp-dev-fx-webparts/samples/react-custompropertypanecontrols/](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-custompropertypanecontrols). +The source of the working web part is available on GitHub at [sp-dev-fx-webparts/samples/react-cascadingdropdowns/](https://github.com/pnp/sp-dev-fx-webparts/tree/master/samples/react-cascadingdropdowns). > [!NOTE] > Before following the steps in this article, be sure to [set up your SharePoint client-side web part development environment](../../set-up-your-development-environment.md). @@ -39,12 +38,9 @@ The source of the working web part is available on GitHub at [sp-dev-fx-webparts 1. When prompted, enter the following values (*select the default option for all prompts omitted below*): - **What is your solution name?**: react-cascadingdropdowns - - **Which baseline packages do you want to target for your component(s)?**: SharePoint Online - - **Where do you want to place the files?**: Use the current folder - **Which type of client-side component to create?**: WebPart - **What is your Web part name?**: List items - - **What is your Web part description?**: Shows list items from the selected list - - **Which framework would you like to use?**: React + - **Which template would you like to use?**: React 1. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer. @@ -66,7 +62,7 @@ You'll build a web part that displays list items from a selected SharePoint list } ``` -1. Open the **src/webparts/listItems/IListItemsWebPartProps.ts** file, and replace its contents with: +1. Open the **src/webparts/listItems/ListItemsWebPart.ts** file, and replace the `IListItemsWebPartProps` interface with the following: ```typescript export interface IListItemsWebPartProps { @@ -80,9 +76,16 @@ You'll build a web part that displays list items from a selected SharePoint list export default class ListItemsWebPart extends BaseClientSideWebPart { // ... public render(): void { - const element: React.ReactElement = React.createElement(ListItems, { - listName: this.properties.listName - }); + const element: React.ReactElement = React.createElement( + ListItems, + { + listName: this.properties.listName, + isDarkTheme: this._isDarkTheme, + environmentMessage: this._environmentMessage, + hasTeamsContext: !!this.context.sdks.microsoftTeams, + userDisplayName: this.context.pageContext.user.displayName + } + ); ReactDom.render(element, this.domElement); } @@ -95,7 +98,6 @@ You'll build a web part that displays list items from a selected SharePoint list ```typescript export default class ListItemsWebPart extends BaseClientSideWebPart { // ... - protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [ @@ -117,7 +119,6 @@ You'll build a web part that displays list items from a selected SharePoint list ] }; } - // ... } ``` @@ -125,10 +126,19 @@ You'll build a web part that displays list items from a selected SharePoint list 1. In the **src/webparts/listItems/loc/mystrings.d.ts** file, change the `IListItemsStrings` interface to: ```typescript - declare interface IListItemsStrings { + declare interface IListItemsWebPartStrings { PropertyPaneDescription: string; BasicGroupName: string; ListNameFieldLabel: string; + AppLocalEnvironmentSharePoint: string; + AppLocalEnvironmentTeams: string; + AppLocalEnvironmentOffice: string; + AppLocalEnvironmentOutlook: string; + AppSharePointEnvironment: string; + AppTeamsTabEnvironment: string; + AppOfficeEnvironment: string; + AppOutlookEnvironment: string; + UnknownEnvironment: string; } ``` @@ -139,7 +149,16 @@ You'll build a web part that displays list items from a selected SharePoint list return { "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", - "ListNameFieldLabel": "List" + "ListNameFieldLabel": "List", + "AppLocalEnvironmentSharePoint": "The app is running on your local environment as SharePoint web part", + "AppLocalEnvironmentTeams": "The app is running on your local environment as Microsoft Teams app", + "AppLocalEnvironmentOffice": "The app is running on your local environment in office.com", + "AppLocalEnvironmentOutlook": "The app is running on your local environment in Outlook", + "AppSharePointEnvironment": "The app is running on SharePoint page", + "AppTeamsTabEnvironment": "The app is running in Microsoft Teams", + "AppOfficeEnvironment": "The app is running in office.com", + "AppOutlookEnvironment": "The app is running in Outlook", + "UnknownEnvironment": "The app is running in an unknown environment" } }); ``` @@ -147,25 +166,25 @@ You'll build a web part that displays list items from a selected SharePoint list 1. In the **src/webparts/listItems/components/ListItems.tsx** file, change the contents of the `render()` method to: ```tsx - export default class ListItems extends React.Component { public render(): JSX.Element { - return ( -
    -
    -
    -
    - Welcome to SharePoint! -

    Customize SharePoint experiences using web parts.

    -

    {escape(this.props.listName)}

    - - Learn more - -
    -
    -
    + const { + listName, + isDarkTheme, + environmentMessage, + hasTeamsContext, + userDisplayName + } = this.props; + + return ( +
    +
    + +

    Well done, {escape(userDisplayName)}!

    +
    {environmentMessage}
    +
    List name: {escape(listName)}
    - ); - } +
    + ); } ``` @@ -174,6 +193,10 @@ You'll build a web part that displays list items from a selected SharePoint list ```typescript export interface IListItemsProps { listName: string; + isDarkTheme: boolean; + environmentMessage: string; + hasTeamsContext: boolean; + userDisplayName: string; } ``` @@ -183,6 +206,9 @@ You'll build a web part that displays list items from a selected SharePoint list gulp serve ``` + > [!NOTE] + > If this is your first time running the `gulp serve` command on your workstation, you may need to run the `gulp trust-dev-cert` command first. + 1. In the web browser, add the **List items** web part to the canvas and open its properties. Verify that the value set for the **List** property is displayed in the web part body. ![Web part showing the value of the listName property](../../../images/react-cascading-dropdowns-web-part-first-run.png) @@ -198,7 +224,6 @@ At this point, a user specifies which list the web part should use by manually e ```typescript import { IPropertyPaneConfiguration, - PropertyPaneTextField, PropertyPaneDropdown, IPropertyPaneDropdownOption } from '@microsoft/sp-property-pane'; @@ -223,6 +248,16 @@ At this point, a user specifies which list the web part should use by manually e } ``` +1. Add a new class variable named `loadingIndicator`. This variable determines whether the property pane should display a loading indicator. while the web part retrieves the information about the lists available in the current site, the loading indicator should be set to `true`. + + ```typescript + export default class ListItemsWebPart extends BaseClientSideWebPart { + // ... + private loadingIndicator: boolean = true; + // ... + } + ``` + 1. Change the `getPropertyPaneConfiguration()` method to use the dropdown control to render the `listName` property: ```typescript @@ -231,6 +266,7 @@ At this point, a user specifies which list the web part should use by manually e protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { + showLoadingIndicator: this.loadingIndicator, pages: [ { header: { @@ -274,20 +310,21 @@ Previously, you associated the dropdown control of the `listName` property with export default class ListItemsWebPart extends BaseClientSideWebPart { // ... - private loadLists(): Promise { - return new Promise((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => { - setTimeout((): void => { - resolve([{ - key: 'sharedDocuments', - text: 'Shared Documents' - }, - { - key: 'myDocuments', - text: 'My Documents' - }]); - }, 2000); - }); - } + private async loadLists(): Promise { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return await new Promise((resolve: (options: IPropertyPaneDropdownOption[]) => void, _reject: (error: any) => void) => { + setTimeout((): void => { + resolve([{ + key: 'sharedDocuments', + text: 'Shared Documents' + }, + { + key: 'myDocuments', + text: 'My Documents' + }]); + }, 2000); + }); + } } ``` @@ -297,23 +334,27 @@ Previously, you associated the dropdown control of the `listName` property with export default class ListItemsWebPart extends BaseClientSideWebPart { // ... - protected onPropertyPaneConfigurationStart(): void { + protected async onPropertyPaneConfigurationStart(): Promise { + // disable the item selector until lists have been loaded this.listsDropdownDisabled = !this.lists; + // nothing to do until someone selects a list if (this.lists) { return; } - this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'lists'); + // show a loading indicator in the property pane while loading lists and items + this.loadingIndicator = true; + this.context.propertyPane.refresh(); - this.loadLists() - .then((listOptions: IPropertyPaneDropdownOption[]): void => { - this.lists = listOptions; - this.listsDropdownDisabled = false; - this.context.propertyPane.refresh(); - this.context.statusRenderer.clearLoadingIndicator(this.domElement); - this.render(); - }); + // load the lists from SharePoint + const listOptions: IPropertyPaneDropdownOption[] = await this.loadLists(); + this.lists = listOptions; + this.listsDropdownDisabled = false; + + // remove the loading indicator + this.loadingIndicator = false; + this.context.propertyPane.refresh(); } // ... } @@ -323,7 +364,7 @@ Previously, you associated the dropdown control of the `listName` property with - First, the method checks if the information about the lists available in the current site has been loaded. - If the list information is loaded, the list dropdown is enabled. - - If the list information about lists hasn't been loaded yet, the loading indicator is displayed, which informs the user that the web part is loading information about lists. + - If the list information about lists hasn't been loaded yet, the loading indicator is displayed in the property pane, which informs the user that the web part is loading information about lists. ![Loading indicator displayed in web part while loading information about available lists](../../../images/react-cascading-dropdowns-loading-indicator-when-loading-list-info.png) @@ -331,7 +372,7 @@ Previously, you associated the dropdown control of the `listName` property with Next, the dropdown is enabled allowing the user to select a list. By calling `this.context.propertyPane.refresh()`, the web part property pane is refreshed and it reflects the latest changes to the list dropdown. - After list information is loaded, the loading indicator is removed by a call to the `clearLoadingIndicator()` method. Because calling this method clears the web part user interface, the `render()` method is called to force the web part to re-render. + After list information is loaded, the loading indicator is removed by a setting the`this.loadingIndicator` to `false`. Because calling this method changes the property pane interface, the `this.context.propertyPane.refresh()` method is called to force the property pane to re-render. 1. Run the following command to confirm that everything is working as expected: @@ -379,6 +420,10 @@ When building web parts, you often need to allow users to choose an option from export interface IListItemsProps { listName: string; itemName: string; + isDarkTheme: boolean; + environmentMessage: string; + hasTeamsContext: boolean; + userDisplayName: string; } ``` @@ -388,10 +433,17 @@ When building web parts, you often need to allow users to choose an option from export default class ListItemsWebPart extends BaseClientSideWebPart { // ... public render(): void { - const element: React.ReactElement = React.createElement(ListItems, { - listName: this.properties.listName, - itemName: this.properties.itemName - }); + const element: React.ReactElement = React.createElement( + ListItems, + { + listName: this.properties.listName, + itemName: this.properties.itemName, + isDarkTheme: this._isDarkTheme, + environmentMessage: this._environmentMessage, + hasTeamsContext: !!this.context.sdks.microsoftTeams, + userDisplayName: this.context.pageContext.user.displayName + } + ); ReactDom.render(element, this.domElement); } @@ -402,11 +454,20 @@ When building web parts, you often need to allow users to choose an option from 1. In the **src/webparts/listItems/loc/mystrings.d.ts** file, change the `IListItemsStrings` interface to: ```typescript - declare interface IListItemsStrings { + declare interface IListItemsWebPartStrings { PropertyPaneDescription: string; BasicGroupName: string; ListNameFieldLabel: string; ItemNameFieldLabel: string; + AppLocalEnvironmentSharePoint: string; + AppLocalEnvironmentTeams: string; + AppLocalEnvironmentOffice: string; + AppLocalEnvironmentOutlook: string; + AppSharePointEnvironment: string; + AppTeamsTabEnvironment: string; + AppOfficeEnvironment: string; + AppOutlookEnvironment: string; + UnknownEnvironment: string; } ``` @@ -418,7 +479,16 @@ When building web parts, you often need to allow users to choose an option from "PropertyPaneDescription": "Description", "BasicGroupName": "Group Name", "ListNameFieldLabel": "List", - "ItemNameFieldLabel": "Item" + "ItemNameFieldLabel": "Item", + "AppLocalEnvironmentSharePoint": "The app is running on your local environment as SharePoint web part", + "AppLocalEnvironmentTeams": "The app is running on your local environment as Microsoft Teams app", + "AppLocalEnvironmentOffice": "The app is running on your local environment in office.com", + "AppLocalEnvironmentOutlook": "The app is running on your local environment in Outlook", + "AppSharePointEnvironment": "The app is running on SharePoint page", + "AppTeamsTabEnvironment": "The app is running in Microsoft Teams", + "AppOfficeEnvironment": "The app is running in office.com", + "AppOutlookEnvironment": "The app is running in Outlook", + "UnknownEnvironment": "The app is running in an unknown environment" } }); ``` @@ -429,23 +499,26 @@ In the **src/webparts/listItems/components/ListItems.tsx** file, change the `ren ```tsx export default class ListItems extends React.Component { - public render(): JSX.Element { + public render(): React.ReactElement { + const { + listName, + itemName, + isDarkTheme, + environmentMessage, + hasTeamsContext, + userDisplayName + } = this.props; + return ( -
    -
    -
    -
    - Welcome to SharePoint! -

    Customize SharePoint experiences using web parts.

    -

    {escape(this.props.listName)}

    -

    {escape(this.props.itemName)}

    - - Learn more - -
    -
    +
    +
    + +

    Well done, {escape(userDisplayName)}!

    +
    {environmentMessage}
    +
    List name: {escape(listName)}
    +
    Item name: {escape(itemName)}
    -
    + ); } } @@ -478,36 +551,35 @@ Similar to how users can select a list by using a dropdown, they can select the 1. Change the `getPropertyPaneConfiguration()` method to use the dropdown control to render the `itemName` property. ```typescript - export default class ListItemsWebPart extends BaseClientSideWebPart { - // ... - protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { - return { - pages: [ - { - header: { - description: strings.PropertyPaneDescription - }, - groups: [ - { - groupName: strings.BasicGroupName, - groupFields: [ - PropertyPaneDropdown('listName', { - label: strings.ListNameFieldLabel, - options: this.lists, - disabled: this.listsDropdownDisabled - }), - PropertyPaneDropdown('itemName', { - label: strings.ItemNameFieldLabel, - options: this.items, - disabled: this.itemsDropdownDisabled - }) - ] - } - ] - } - ] - }; - } + protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { + return { + showLoadingIndicator: this.loadingIndicator, + pages: [ + { + header: { + description: strings.PropertyPaneDescription + }, + groups: [ + { + groupName: strings.BasicGroupName, + groupFields: [ + PropertyPaneDropdown('listName', { + label: strings.ListNameFieldLabel, + options: this.lists, + disabled: this.listsDropdownDisabled + }), + PropertyPaneDropdown('itemName', { + label: strings.ItemNameFieldLabel, + options: this.items, + disabled: this.itemsDropdownDisabled, + selectedKey: this.properties.itemName // don't forget to bind this property so it is refreshed when the parent property changes + }) + ] + } + ] + } + ] + }; } ``` @@ -526,44 +598,42 @@ Previously, you defined a dropdown control to render the `itemName` property in 1. Add method to load list items. In the **src/webparts/listItems/ListItemsWebPart.ts** file, in the `ListItemsWebPart` class, add a new method to load available list items from the selected list. (Like the method for loading available lists, you use mock data.) ```typescript - export default class ListItemsWebPart extends BaseClientSideWebPart { - // ... - private loadItems(): Promise { - if (!this.properties.listName) { - // resolve to empty options since no list has been selected - return Promise.resolve(); - } - - const wp: ListItemsWebPart = this; - - return new Promise((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => { - setTimeout(() => { - const items = { - sharedDocuments: [ - { - key: 'spfx_presentation.pptx', - text: 'SPFx for the masses' - }, - { - key: 'hello-world.spapp', - text: 'hello-world.spapp' - } - ], - myDocuments: [ - { - key: 'isaiah_cv.docx', - text: 'Isaiah CV' - }, - { - key: 'isaiah_expenses.xlsx', - text: 'Isaiah Expenses' - } - ] - }; - resolve(items[wp.properties.listName]); - }, 2000); - }); + private async loadItems(): Promise { + if (!this.properties.listName) { + // return empty options since no list has been selected + return []; } + + // This is where you'd replace the mock data with the actual data from SharePoint + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return await new Promise((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => { + // timeout to simulate async call + setTimeout(() => { + const items: { [key: string]: { key: string; text: string }[] } = { + sharedDocuments: [ + { + key: 'spfx_presentation.pptx', + text: 'SPFx for the masses' + }, + { + key: 'hello-world.spapp', + text: 'hello-world.spapp' + } + ], + myDocuments: [ + { + key: 'isaiah_cv.docx', + text: 'Isaiah CV' + }, + { + key: 'isaiah_expenses.xlsx', + text: 'Isaiah Expenses' + } + ] + }; + resolve(items[this.properties.listName]); + }, 2000); + }); } ``` @@ -574,30 +644,35 @@ Previously, you defined a dropdown control to render the `itemName` property in ```typescript export default class ListItemsWebPart extends BaseClientSideWebPart { // ... - protected onPropertyPaneConfigurationStart(): void { + protected async onPropertyPaneConfigurationStart(): Promise { + // disable the item selector until lists have been loaded this.listsDropdownDisabled = !this.lists; + + // disable the item selector until items have been loaded or if the list has not been selected this.itemsDropdownDisabled = !this.properties.listName || !this.items; + // nothing to do until someone selects a list if (this.lists) { return; } - this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'options'); - - this.loadLists() - .then((listOptions: IPropertyPaneDropdownOption[]): Promise => { - this.lists = listOptions; - this.listsDropdownDisabled = false; - this.context.propertyPane.refresh(); - return this.loadItems(); - }) - .then((itemOptions: IPropertyPaneDropdownOption[]): void => { - this.items = itemOptions; - this.itemsDropdownDisabled = !this.properties.listName; - this.context.propertyPane.refresh(); - this.context.statusRenderer.clearLoadingIndicator(this.domElement); - this.render(); - }); + // show a loading indicator in the property pane while loading lists and items + this.loadingIndicator = true; + this.context.propertyPane.refresh(); + + // load the lists from SharePoint + const listOptions: IPropertyPaneDropdownOption[] = await this.loadLists(); + this.lists = listOptions; + this.listsDropdownDisabled = false; + + // load the items from SharePoint + const itemOptions: IPropertyPaneDropdownOption[] = await this.loadItems(); + this.items = itemOptions; + this.itemsDropdownDisabled = !this.properties.listName; + + // remove the loading indicator + this.loadingIndicator = false; + this.context.propertyPane.refresh(); } // ... } @@ -624,37 +699,39 @@ Previously, you defined a dropdown control to render the `itemName` property in ```typescript export default class ListItemsWebPart extends BaseClientSideWebPart { // ... - protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void { - if (propertyPath === 'listName' && - newValue) { + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected async onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): Promise { + if (propertyPath === 'listName' && newValue) { + // communicate loading items + this.loadingIndicator = true; + // push new list value super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue); - // get previously selected item - const previousItem: string = this.properties.itemName; + // reset selected item - this.properties.itemName = undefined; - // push new item value - this.onPropertyPaneFieldChanged('itemName', previousItem, this.properties.itemName); + this.properties.itemName = ''; // use empty string to force property pane to reset the selected item. undefined will not trigger the reset + // disable item selector until new items are loaded this.itemsDropdownDisabled = true; + + // refresh the item selector control by repainting the property pane + this.context.propertyPane.refresh(); + + // get new items + const itemOptions: IPropertyPaneDropdownOption[] = await this.loadItems(); + + // store items + this.items = itemOptions; + + // enable item selector + this.itemsDropdownDisabled = false; + + // clear status indicator + this.loadingIndicator = false; + // refresh the item selector control by repainting the property pane this.context.propertyPane.refresh(); - // communicate loading items - this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'items'); - - this.loadItems() - .then((itemOptions: IPropertyPaneDropdownOption[]): void => { - // store items - this.items = itemOptions; - // enable item selector - this.itemsDropdownDisabled = false; - // clear status indicator - this.context.statusRenderer.clearLoadingIndicator(this.domElement); - // re-render the web part as clearing the loading indicator removes the web part body - this.render(); - // refresh the item selector control by repainting the property pane - this.context.propertyPane.refresh(); - }); } else { super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue); @@ -664,12 +741,14 @@ Previously, you defined a dropdown control to render the `itemName` property in } ``` - After the user selected a list, the web part persists the newly selected value. Because the selected list changed, the web part resets the previously selected list item. Now that a list is selected, the web part property pane loads list items for that particular list. While loading items, the user can't select an item. + After the user selects a list, the web part persists the newly selected value. Because the selected list changed, the web part resets the previously selected list item. Now that a list is selected, the web part property pane loads list items for that particular list. While loading items, the user can't select an item. After the items for the selected list are loaded, they're assigned to the **items** class variable from where they can be referenced by the item dropdown. Now that the information about available list items is available, the item dropdown is enabled allowing users to choose an item. The loading indicator is removed, which clears the web part body that is why the web part should re-render. Finally, the web part property pane refreshes to reflect the latest changes. ![Item dropdown in the web part property pane showing available list items for the selected list](../../../images/react-cascading-dropdowns-item-dropdown-list-items.png) + This article demonstrated how to use cascading dropdowns in the web part property pane, using static values. In a real-world scenario, you might use an API to retrieve the dropdown choices in each dropdown. An example of a working web part which expands upon this article and loads dropdown choices using an API is available on GitHub at [sp-dev-fx-webparts/samples/react-custompropertypanecontrols/](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-custompropertypanecontrols).. + ## See also - [Build custom controls for the property pane](./build-custom-property-pane-controls.md) diff --git a/docs/spfx/web-parts/guidance/use-existing-javascript-libraries.md b/docs/spfx/web-parts/guidance/use-existing-javascript-libraries.md index 859ddbf0f..bcb6db5b4 100644 --- a/docs/spfx/web-parts/guidance/use-existing-javascript-libraries.md +++ b/docs/spfx/web-parts/guidance/use-existing-javascript-libraries.md @@ -1,9 +1,8 @@ --- title: Use existing JavaScript libraries in SharePoint Framework client-side web parts description: Ensure that your web parts won't negatively impact the performance of SharePoint pages that they're being used on. -ms.date: 12/02/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 06/13/2022 +ms.localizationpriority: high --- # Use existing JavaScript libraries in SharePoint Framework client-side web parts @@ -75,11 +74,11 @@ However, bundling existing JavaScript libraries with SharePoint Framework client When bundling existing JavaScript frameworks in the SharePoint Framework, all referenced scripts are included in the generated bundle file. Following the Angular example, an optimized web part bundle including Angular is over 170 KB. -![Bundle file size highlighted in Explorer](../../../images/external-scripts-bundle-size.png) +![Screenshot of the File Explorer screen's deploy folder showing the Hello World bundle JavaScript file being highlighted.](../../../images/external-scripts-bundle-size.png) If you add another web part to your project that also uses Angular and you build the project, you get two bundle files, one for each web part, each of them being over 170 KB. -![Two bundle files highlighted in Explorer](../../../images/external-scripts-two-bundles-size.png) +![Screenshot of the File Explorer screen's deploy folder showing two Hello World bundle JavaScript files being highlighted.](../../../images/external-scripts-two-bundles-size.png) If you add these web parts to a page, each user would download Angular multiple times, once with each web part on the page. This approach is inefficient and slows down page load time. @@ -162,11 +161,11 @@ export default class HelloWorldWebPart extends BaseClientSideWebPart [!NOTE] > Before following the steps in this article, be sure to [set up your SharePoint client-side web part development environment](../../set-up-your-development-environment.md). @@ -40,21 +39,13 @@ You can download the [full source](https://github.com/SharePoint/sp-dev-fx-webpa 1. Enter the following values when prompted during the setup of the new project: - **spfx-pnp-js-example** as the solution name (keep default) + - **spfx-pnp-js-example description** as the solution description (keep default) - **SharePoint Online only (latest)** as the baseline packages version - - **Current Folder** as the solution location - - **Y** as allow tenant admin to deploy solution to all sites + - **N** to allow access to unique web APIs - **WebPart** as the component to create - **PnPJSExample** as the name of the web part - - **Example of using pnp-js within SPFx** as the description - - **Knockout** as the framework - - ![Completed Project Scaffolding](../../../images/sp-pnp-js-guide-completed-setup.png) - -1. After the scaffolding completes, lock down the version of the project dependencies by running the following command: - - ```console - npm shrinkwrap - ``` + - **PnPJSExample description** as the description + - **React** as the framework 1. Open the project in the code editor of your choosing. The screenshots shown here demonstrate [Visual Studio Code](https://code.visualstudio.com/). To open the directory within Visual Studio Code, enter the following in the console: @@ -64,307 +55,317 @@ You can download the [full source](https://github.com/SharePoint/sp-dev-fx-webpa ![Project as first opened in Visual Studio Code](../../../images/sp-pnp-js-guide-first-open.png) +1. Set up the location of your SharePoint-hosted workbench by modifying the `initialPage` value in the config/serve.json to point to your tenant/site. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json", + "port": 4321, + "https": true, + "initialPage": "https://{your tenant name}/sites/dev/_layouts/15/workbench.aspx" +} +``` + ## Install and set up @pnp/sp -After your project is created, you must install and set up @pnp/sp , starting with installing the package. These steps are common for any project type (React, etc). +After your project is created, you must install and set up **@pnp/sp** package. In addition, we'll use the **@pnp/logging** extension, but that is optional. These steps are common for any project type (React, etc). ```console -npm install @pnp/logging @pnp/common @pnp/odata @pnp/sp --save +npm install @pnp/logging @pnp/sp --save ``` -Because the @pnp/sp library constructs REST requests, it needs to know the URL to send these requests. When operating within classic sites and pages, we can make use of the global `_spPageContextInfo` variable. Within SPFx, this is not available, or if it is, it may not be correct. So we need to rely on the [context](/javascript/api/sp-webpart-base/webpartcontext) object -supplied by the framework. +### For SPFx Version 1.14.x or those that aren't supporting typescript v4.x + +> [!NOTE] +> PnPjs version 3.x is only supported in SPFx v1.14 and higher and NodeJs v12.x and higher. + +1. Update the rush stack compiler to 4.2. This is covered in this [great article by Elio](https://www.eliostruyf.com/define-the-typescript-version-you-want-to-use-in-sharepoint-framework/), but the steps are listed below. + - Uninstall the existing rush stack compiler (replace the x with the version installed in your package.json file): + `npm uninstall @microsoft/rush-stack-compiler-3.x` + - Install 4.2 version: + `npm i @microsoft/rush-stack-compiler-4.2` + - Update tsconfig.json to extend the 4.2 config: + `"extends": "./node_modules/@microsoft/rush-stack-compiler-4.2/includes/tsconfig-web.json"` + +1. Replace the contents of the gulpfile.js with: + + ```javascript + 'use strict'; + + const build = require('@microsoft/sp-build-web'); -There are [two ways](https://pnp.github.io/pnpjs/sp/docs/#getting-started-sharepoint-framework) to ensure that you have correctly set up your requests; we use the `onInit` method in this example. + build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); + + var getTasks = build.rig.getTasks; + build.rig.getTasks = function () { + var result = getTasks.call(build.rig); + + result.set('serve', result.get('serve-deprecated')); + + return result; + }; + + // ********* ADDED ******* + // disable tslint + build.tslintCmd.enabled = false; + // ********* ADDED ******* + + build.initialize(require('gulp')); + ``` ### Update onInit in PnPjsExampleWebPart.ts -1. Open the **src\webparts\spPnPjsExample\SpPnPjsExampleWebPart.ts** file, and add an import statement for the pnp root object: +Because the **@pnp/sp** library constructs REST requests, it needs to know the URL to send these requests. When operating within SPFx, we need to rely on the [context](/javascript/api/sp-webpart-base/webpartcontext) object supplied by the framework. + +There are [two ways](https://pnp.github.io/pnpjs/getting-started) to ensure that you have correctly set up your requests; we use the `onInit` method in this example. + +1. Open the **src\webparts\spPnPjsExample\SpPnPjsExampleWebPart.ts** file, and add an import statement for the PnP project configuration file (more on this file below): ```typescript - import { sp } from "@pnp/sp"; + import { getSP } from './pnpjsConfig'; ``` -1. In the `onInit()` method, update the code to appear as follows. Add the block after the `super.onInit()` call. We do this after the `super.onInit()` to ensure that the framework has a chance to initialize anything required, and that we are setting up the library after those steps are completed. +1. In the `onInit()` method, update the code to appear as follows. Add the call to initialize our project configuration after the `super.onInit()` call. We do this after the `super.onInit()` to ensure that the framework has a chance to initialize anything required and that we are setting up the library after those steps are completed. ```typescript /** * Initialize the web part. */ - protected onInit(): Promise { - this._id = _instance++; + public async onInit(): Promise { + this._environmentMessage = this._getEnvironmentMessage(); - const tagName: string = `ComponentElement-${this._id}`; - this._componentElement = this._createComponentElement(tagName); - this._registerComponent(tagName); + await super.onInit(); - // When web part description is changed, notify view model to update. - this._koDescription.subscribe((newValue: string) => { - this._shouter.notifySubscribers(newValue, 'description'); - }); + //Initialize our _sp object that we can then use in other packages without having to pass around the context. + // Check out pnpjsConfig.ts for an example of a project setup file. + getSP(this.context); + } - const bindings: IPnPjsExampleBindingContext = { - description: this.properties.description, - shouter: this._shouter - }; + ``` - ko.applyBindings(bindings, this._componentElement); +## Add a project configuration file - sp.setup({ - spfxContext: this.context - }); +Next, let's create a project configuration file for PnPjs. This file allows us to set up the imports we will need for the project as well as initialize an instance of the sp object for use on any of our other components. - // optional, we are setting up the @pnp/logging for debugging - Logger.activeLogLevel = LogLevel.Info; - Logger.subscribe(new ConsoleListener()); +Note all the imports for webs, lists, items, and batching. In our component we will be making calls to get items from a library, so we need to include those imports for future reference. In addition, we create a variable that will hold our configured instance of the `SharePoint Querable` that will be created with the factory instance. If you'll recall from our `onInit` function above we're calling the exported getSP with the SPFx context passed in as a property. By doing so we're able to establish context with the PnPjs library so that we can subsequently make calls to the SharePoint API. Subsequent calls to `getSP` without the context will return the object that has already been configured. - return super.onInit(); - } - ``` - -## Update the ViewModel +This sample also shows how we can add an additional `behavior` to the instance which enables logging for all the calls. This will use the default logging but we could expand to include our own logging functions. -Next, replace the contents of the **PnPjsExampleViewModel.ts** file with the following code. We added an import statement for the pnp items, an interface to define our list item's fields, some observables to track both our list of items and the new item form, and methods to support getting, adding, and deleting items. +```typescript +import { WebPartContext } from "@microsoft/sp-webpart-base"; + +// import pnp and pnp logging system +import { spfi, SPFI, SPFx } from "@pnp/sp"; +import { LogLevel, PnPLogging } from "@pnp/logging"; +import "@pnp/sp/webs"; +import "@pnp/sp/lists"; +import "@pnp/sp/items"; +import "@pnp/sp/batching"; + +var _sp: SPFI | null = null; + +export const getSP = (context?: WebPartContext): SPFI => { + if (context != null) { + //You must add the @pnp/logging package to include the PnPLogging behavior it is no longer a peer dependency + // The LogLevel set's at what level a message will be written to the console + _sp = spfi().using(SPFx(context)).using(PnPLogging(LogLevel.Warning)); + } + return _sp!; +}; +``` -We also added an `ensureList()` method, which uses the @pnp/sp `lists.ensure()` method to always ensure that we have the list (and to create it if necessary). There are many ways to provision resources, but this method was chosen to demonstrate creating a list, field, and items by using batching within a single method. +## Add an interface file for the data model -The takeaway is that by using @pnp/sp, we write much less code to handle requests and can focus on our business logic. +Add a new file in the root of the components folder called **interfaces.ts**. Replace the contents with the following definitions which will be referenced by our component. ```typescript -import * as ko from 'knockout'; -import styles from './PnPjsExample.module.scss'; -import { IPnPjsExampleWebPartProps } from './PnPjsExampleWebPart'; -require("tslib"); -require("@pnp/logging"); -require("@pnp/common"); -require("@pnp/odata"); -import { sp, List, ListEnsureResult, ItemAddResult, FieldAddResult } from "@pnp/sp"; - -export interface IPnPjsExampleBindingContext extends IPnPjsExampleWebPartProps { - shouter: KnockoutSubscribable<{}>; +// create File item to work with it internally +export interface IFile { + Id: number; + Title: string; + Name: string; + Size: number; +} + +// create PnP JS response interface for File +export interface IResponseFile { + Length: number; } -/** - * Interface which defines the fields in our list items - */ -export interface OrderListItem { +// create PnP JS response interface for Item +export interface IResponseItem { Id: number; + File: IResponseFile; + FileLeafRef: string; Title: string; - OrderNumber: string; } +``` -export default class PnPjsExampleViewModel { - public description: KnockoutObservable = ko.observable(''); - public newItemTitle: KnockoutObservable = ko.observable(''); - public newItemNumber: KnockoutObservable = ko.observable(''); - public items: KnockoutObservableArray = ko.observableArray([]); - - public labelClass: string = styles.label; - public helloWorldClass: string = styles.pnPjsExample; - public containerClass: string = styles.container; - public rowClass: string = `ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`; - public buttonClass: string = `ms-Button ${styles.button}`; +## Update the default component - constructor(bindings: IPnPjsExampleBindingContext) { - this.description(bindings.description); +Finally, we need to do a bit of cleanup to create our base component. First, replace the entire contents of the **PnPjsExample.tsx** file with the following code. - // When web part description is updated, change this view model's description. - bindings.shouter.subscribe((value: string) => { - this.description(value); - }, this, 'description'); +```typescript +import * as React from 'react'; +import styles from './PnPjsExample.module.scss'; +import { IPnPjsExampleProps } from './IPnPjsExampleProps'; - // call the load the items - this.getItems().then(items => { +// import interfaces +import { IFile, IResponseItem } from "./interfaces"; - this.items(items); - }); - } +import { Caching } from "@pnp/queryable"; +import { getSP } from "../pnpjsConfig"; +import { SPFI, spfi } from "@pnp/sp"; +import { Logger, LogLevel } from "@pnp/logging"; +import { IItemUpdateResult } from "@pnp/sp/items"; +import { Label, PrimaryButton } from '@microsoft/office-ui-fabric-react-bundle'; - /** - * Gets the items from the list - */ - private getItems(): Promise { +export interface IAsyncAwaitPnPJsProps { + description: string; +} - return this.ensureList().then(list => { +export interface IIPnPjsExampleState { + items: IFile[]; + errors: string[]; +} - // here we are using the getAs operator so that our returned value will be typed - return list.items.select("Id", "Title", "OrderNumber").get(); - }); +export default class PnPjsExample extends React.Component { + private LOG_SOURCE = "🅿PnPjsExample"; + private LIBRARY_NAME = "Documents"; + private _sp: SPFI; + + constructor(props: IPnPjsExampleProps) { + super(props); + // set initial state + this.state = { + items: [], + errors: [] + }; + this._sp = getSP(); } - /** - * Adds an item to the list - */ - public addItem(): void { - - if (this.newItemTitle() !== "" && this.newItemNumber() !== "") { - - this.ensureList().then(list => { - - // add the new item to the SharePoint list - list.items.add({ - Title: this.newItemTitle(), - OrderNumber: this.newItemNumber(), - }).then((iar: ItemAddResult) => { - - // add the new item to the display - this.items.push({ - Id: iar.data.Id, - OrderNumber: iar.data.OrderNumber, - Title: iar.data.Title, - }); + public componentDidMount(): void { + // read all file sizes from Documents library + this._readAllFilesSize(); + } - // clear the form - this.newItemTitle(""); - this.newItemNumber(""); - }); - }); - } + public render(): React.ReactElement { + // calculate total of file sizes + const totalDocs: number = this.state.items.length > 0 + ? this.state.items.reduce((acc: number, item: IFile) => { + return (acc + Number(item.Size)); + }, 0) + : 0; + return ( +
    + + Update Item Titles + + + + + + + + {this.state.items.map((item, idx) => { + return ( + + + + + + ); + })} + + + + + +
    TitleNameSize (KB)
    {item.Title}{item.Name}{(item.Size / 1024).toFixed(2)}
    Total:{(totalDocs / 1024).toFixed(2)}
    +
    + ); } - /** - * Deletes an item from the list - */ - public deleteItem(data): void { - - if (confirm("Are you sure you want to delete this item?")) { - this.ensureList().then(list => { - list.items.getById(data.Id).delete().then(_ => { - this.items.remove(data); - }); - }).catch((e: Error) => { - alert(`There was an error deleting the item ${e.message}`); + private _readAllFilesSize = async (): Promise => { + try { + // do PnP JS query, some notes: + // - .expand() method will retrive Item.File item but only Length property + // - .get() always returns a promise + // - await resolves promises making your code act synchronous, ergo Promise becomes IResponse[] + + //Extending our sp object to include caching behavior, this modification will add caching to the sp object itself + //this._sp.using(Caching({store:"session"})); + + //Creating a new sp object to include caching behavior. This way our original object is unchanged. + const spCache = spfi(this._sp).using(Caching({store:"session"})); + + const response: IResponseItem[] = await spCache.web.lists + .getByTitle(this.LIBRARY_NAME) + .items + .select("Id", "Title", "FileLeafRef", "File/Length") + .expand("File/Length")(); + + // use map to convert IResponseItem[] into our internal object IFile[] + const items: IFile[] = response.map((item: IResponseItem) => { + return { + Id: item.Id, + Title: item.Title || "Unknown", + Size: item.File?.Length || 0, + Name: item.FileLeafRef + }; }); + + // Add the items to the state + this.setState({ items }); + } catch (err) { + Logger.write(`${this.LOG_SOURCE} (_readAllFilesSize) - ${JSON.stringify(err)} - `, LogLevel.Error); } } - /** - * Ensures the list exists and if it creates it adds some default example data - */ - private ensureList(): Promise { - - return new Promise((resolve, reject) => { - - // use lists.ensure to always have the list available - sp.web.lists.ensure("SPPnPJSExampleList").then((ler: ListEnsureResult) => { - - if (ler.created) { - - // we created the list on this call so let's add a column - ler.list.fields.addText("OrderNumber").then(_ => { - - // and we will also add a few items so we can see some example data - // here we use batching - - // create a batch - let batch = sp.web.createBatch(); - - ler.list.getListItemEntityTypeFullName().then(typeName => { - - ler.list.items.inBatch(batch).add({ - Title: "Title 1", - OrderNumber: "4826492" - }, typeName); - - ler.list.items.inBatch(batch).add({ - Title: "Title 2", - OrderNumber: "828475" - }, typeName); - - ler.list.items.inBatch(batch).add({ - Title: "Title 3", - OrderNumber: "75638923" - }, typeName); - - // excute the batched operations - batch.execute().then(_ => { - // all of the items have been added within the batch - - resolve(ler.list); - - }).catch(e => reject(e)); - - }).catch(e => reject(e)); - - }).catch(e => reject(e)); - - } else { - - resolve(ler.list); - } + private _updateTitles = async (): Promise => { + try { + //Will create a batch call that will update the title of each item + // in the library by adding `-Updated` to the end. + const [batchedSP, execute] = this._sp.batched(); + + //Clone items from the state + const items = JSON.parse(JSON.stringify(this.state.items)); + + let res: IItemUpdateResult[] = []; + + for (let i = 0; i < items.length; i++) { + // you need to use .then syntax here as otherwise the application will stop and await the result + batchedSP.web.lists + .getByTitle(this.LIBRARY_NAME) + .items + .getById(items[i].Id) + .update({ Title: `${items[i].Name}-Updated` }) + .then(r => res.push(r)); + } + // Executes the batched calls + await execute(); + + // Results for all batched calls are available + for (let i = 0; i < res.length; i++) { + //If the result is successful update the item + //NOTE: This code is over simplified, you need to make sure the Id's match + const item = await res[i].item.select("Id, Title")<{ Id: number, Title: string }>(); + items[i].Name = item.Title; + } - }).catch(e => reject(e)); - }); + //Update the state which rerenders the component + this.setState({ items }); + } catch (err) { + Logger.write(`${this.LOG_SOURCE} (_updateTitles) - ${JSON.stringify(err)} - `, LogLevel.Error); + } } } ``` -## Update the template - -Finally, we need to update the template to match the functionality that we added into the ViewModel. Copy the following code into the **PnPjsExample.template.html** file. We added a title row, a `foreach` repeater for the items collection, and a form allowing you to add new items to the list. - -```html -
    -
    - -
    -
    - -
    -
    - -
    -
    - Title -
    -
    - Order Number -
    -
    - - -
    -
    - -
    -
    - -
    -
    - -
    -
    - - -
    -
    - Add New -
    -
    - -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    -``` - ## Run the example -Start the sample, and add the web part to your SharePoint-hosted Workbench (/_layouts/workbench.aspx) to see it in action. +Start the sample, and add the web part to your SharePoint-hosted Workbench (**/_layouts/15/workbench.aspx**) to see it in action. ```console gulp serve --nobrowser @@ -376,196 +377,10 @@ You can delete existing items by selecting the trashcan icon, or you can add new ### Next steps -The @pnp/sp library contains a great range of functionality and extensibility. For samples, guidance, and hints about using and configuring the library, see the [Developer Guide](https://pnp.github.io/pnpjs/documentation/getting-started/). - -## Deploy to production - -When you are ready to deploy your solution and want to build by using the `--ship` flag, you need to mark @pnp/sp as an external library in the configuration. This is done by updating the SPFx **config/config.js** file to include these lines in the externals section: - -```json -"externals": { - "tslib": { - "path": "https://cdnjs.cloudflare.com/ajax/libs/tslib/1.9.3/tslib.min.js", - "globalName": "tslib" - }, - "@pnp/common": { - "path": "https://cdnjs.cloudflare.com/ajax/libs/pnp-common/1.2.5/common.es5.umd.bundle.min.js", - "globalName": "pnp.common" - }, - "@pnp/logging": { - "path": "https://cdnjs.cloudflare.com/ajax/libs/pnp-logging/1.2.5/logging.es5.umd.min.js", - "globalName": "pnp.logging", - "globalDependencies": [ - "tslib" - ] - }, - "@pnp/odata": { - "path": "https://cdnjs.cloudflare.com/ajax/libs/pnp-odata/1.2.5/odata.es5.umd.min.js", - "globalName": "pnp.odata", - "globalDependencies": [ - "@pnp/common", - "@pnp/logging", - "tslib" - ] - }, - "@pnp/sp": { - "path": "https://cdnjs.cloudflare.com/ajax/libs/pnp-sp/1.2.5/sp.es5.umd.min.js", - "globalName": "pnp.sp", - "globalDependencies": [ - "@pnp/logging", - "@pnp/common", - "@pnp/odata", - "tslib" - ] - } - }, -``` - -In this configuration, we use the public CDN, but the URL can be an internal path or any other location you would like to use. Be sure, however, to update the version number in the URL to match the version you are targeting. - -## Improve the mock data example - -Ideally, the sample should work within both the local Workbench as well as the SharePoint-hosted Workbench. To enable this, we need to mock our ViewModel and make an update to the web part code as outlined in the following sections. - -### Add mock ViewModel file - -Add a new file named **MockPnPjsExampleViewModel.ts** alongside the other web part files. Update the content of this file using the following code. This provides the same set of functionality and works in the local environment, but does not rely on SharePoint being available. - -```typescript -import * as ko from 'knockout'; -import styles from './PnPjsExample.module.scss'; -import { IPnPjsExampleBindingContext, OrderListItem } from './PnPjsExampleViewModel'; - -export default class MockPnPjsExampleViewModel { - public description: KnockoutObservable = ko.observable(''); - public newItemTitle: KnockoutObservable = ko.observable(''); - public newItemNumber: KnockoutObservable = ko.observable(''); - public items: KnockoutObservableArray = ko.observableArray([]); - - public labelClass: string = styles.label; - public helloWorldClass: string = styles.pnPjsExample; - public containerClass: string = styles.container; - public rowClass: string = `ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`; - public buttonClass: string = `ms-Button ${styles.button}`; - - constructor(bindings: IPnPjsExampleBindingContext) { - this.description(bindings.description); - - // When web part description is updated, change this view model's description. - bindings.shouter.subscribe((value: string) => { - this.description(value); - }, this, 'description'); - - // call the load the items - this.getItems().then(items => { - this.items(items); - }); - } - - /** - * Gets the items from the list - */ - private getItems(): Promise { - return Promise.resolve([{ - Id: 1, - Title: "Mock Item 1", - OrderNumber: "12345" - }, - { - Id: 2, - Title: "Mock Item 2", - OrderNumber: "12345" - }, - { - Id: 3, - Title: "Mock Item 3", - OrderNumber: "12345" - }]); - } - - /** - * Adds an item to the list - */ - public addItem(): void { - if (this.newItemTitle() !== "" && this.newItemNumber() !== "") { - // add the new item to the display - this.items.push({ - Id: this.items.length, - OrderNumber: this.newItemNumber(), - Title: this.newItemTitle(), - }); - - // clear the form - this.newItemTitle(""); - this.newItemNumber(""); - } - } - - /** - * Deletes an item from the list - */ - public deleteItem(data): void { - if (confirm("Are you sure you want to delete this item?")) { - this.items.remove(data); - } - } -} -``` - -### Update web part - -Finally, we need to update the web part to use the mock data when appropriate. - -1. Open the **PnPjsExampleWebPart.ts** file, and import the mock ViewModel web just created: - - ```typescript - import MockSpPnPjsExampleViewModel from './MockPnPjsExampleViewModel'; - ``` - -1. Import the `Environment` and `EnvironmentType` types that you use to detect the type of -environment the web part is running in: - - ```typescript - import { Version, Environment, EnvironmentType } from '@microsoft/sp-core-library'; - ``` - -1. Locate the `_registerComponent` method and update it as shown: - - ```typescript - private _registerComponent(tagName: string): void { - if (Environment.type === EnvironmentType.Local) { - console.log("here I am.") - ko.components.register( - tagName, - { - viewModel: MockSpPnPjsExampleViewModel, - template: require('./PnPjsExample.template.html'), - synchronous: false - } - ); - } else { - ko.components.register( - tagName, - { - viewModel: PnPjsExampleViewModel, - template: require('./PnPjsExample.template.html'), - synchronous: false - } - ); - } - } - ``` - -1. Type **gulp serve** in the console to bring up the local Workbench, which now works with the mock data. (If you already have the server running, stop it by selecting Ctrl+C, and then restart it): - - ```console - gulp serve - ``` - - ![Project as it appears running in the local workbench with mock data](../../../images/sp-pnp-js-guide-with-mock-data.png) +The **@pnp/sp** library contains a great range of functionality and extensibility. For samples, guidance, and hints about using and configuring the library, see the [Developer Guide](https://pnp.github.io/pnpjs/getting-started). ## See also -- [Download the full sample](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/knockout-sp-pnp-js) +- [Download the full sample](https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-pnp-js-sample) - [Provide feedback or report issues](https://github.com/SharePoint/PnP-JS-Core/issues) - [SharePoint Framework Overview](../../sharepoint-framework-overview.md) diff --git a/docs/spfx/web-parts/guidance/validate-web-part-property-values.md b/docs/spfx/web-parts/guidance/validate-web-part-property-values.md index 248b7994d..71ac9350b 100644 --- a/docs/spfx/web-parts/guidance/validate-web-part-property-values.md +++ b/docs/spfx/web-parts/guidance/validate-web-part-property-values.md @@ -1,9 +1,8 @@ --- title: Validate web part property values description: Validate property values in SharePoint Framework client-side web parts by validating the value directly inside a web part's code, or by calling an external API. -ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 02/11/2022 +ms.localizationpriority: high --- # Validate web part property values @@ -36,10 +35,8 @@ When working with SharePoint Framework client-side web parts, users can configur 1. When prompted, enter the following values (*select the default option for all prompts omitted below*): - **What is your solution name?**: react-listinfo - - **Where do you want to place the files?**: Use the current folder - **What is your Web part name?**: List info - - **What is your Web part description?**: Shows information about the selected list - - **Which framework would you like to use?**: No JavaScript framework + - **Which template would you like to use?**: No JavaScript framework 1. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer. @@ -355,7 +352,7 @@ In this step, you validate the provided list name and check if it corresponds to 1. Add the web part to the canvas and open its properties. Because you haven't specified a default value for the list name, which is a required property, you see a validation error. - ![Validation error displayed on a required property without a value specified](../../../images/property-validation-empty-list-name-error.png) + ![Validation error displayed on a required property (last name) without a value specified](../../../images/property-validation-empty-list-name-error.png) If you provide the name of a list that doesn't exist, the web part displays a validation error stating that the list you specified doesn't exist in the current site. @@ -369,8 +366,6 @@ In this step, you validate the provided list name and check if it corresponds to When validating web part properties using remote APIs, SharePoint Framework monitors changes in the property pane controls and sends updated values for validation to the specified validation handler. By default, the SharePoint Framework waits 200 ms before triggering the validation process. If the user hasn't changed the particular value for 200 ms, the SharePoint Framework starts the validation process. When the validation handler uses a remote API, each time the validation process starts, that method issues a web request to the API to validate the specified value. If users don't type fast enough, this results in partially completed values being sent over for validation, unnecessarily stressing the network and the API. In such cases, you should consider increasing the validation delay. -![Network tools in Microsoft Edge showing web requests with partial list name being sent over for validation](../../../images/property-validation-partial-list-name-validation.png) - You can configure the validation delay for each property separately, depending on the type of value that users need to provide. #### Increase the validation delay for the `listName` property diff --git a/docs/spfx/web-parts/isolated-web-parts-retirement.md b/docs/spfx/web-parts/isolated-web-parts-retirement.md new file mode 100644 index 000000000..ea9ed4c74 --- /dev/null +++ b/docs/spfx/web-parts/isolated-web-parts-retirement.md @@ -0,0 +1,205 @@ +--- +title: Isolated web parts retirement +description: All datails on the domain isolated web parts retirement +ms.date: 04/23/2024 +ms.localizationpriority: high +--- + +# Retiring SharePoint Framework domain isolated web parts for SharePoint Online + +After careful consideration and extensive review of usage data and feedback we’ve decided to announce the retirement of the domain isolated web parts feature in SharePoint Framework (SPFx). As of April 2nd, 2026 domain isolated web parts will be fully retired and stop working for existing tenants. If tenants are still using domain isolated web parts then they’ll see the web part render and error message and stop functioning. New tenants onboarding from April 2nd, 2025 will not be able to use domain isolated web parts. This applies to all environments including Government Clouds and Department of Defense. There will not be an option to extend domain isolated web parts beyond April 2, 2026. + +We apologize for any inconvenience this may cause, but we believe this is the best decision for the future of SPFx and SharePoint. + +## Timeline + +Date | Action +-----|------- +April 2, 2025 | Domain isolated web parts will be turned off for newly created tenants. +April 2, 2026 | Domain isolated web parts will be turned off for existing tenants. + +## Overview + +Domain isolated web parts allow developers to create web parts that run in a separate domain from the host page, providing an additional layer of security and isolation. Due to the performance implications of running in dedicated domain we saw limited usage of this feature. + +To understand whether you have installed domain isolated web parts and granted permissions you can verify if the [SharePoint admin center API access page](/sharepoint/api-access) contains permissions listed under the “Isolated” grouping. + +![SharePoint admin center showing the permissions granted for domain isolated web parts](../../images/discoverdomainisolatedwebpartusage.png) + +If you see permissions listed under **Isolated** then use the instructions below to understand more about the deployed domain isolated web parts. This script will create two CSV files: + +- **Solutions.csv**: this file contains an overview of the solutions that contain domain isolated web parts +- **Pages.csv**: this file contains an entry per page holding one of the domain isolated web parts + +To use this script follow these steps: + +1. Copy PowerShell script file contents (end of this page) and save it as **Find-DomainIsolatedWebparts.ps1** on your local drive. +1. [Install PnP PowerShell](https://pnp.github.io/powershell/articles/installation.html) in case that is not yet available. +1. [Configure PnP PowerShell to authenticate with Microsoft Entra](https://pnp.github.io/powershell/articles/authentication.html#setting-up-access-to-your-own-azure-ad-app), preferably configure for using application permissions as that’s required to check for domain isolated web parts across the whole tenant. If you have a Microsoft Entra application configured with a cert and the SharePoint Sites.Read.All permission you can just use that, if not follow below guidance to create such an application. Replace the values between `<>` with relevant values for your tenant: + + ```PowerShell + Register-PnPAzureADApp -ApplicationName FindDomainIsolatedWebparts -Tenant -Store CurrentUser -SharePointApplicationPermissions "Sites.Read.All" -Username "" -Interactive + ``` + +1. Connect to your tenant app catalog using the client id and certificate. Replace the values between `<>` with relevant values for your tenant. If you don’t know your app catalog site URL you can connect to an arbitrary site in your tenant and then use **Get-PnPTenantAppCatalogUrl**: + + ```PowerShell + Connect-PnPOnline -ClientId <5be692c9-0a1a-4f07-b3e8-7b79f1582375> -Thumbprint -tenant + ``` + +1. Run the script to discover domain isolated web part usage: + + ```PowerShell + .\Find-DomainIsolatedWebparts.ps1 + ``` + +## Call to Action Guidance + +If you are using domain isolated web parts in your SPFx solutions, you will need to migrate them to regular web parts before April 2026. Otherwise, your web parts will stop working after that date. Microsoft is working on to be announced features that offer an alternative strategy for domain isolated web parts, but we strongly recommend to move away from domain isolated web parts. + +To migrate your web parts, you will need to switch the `isDomainIsolated` property from the **package-solution.json** file to false, increment the version and redeploy your solution. + +Next to that you also need to ensure that the permissions granted to the domain isolated web part, listed under the **Isolated** grouping in the **API access** page of SharePoint admin center, are now granted as **Organization-wide** permissions. Check the [Manage access to Microsoft Entra ID-secured APIs](/sharepoint/api-access?WT.mc_id=365AdminCSH_spo) article to learn more. + +## PowerShell script to discover domain isolated web part usage + +```PowerShell +<# +.Synopsis + + Detects solutions containing domain isolated web parts and the SharePoint pages holding those web parts. + You need to install a recent PnP PowerShell version (July 2023 or higher) to use this script. + + This script generates two CSV files in case domain isolated web parts are found: + - solutions.csv: contains the solutions with domain isolated web parts + - pages.csv: contains the pages holding the domain isolated web parts + + Optionally you can skip the search for pages with domain isolated web parts by using the -SkipPages parameter. + + This script uses search to find the relevant pages, so when you use Connect-PnPOnline with delegated permissions you can only see + the pages that the current account has access to. For a complete search use Connect-PnPOnline with application permissions. + +.Example + + Connect-PnPOnline https://contoso.sharepoint.com/sites/appcatalog -ClientId 0b6a3858-dbbb-489b-b63d-1905426222f8 -Tenant contoso.onmicrosoft.com -CertificatePath "c:\certificate.pfx" + Find-DomainIsolatedWebparts.ps1 -SkipPages $false + +.Notes + + Useful references: + - https://aka.ms/retirement/domainisolatedwebparts/support + - https://aka.ms/sppnp-powershell +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $false, HelpMessage = "Skip searching for pages with domain isolated web parts.")] + [bool]$SkipPages = $false +) +begin +{ + # Verify there's an app catalog and that we're connected to it + $appCatalog = Get-PnPTenantAppCatalogUrl + + if ($null -eq $appCatalog) + { + Write-Host "No app catalog found, exiting as there can't be any domain isolated web parts without a configured app catalog!" -ForegroundColor Green + exit + } + + if ($appCatalog -ne (Get-PnPConnection).Url.TrimEnd("/")) + { + Write-Host "You need to connect to your tenant app catalog first. Use Connect-PnPOnline to connect to $appCatalog" -ForegroundColor Red + exit + } +} +process +{ + # check for apps that use domain isolation + $solutionsWithDomainIsolatedWebParts = Get-PnPListItem -List AppCatalog -Query "" + + if ($null -eq $solutionsWithDomainIsolatedWebParts) + { + Write-Host "No domain isolated web parts found!" -ForegroundColor Green + exit + } + + $solutionsToExport = @() + $pagesToExport = @() + + if ($SkipPages -eq $false -and [string]::IsNullOrEmpty((Get-PnPConnection).Certificate.Thumbprint)) + { + Write-Host + Write-Host "WARNING: You'll be searching for pages containing domain isolated web parts using delegated permissions. Only the pages that the current account can access will be returned. For a complete search use Connect-PnPOnline with applicaiton permissions" -ForegroundColor Yellow + Write-Host + } + + # inspect the manifest to find the web part ids + foreach ($domainIsolatedSolution in $solutionsWithDomainIsolatedWebParts) { + + if ($domainIsolatedSolution.FieldValues.IsClientSideSolutionDeployed -eq $false) + { + Write-Host "Skipping solution ""$($domainIsolatedSolution.FieldValues.Title)"" as it is not deployed" -ForegroundColor Yellow + continue + } + + Write-Host "Solution ""$($domainIsolatedSolution.FieldValues.Title)"" contains domain isolated web parts!" -ForegroundColor Green + Write-Host "Inspecting solution ""$($domainIsolatedSolution.FieldValues.Title)"" with id $($domainIsolatedSolution.FieldValues.UniqueSolutionId)..." -ForegroundColor Green + + $solutionsToExport += [pscustomobject]@{ + 'Title' = $domainIsolatedSolution.FieldValues.Title; + 'Solution Id' = $domainIsolatedSolution.FieldValues.UniqueSolutionId; + 'Publisher' = $domainIsolatedSolution.FieldValues.AppPublisher; + 'Description' = $domainIsolatedSolution.FieldValues.AppShortDescription; + 'Version' = $domainIsolatedSolution.FieldValues.AppVersion; + 'Skip feature deployment' = $domainIsolatedSolution.FieldValues.SkipFeatureDeployment; + 'Isolated domain' = $domainIsolatedSolution.FieldValues.IsolatedDomain; + } + + if ($SkipPages -eq $true) + { + Write-Host "Skipping search for pages with domain isolated web parts" -ForegroundColor Yellow + continue + } + + $components = Get-PnPListItem -List "Lists/ComponentManifests" -Query "$($domainIsolatedSolution.FieldValues.UniqueSolutionId)" + + if ($null -ne $components) { + + foreach($component in $components) + { + Write-Host "Searching for pages using component: ""$($component.FieldValues.ClientComponentName)"" with id $($component.FieldValues.ClientComponentId)..." -ForegroundColor Blue + + #Perform a search to find the pages hosting these web parts + $pages = Submit-PnPSearchQuery -Query "FileExtension:aspx SPFxExtensionJson:$($component.FieldValues.ClientComponentId)" -All -RelevantResults | Select-Object SPWebUrl,OriginalPath + + if ($null -ne $pages) { + foreach($page in $pages) + { + Write-Host $page.OriginalPath + + $pagesToExport += [pscustomobject]@{ + 'Title' = $domainIsolatedSolution.FieldValues.Title; + 'Publisher' = $domainIsolatedSolution.FieldValues.AppPublisher; + 'Component' = $component.FieldValues.ClientComponentName; + 'Component Id' = $component.FieldValues.ClientComponentId; + 'Site' = $page.SPWebUrl; + 'Page' = $page.OriginalPath; + } + } + } + + Write-Host("-" * 40) -ForegroundColor Blue + } + } + } + + $solutionsToExport | Export-CSV "solutions.csv" -NoTypeInformation + + if ($SkipPages -eq $false) + { + $pagesToExport | Export-CSV "pages.csv" -NoTypeInformation + } + +} +``` diff --git a/docs/spfx/web-parts/isolated-web-parts.md b/docs/spfx/web-parts/isolated-web-parts.md index 8efa25dec..6d56723f3 100644 --- a/docs/spfx/web-parts/isolated-web-parts.md +++ b/docs/spfx/web-parts/isolated-web-parts.md @@ -1,15 +1,17 @@ --- title: Isolated web parts description: Overview of the isolated web parts capability in the SharePoint Framework -ms.date: 06/16/2020 -ms.prod: sharepoint -localization_priority: Priority +ms.date: 05/39/2024 +ms.localizationpriority: high --- # Isolated web parts Using this capability, you can build web parts that securely communicate with APIs secured with Azure AD without exposing the access token to other components on the page or even scripts in the tenant. +> [!IMPORTANT] +> The isolated web parts feature has been deprecated and will be retired as of April 2, 2026. Check the [retirement announcement](./isolated-web-parts-retirement.md) to learn more. + ## Why isolated web parts To allow your SharePoint Framework solutions to securely access APIs secured with Azure AD, you can use the API management to specify which APIs can be accessed by scripts in your tenant and with which permissions. Next, using the SharePoint Framework, you can easily retrieve an access token for the specific API. While it significantly simplifies communicating with APIs secured with Azure AD, it allows all scripts, not just specific SharePoint Framework solutions, to obtain an access token for any of the approved APIs. If one of the scripts you use in your tenant was exploited, then it could access any of the approved APIs on behalf of the current user. @@ -20,6 +22,8 @@ Isolated web parts introduce a new way to isolate access to APIs secured with Az > [!IMPORTANT] > The isolated web parts capability is available only in SharePoint Framework v1.8 and later. +> Isolated web parts are only supported on modern pages. While you might be able to add isolated web parts to classic pages, upon publishing, the web part will not render and generate an error. +> Isolated web parts can only be installed into the tenant app catalog. They will not work from a Site Collection app catalog. ![Architectural overview illustrating how isolated web parts work](../../images/isolated-web-parts.png) @@ -27,7 +31,7 @@ Solutions using the isolated web parts capability, have a specific flag set in t After approving an isolated API permission request, SharePoint will create a separate Azure AD application in the Azure AD linked to the Microsoft 365 tenant. This Azure AD application is specific to the SharePoint Framework solution that requested API permissions and will have set OAuth permissions as requested by that solution. The return URL of that Azure AD application, which is used by the OAuth implicit flow, will be set to a unique domain that is tied to that specific SharePoint Framework application. -All web parts from solutions using isolated permissions, when added to a page, will be displayed using an iframe pointing to a unique domain tied to the particular SharePoint Framework solution. This way, SharePoint Framework can enforce unique API permissions and ensure that no other solution or script in the tenant can obtain an access token to these APIs. +All web parts from solutions using isolated permissions, when added to a page, will be displayed using an `