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 b7e0be39b..f3522487f 100644 --- a/.openpublishing.publish.config.json +++ b/.openpublishing.publish.config.json @@ -24,8 +24,7 @@ ], "notification_subscribers": [ "vesaj@microsoft.com", - "bjansen@microsoft.com", - "v-licapu@microsoft.com" + "bjansen@microsoft.com" ], "sync_notification_subscribers": null, "branches_to_filter": [], @@ -81,4 +80,4 @@ "nuget_feed": "https://www.myget.org/F/op/api/v2" } ] -} \ No newline at end of file +} diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 8b520d9a1..78222f726 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -109,6 +109,166 @@ "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/README.md b/README.md index 8d22cc941..4e77f8fcb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 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. @@ -22,7 +22,6 @@ Review all the SPFx releases here from the [initial GA release in February 2017] * [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://learn.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview) 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/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/docs/apis/csom-methods-for-applying-retention-labels.md b/docs/apis/csom-methods-for-applying-retention-labels.md index 13155c12b..ddde1e391 100644 --- a/docs/apis/csom-methods-for-applying-retention-labels.md +++ b/docs/apis/csom-methods-for-applying-retention-labels.md @@ -1,18 +1,18 @@ --- -title: CSOM methods for applying retention labels -description: CSOM methods are available to apply (set) a retention label (ComplianceTag) on one or many items (ListItems) in SharePoint. +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: 4/18/2023 +ms.date: 9/30/2024 --- -# CSOM methods for applying retention labels (setting ComplianceTags) +# 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. Retention labels can be applied using this method without being published to the location by an existing label policy. +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 @@ -34,6 +34,93 @@ public List SetComplianceTagOnBulkItems( 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| diff --git a/docs/apis/export-amr-api.md b/docs/apis/export-amr-api.md index 82a13e719..fe7248b8f 100644 --- a/docs/apis/export-amr-api.md +++ b/docs/apis/export-amr-api.md @@ -1,7 +1,7 @@ --- title: "SharePoint Asynchronous Metadata Read (AMR) API Introduction" -description: This document is an overview on how to read metadata from SharePoint, targeted to SharePoint migration tool developers. -ms.date: 04/18/2024 +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 @@ -15,9 +15,9 @@ ms.collection: --- # SharePoint Asynchronous Metadata Read (AMR) API Introduction -The SharePoint Asynchronous Metadata Read (AMR) API asynchronously exports metadata from SharePoint and OneDrive. +The SharePoint Asynchronous Metadata Read (AMR) API enables the asynchronous export of metadata from SharePoint and OneDrive. -Use AMR API to export metadata from SharePoint, for incremental migration, and post-migration validation. +Use AMR API to export metadata from SharePoint for incremental migration and post-migration validation. 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. @@ -33,6 +33,11 @@ Export metadata from SharePoint in three steps: ### Provision the destination containers and the queue +> [!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. + 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. ### Use `CreateSPAsyncReadJob` method to start the export @@ -47,11 +52,16 @@ Check [AMR API Reference](amr-api-reference.md) for details. ### Checking status +> [!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. + Check Azure Queue supplied for export status. Monitor events as listed in [Events](migration-events.md) for details. -AMR API exports metadata in the manifest container supplied, under folder named by `JobID`. Check [Manifest files](migration-manifest.md) for the format and validation of the metadata. +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. -AMR API splits manifest package larger than 25 MB into multiple manifest files per request. +AMR API splits manifest packages larger than 25 MB into multiple manifest files per request. ## Best practice @@ -59,7 +69,7 @@ AMR API is powerful. Ensure good performance to achieve the scale for large migr ### Export security and permissions on top level if possible -Exporting security with `IncludeSecurity` consumes more resources and slows down the export. It's faster to export these metadata at upper-level folder first, then export the children without them. +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. ### Metadata export on a single item @@ -90,9 +100,9 @@ AMR API processes jobs through a queue mechanism with preconfigured workload man ### Lab-tested performance baseline -We tested the performance in 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. +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. -There are multiple factors that affect the real-life performance. These factors include: +Multiple factors affect real-life performance. These factors include: - The number of items that are being exported - The way AMR API is implemented @@ -108,6 +118,6 @@ To ensure good user experiences for all Microsoft 365 customers, SharePoint uses ### Tenant-to-Tenant migrations -AMR isn't intended for scenario 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. +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. Microsoft provides no performance guarantee in this scenario. Use Graph or CSOM as needed. diff --git a/docs/apis/migration-api-overview.md b/docs/apis/migration-api-overview.md index fb9b01168..d09416b7e 100644 --- a/docs/apis/migration-api-overview.md +++ b/docs/apis/migration-api-overview.md @@ -1,7 +1,7 @@ --- title: "SharePoint Import Migration API" -description: "This article provides overview information on how to use the SharePoint Migration API." -ms.date: 04/28/2024 +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 @@ -15,15 +15,27 @@ ms.collection: --- # SharePoint Migration API Introduction -The SharePoint Migration API imports contents 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 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. Use Migration API to migrate content from file shares, SharePoint Server, and other cloud-based services. ## What's new +### December 2024 + +We applied quota on *Share with Me* items per user. Check [ShareWithMe event quota](/sharepoint/dev/apis/migration-api-shared#quota) for more detail. + +### November 2024 + +We enabled logging all file-level events during migration, such as file deletion, to support auditing. + +### July 2024 + +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. + ### April 2024 -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. +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. ### January 2024 @@ -35,7 +47,12 @@ Start a migration job with three steps. Check the guidance in each of the steps ### Provision the destination containers and the queue -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. +> [!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 @@ -51,21 +68,26 @@ Check [Manifest files](migration-manifest.md) to see the detailed requirements. ### Use Migration API to start the migration and get status -`CreateMigrationJob` method creates a migration job, which is queued up for processing. Migration API manages the queue and returns status and logs. Use `CreateMigrationEncrypted` method to migrate encrypted contents. Check [SharePoint Migration API Reference](migration-api-reference.md) for details. +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. -Upon creation of a new migration job, Migration API returns the Job ID. Track the status of the import with `GetMigrationJobStatus` method if needed, with the Azure Queue supplied. +> [!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 SPO backend differently from end user-generated traffic. To properly allocate resources with our elastic capability, only use app-based authentication in your migration solution. +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. Don't use user mode in your migration solution. Running migration in user mode triggers increased throttling, resulting in poor performance. -To learn more on 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). +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). ### Microsoft Entra ID Permissions @@ -74,21 +96,21 @@ Permissions and consent in the Azure Active Directory v1.0 endpoint](/azure/acti For SharePoint and OneDrive migration scenarios, follow the Microsoft Entra ID permission specification. -For migration tools that rely on end-user signed in and presence, use Delegated permission. +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 individual App ID for each of the products. Make sure to register App IDs. Sharing App IDs doesn't affect performance or throttling. +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 SPO site unactivated +### Keep destination SharePoint Site unactivated -To avoid migration issues, deactivate the target site for users until the migration completion. The source could remain active, allowing read and write to keep productivity. Switch users to the new SPO destination sites after migration completion. +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. ## Performance -Migration API processes jobs through a queue mechanism with pre-configured workload management settings. Migration API processes the jobs on a best-effort basis, without Service Level Agreement (SLA) or guaranteed performance. +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. ### Optimize migration performance @@ -96,9 +118,9 @@ In order to ensure optimal performance for your migration projects, it's importa ### I'm seeing throttling messages -To ensure good user experiences for all Microsoft 365 customers, SharePoint uses throttling to protect the SharePoint Online infrastructure. Avoid getting throttled by following [throttling guidance](https://aka.ms/spo429). +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). -## Special topics +## Special articles ### Migrating sharing events of files and folders @@ -106,4 +128,4 @@ Check [Sharing events](/sharepoint/dev/apis/migration-api-shared) article for in ### Web Parts -Use 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. +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 index af1850f71..0db09f400 100644 --- a/docs/apis/migration-api-reference.md +++ b/docs/apis/migration-api-reference.md @@ -1,7 +1,7 @@ --- title: "SharePoint Migration API Reference Guide" description: "This article provides in-depth information on how to use the SharePoint Migration API." -ms.date: 04/28/2024 +ms.date: 07/16/2025 ms.author: ranren author: underreview manager: dapodean @@ -74,9 +74,11 @@ 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 [Azure](migration-azure.md) for instructions on using Azure Blob Storage Containers in migration. +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. -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. +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 @@ -84,9 +86,9 @@ 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 [Azure](migration-azure.md) for instructions on using Azure Blob Storage Containers in migration. +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. -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. +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 @@ -170,6 +172,9 @@ 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. diff --git a/docs/apis/migration-api-shared.md b/docs/apis/migration-api-shared.md index 42aa9660d..dfcc26fd9 100644 --- a/docs/apis/migration-api-shared.md +++ b/docs/apis/migration-api-shared.md @@ -2,9 +2,9 @@ title: "SPO Migration API: Migrating shared files and folders" description: "Migrating shared files and folders using item references." ms.date: 06/28/2022 -ms.author: jhendr -author: JoanneHendrickson -manager: pamgreen +ms.author: jihongzuo +author: shiongzuo +manager: Dan.Podeanu ms.topic: article ms.subservice: migration-tool --- @@ -34,26 +34,32 @@ Add a SharedWithMember block for each person that the item was shared with durin - ``` + ## 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. +**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). @@ -61,7 +67,8 @@ Before starting migration, you must ensure all users are provisioned in the cust 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. @@ -71,3 +78,7 @@ Permissions migration is performed using the DeploymentRoleAssignments object wi > [!NOTE] > The **Migration API** is not available for users of Office 365 operated by 21Vianet in China. + +### Quota + +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-azure.md b/docs/apis/migration-azure.md index b22a2e17f..3dddc87b8 100644 --- a/docs/apis/migration-azure.md +++ b/docs/apis/migration-azure.md @@ -1,7 +1,7 @@ --- 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: 04/18/2024 +ms.date: 07/03/2024 ms.author: ranren author: underreview manager: dapodean @@ -32,9 +32,9 @@ Migration API provisions the containers in the same datacenter of the SharePoint Migration API destroys Used containers 30-90 days after completing migration jobs. -#### Decorate the traffic to avoid throttling +#### Avoid throttling by decorating the traffic -[Decorate your HTTP traffic](/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online#how-to-decorate-your-http-traffic) to avoid throttling. +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 @@ -74,12 +74,20 @@ A **Uri** value containing the URI of the newly created container for storing mi 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. @@ -96,11 +104,11 @@ Migration API provisions Azure Queues in the same datacenter of the SharePoint i Alternatively, use user-provided Azure Queues if desired. Check the requirement in the Migration API Reference document. -### Encryption +### Azure Queue Encryption -When using `CreateMigrationJobEncrypted` method, Migration API encrypts the messages written to the Azure Queue. +`CreateMigrationJobEncrypted` method encrypts the messages written to the Azure Queue. -Make sure you preserve `JobId` and the `IV` values returned by `CreateMigrationJobEncrypted` method, to decrypt the message. +To decrypt the messages, make sure you preserve `JobId` and the `IV` values returned by `CreateMigrationJobEncrypted` method. #### Encrypted message sample @@ -115,7 +123,7 @@ Make sure you preserve `JobId` and the `IV` values returned by `CreateMigrationJ Provisions a new instance of Azure Queue for migration use. -#### Syntax +#### ProvisionMigrationQueue Syntax ```csharp public SPProvisionedMigrationQueueInfo ProvisionMigrationQueue() 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/site-creation-rest.md b/docs/apis/site-creation-rest.md index 8988e7ec6..530ad6137 100644 --- a/docs/apis/site-creation-rest.md +++ b/docs/apis/site-creation-rest.md @@ -62,7 +62,7 @@ body: 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` diff --git a/docs/apis/syntex/syntex-model-rest-api.md b/docs/apis/syntex/syntex-model-rest-api.md index 746de3421..277c633dd 100644 --- a/docs/apis/syntex/syntex-model-rest-api.md +++ b/docs/apis/syntex/syntex-model-rest-api.md @@ -1,7 +1,7 @@ --- -title: Microsoft Syntex document understanding model REST API -description: Overview of the Microsoft Syntex document understanding model REST API. -ms.date: 10/20/2022 +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 @@ -12,7 +12,7 @@ ms.collection: m365initiative-syntex ms.localizationpriority: medium --- -# Microsoft Syntex unstructured document processing model REST API +# 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. @@ -29,14 +29,14 @@ Before you get started, make sure that you're familiar with the following: ## REST commands -The following REST commands are available for working with Syntex unstructured document processing models: +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 a Syntex unstructured document processing model. -- [GetByTitle](rest-getbytitle-method.md) – Gets or updates information about a Syntex unstructured document processing model using the model title. +- [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 a Syntex unstructured document processing model. +- [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. 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 eb8812dbc..967d0e43d 100644 --- a/docs/apis/webhooks/sharepoint-webhooks-using-azure-functions.md +++ b/docs/apis/webhooks/sharepoint-webhooks-using-azure-functions.md @@ -6,7 +6,9 @@ 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 diff --git a/docs/apis/webhooks/webhooks-reference-implementation.md b/docs/apis/webhooks/webhooks-reference-implementation.md index ea182d43c..f6285aaf7 100644 --- a/docs/apis/webhooks/webhooks-reference-implementation.md +++ b/docs/apis/webhooks/webhooks-reference-implementation.md @@ -1,7 +1,7 @@ --- 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: 09/23/2022 +ms.date: 06/05/2024 ms.localizationpriority: high --- # SharePoint webhooks sample reference implementation @@ -10,19 +10,16 @@ The SharePoint Patterns and Practices (PnP) reference implementation shows how y 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 Microsoft 365 Platform Communtiy (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 SharePoint webhooks. 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). @@ -35,9 +32,7 @@ The application shows you how to manage webhooks, specifically for a SharePoint ### Deployment guides - 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 @@ -48,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. @@ -74,8 +69,6 @@ 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: ```csharp @@ -89,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 ", ""); } ``` @@ -123,7 +116,6 @@ To avoid getting the same change repeatedly, it's important that you inform Shar 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 @@ -157,7 +149,7 @@ Create a web job that on a weekly basis reads all the subscription IDs from the > [!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. @@ -176,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... } ``` @@ -184,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/power-automate/guidance/require-doc-approval.md b/docs/business-apps/power-automate/guidance/require-doc-approval.md index 3dd73b2d9..c5c548834 100644 --- a/docs/business-apps/power-automate/guidance/require-doc-approval.md +++ b/docs/business-apps/power-automate/guidance/require-doc-approval.md @@ -84,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: 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 37de3fa89..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 @@ -16,6 +16,8 @@ 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 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 6ee0cea7a..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,7 +1,7 @@ --- title: Microsoft SharePoint Connector for Power Automate description: In Power Automate, Microsoft SharePoint Connector supports the following flow triggers and actions. -ms.date: 06/22/2023 +ms.date: 10/23/2024 ms.service: power-automate search.app: - Flow @@ -32,7 +32,7 @@ For more info about how to use this trigger, see this tutorial video: [Introduci ### 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 @@ -59,7 +59,7 @@ Triggers the flow when you create a file in a SharePoint folder. This trigger do ### 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. 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. +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 [deprecated] @@ -70,7 +70,7 @@ Triggers when a file is created, and also each time it is modified in a SharePoi ### 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 expected 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 diff --git a/docs/community/open-source-projects.md b/docs/community/open-source-projects.md index 3d7c4f2e2..e3f81365e 100644 --- a/docs/community/open-source-projects.md +++ b/docs/community/open-source-projects.md @@ -12,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://lookbook.microsoft.com/service-description) 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/declarative-customization/formatting-advanced.md b/docs/declarative-customization/formatting-advanced.md index ad197c1d9..5a4d79813 100644 --- a/docs/declarative-customization/formatting-advanced.md +++ b/docs/declarative-customization/formatting-advanced.md @@ -1,12 +1,12 @@ --- title: Advanced formatting concepts description: Advanced formatting concepts -ms.date: 08/24/2022 +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 interactable. +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 @@ -14,7 +14,7 @@ The following screenshot shows a list with a Flow button added to the Action col ![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 choosing the button and the Flow will just run. +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. @@ -30,43 +30,44 @@ To obtain the ID of a flow that is solution-aware: To obtain the ID of a flow that isn't solution-aware: -1. Select **Flow > See your flows** in the SharePoint list where the Flow is configured. +1. Switch to the environment in which the Flow is hosted. 1. Select the Flow you want to run. -1. Copy the ID from the end of the URL. +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": [ + ```JSON { - "elmType": "span", + "$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": { - "iconName": "Flow" + "class": "ms-fontColor-themePrimary ms-fontColor-themeDarker--hover" }, "style": { - "padding-right": "6px" - } - }, - { - "elmType": "span", - "txtContent": "Send to Manager" + "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. @@ -82,9 +83,9 @@ On hover - Metadata on the column "Status" is made available in column formattin ![Preview Image 2](../images/HoverImage-2.png) -You can use formatting to define custom call out that can be commissioned basis user-defined actions like click or hover. +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`: +This example uses `customCardProps`, `openOnEvent`, `directionalHint`, and `isBeakVisible`: ```JSON { @@ -110,20 +111,20 @@ This example uses `customCardProps`, `openOnEvent`, `directionalHint` and `isBea ## 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: +Users can now have a profile card or a file hover card on formatters too. Some of the things users can now do: -1. Profile card or File Hover card on any column -1. Profile card or Hover card with view formatting +- Profile card or File Hover card on any column +- Profile card or Hover card with view formatting -Hover on a filename with formatting with default file card: +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 default Profile card: +Hover on a person column with formatting with the default Profile card: ![Preview Image 4](../images/HoverImage-4.png) -Both the example uses defaultHoverField +This example uses `defaultHoverField`: ```JSON { @@ -257,9 +258,9 @@ The following image shows a list with a Gallery layout referencing the 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 set of supported types for this feature to work. +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. +A special JSON property `inlineEditField` is used with value as the field internal name __`[$FieldName]`__ at the target element in the JSON. ```json { @@ -287,7 +288,7 @@ List of supported field types for inline editing: ### Hover Borders and Customizations -The inline editing adds a hover border on the elements to indicate 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`. +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 { @@ -307,7 +308,7 @@ The inline editing adds a hover border on the elements to indicate these element 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 value of `FieldInternalName_1`, `FieldInternalName_2`, and `FieldInternalName_3`with the values provided: +The below JSON will set the value of `FieldInternalName_1`, `FieldInternalName_2`, and `FieldInternalName_3`with the values provided: ```json { @@ -361,15 +362,15 @@ The below JSON will set value of `FieldInternalName_1`, `FieldInternalName_2`, a - `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. + - 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 second parameter with third. + - `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 people column and the first person in the returned results is used. + > [!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 index d170e9031..bf3f244cf 100644 --- a/docs/declarative-customization/formatting-syntax-reference.md +++ b/docs/declarative-customization/formatting-syntax-reference.md @@ -1,7 +1,7 @@ --- title: Formatting syntax reference description: Formatting syntax reference -ms.date: 04/05/2024 +ms.date: 02/19/2025 ms.localizationpriority: high --- @@ -53,6 +53,9 @@ An optional property that specifies the text content of the element specified by 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' @@ -163,7 +166,7 @@ An optional property that specifies style attributes to apply to the element spe 'clear' 'clip' 'display' -'float' +'float' (Deprecated) 'left' 'overflow' 'position' @@ -309,7 +312,7 @@ See [Formatting multi-value fields](column-formatting.md#formatting-multi-value- `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 select on the item, which results in opening the list item. Adding this example button to a document library simulates a select on the file or folder, which results in the file or folder being opened. +- **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 { @@ -348,7 +351,7 @@ See [Formatting multi-value fields](column-formatting.md#formatting-multi-value- "action": "setValue", "actionInput": { "FieldInternalName_1": "FieldValue_1", - "FieldInternalName_2": "FieldValue_2", + "FieldInternalName_2": "FieldValue_2" } } } @@ -403,8 +406,8 @@ See [Formatting multi-value fields](column-formatting.md#formatting-multi-value- 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. Default value is 300. _(optional)_ - - **width**: The width of the callout within which the embedded content will render. Default value is 300. _(optional)_ + - **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 @@ -413,14 +416,14 @@ Add a custom card to the element, that shows up on hover or `click` event. The f - `"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 isn't guaranteed depending on space. +- `"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 custom card's beak. +- `"beakStyle"`: Specifies the style object for the custom card's beak. ## defaultHoverField -Adds the profile card for the people fields or file hover card for files in the document library. +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 @@ -429,6 +432,8 @@ Adds the profile card for the people fields or file hover card for files in the 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]" @@ -478,7 +483,7 @@ Values for `txtContent`, style properties, and attribute properties can be expre 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 in expressions, even if it's marked `Explicit`. +All fields in `ViewFields` can be referred to in expressions, even if it's marked `Explicit`. ### Excel-style expressions @@ -636,13 +641,13 @@ Operators specify the type of operation to perform. Valid operator values includ - `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 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 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"_ + - `"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_ @@ -719,7 +724,7 @@ Operators specify the type of operation to perform. Valid operator values includ - `"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. + 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_ @@ -735,16 +740,16 @@ Operators specify the type of operation to perform. Valid operator values includ - `"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 image for a given image field and preferred size. - - `"src":"=getThumbnailImage([$ImageField], 400, 200)"` results in a URL pointing to image for a given image field with 400 width and 200 height +- `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. +- `?`: 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 field of type Person, Lookup, or Choice. +**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` @@ -754,11 +759,11 @@ Operators specify the type of operation to perform. Valid operator values includ `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 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. +`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: +**String-related operators** - Some of the previously detailed operators can be used when working with string values: - `+` - `indexOf` (*for string length workaround*) @@ -769,7 +774,7 @@ For examples, see [Formatting multi-value fields](column-formatting.md#formattin "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. +`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 @@ -781,7 +786,7 @@ The values for `txtContent`, styles, and attributes can be either strings or Exp ### "@currentField" -Will evaluate to the value of the current field. +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. @@ -963,21 +968,16 @@ The following example shows how a hyperlink field might be used on a current fie **Image fields** -The image field object has the following properties (with example values): +The image field object has the following `fileName` property: ```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", - "thumbnailRenderer": { - "spItemUrl": "https://contoso.sharepoint.com:443/_api/v2.1/drives/b!7196759210defdc0/items/2303b15bfa48c74a74758135a0df1201", - "fileVersion": 3, - "sponsorToken": "3u+UR6n8AgABAAAAHxxdXKmiOmUoqKnZlf8lTOhlPYy93EAkbPfs5+49YLFd/B1+omSKbW7DoqNM40/EeVnwJ8kYoXv9zy9D5C5m5A==" - } } ``` +> [!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. @@ -1007,9 +1007,9 @@ The Approval Status field object has the following property (with example value) } ``` -`displayValue` is localized string of the approval status. +`displayValue` is a localized string of the approval status. -`@currentField` or `[$__ModerationStatus]`will also internally map to the following internal numeric value: +`@currentField` or `[$__ModerationStatus]` will also internally map to the following internal numeric value: - 0: Approved - 1: Denied @@ -1017,7 +1017,7 @@ The Approval Status field object has the following property (with example value) - 3: Draft - 4: Scheduled -`[$_ModerationStatus]` field supports comparisons to both strings and the numeric value. The numeric comparisons work across locales and languages, and that will be the recommended way for this field. +`[$_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`: @@ -1068,17 +1068,17 @@ If the value of a field is an object, the object's properties can be accessed. F 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]`. +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. +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 to the email address of the current logged in user. +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 current logged in user and blue otherwise: +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 { @@ -1119,11 +1119,11 @@ Here's the same sample from above, using the Excel-style expression syntax: ### "@now" -This will evaluate to the current date and time. +This will evaluate 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. +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: @@ -1136,7 +1136,7 @@ Here's an example of using the value within a view format to apply alternating s ### "@window.innerHeight" -This will evaluate to a number equal to the height of the browser window (in pixels) when the list was rendered. +This will be evaluated to a number equal to the height of the browser window (in pixels) when the list is rendered. ### "@window.innerWidth" @@ -1146,14 +1146,14 @@ This will evaluate to a number equal to the width of the browser window (in pixe 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 to the thumbnail URL in three different predefined sizes. -- `@thumbnail.` evaluates to the URL to the largest thumbnails 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 to 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. +- `@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 thumbnail generated is the same as how the file looks like, changing the bounding sizes will not affect the aspect ratio of the thumbnail. +> 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. @@ -1218,12 +1218,12 @@ This also works with field name: ### "@isSelected" -This will evaluate to `true` for selected item(s) in a view and `false` otherwise. +This will evaluate to `true` for the selected item(s) in a view and `false` otherwise. ### "@lcid" -This will evaluate to the LCID of current culture. This can be used to format the date, time and numbers. +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 current UI culture. This can be used to show localized display strings. +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/list-form-conditional-show-hide.md b/docs/declarative-customization/list-form-conditional-show-hide.md index 23977f2f3..1d4afe455 100644 --- a/docs/declarative-customization/list-form-conditional-show-hide.md +++ b/docs/declarative-customization/list-form-conditional-show-hide.md @@ -1,7 +1,7 @@ --- 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: 06/28/2022 +ms.date: 07/28/2025 ms.localizationpriority: high --- @@ -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,9 +56,9 @@ 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 @@ -66,7 +66,8 @@ While the formula supports many of the available column types, we do not current - Person or Group with multiple selections - Choice with multiple selections -- Time calculations in Date and Time column +- Lookup with multiple selections +- Time calculations in **Date and Time** column - Currency columns - Location columns - Calculated columns @@ -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,16 +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 72c625c77..ab641654f 100644 --- a/docs/declarative-customization/list-form-configuration.md +++ b/docs/declarative-customization/list-form-configuration.md @@ -7,9 +7,9 @@ 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 @@ -173,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. @@ -242,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 8f711add3..2ed0397a6 100644 --- a/docs/declarative-customization/site-design-json-schema.md +++ b/docs/declarative-customization/site-design-json-schema.md @@ -1,7 +1,7 @@ --- title: Site template JSON schema description: JSON schema reference for building site templates for SharePoint. -ms.date: 09/23/2022 +ms.date: 11/18/2024 ms.localizationpriority: high --- @@ -18,9 +18,7 @@ The overall JSON structure is specified as follows: ... ... - ], - "bindata": { }, - "version": 1 + ] } ``` diff --git a/docs/declarative-customization/site-design-o365cli.md b/docs/declarative-customization/site-design-o365cli.md index 1dd252859..6282f7491 100644 --- a/docs/declarative-customization/site-design-o365cli.md +++ b/docs/declarative-customization/site-design-o365cli.md @@ -1,7 +1,7 @@ --- 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: 06/28/2022 +ms.date: 06/27/2024 ms.localizationpriority: high --- @@ -17,7 +17,7 @@ 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/) 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-office-365/) to connect to your SharePoint tenant. +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 287b7a836..701efedc2 100644 --- a/docs/declarative-customization/site-design-overview.md +++ b/docs/declarative-customization/site-design-overview.md @@ -1,7 +1,7 @@ --- 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: 06/28/2022 +ms.date: 01/22/2025 ms.localizationpriority: high --- @@ -10,12 +10,12 @@ ms.localizationpriority: high > [!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 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). +> - 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 provisioning new or existing modern SharePoint sites that use your own custom configurations. +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. @@ -23,11 +23,11 @@ This article describes how you can use site templates and site scripts to provid ## 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. +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 display 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. +> - 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. @@ -38,14 +38,14 @@ You create site templates and register them in SharePoint to one of the modern t 1. Choose the type of site needed. - - SharePoint will automatically create a communication site using the **Topic** site template. - - Had you chosen the default Team site, SharePoint will create a new site using the **Team collaboration** template. + - 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. +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. @@ -102,8 +102,7 @@ The following example is a script that has two top-level actions. First, it appl } ] } - ], - "version": 1 + ] } ``` @@ -113,7 +112,7 @@ Each action in a site script is specified by a **verb** value in the JSON. In th - 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 +- 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** @@ -130,7 +129,7 @@ For a complete list of available actions and their parameters, see the [JSON sch > - 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. Site scripts are non-destructive, so when they run again, they ensure that the site matches the configuration in the script. +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. @@ -140,7 +139,7 @@ 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. +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. @@ -168,7 +167,7 @@ In the previous example, the **Add-SPOSiteScript** cmdlet or **CreateSiteScript* | Parameter | Value | Site template type | | :------------------- | :------------------- |:----------------| | WebTemplate | 64 | Team site template | -| WebTemplate 1 | 1 | Team site (with group creation disabled) | +| WebTemplate | 1 | Team site (with group creation disabled) | | WebTemplate | 68 | Communication site template | | WebTemplate | 69 | Channel site template | diff --git a/docs/declarative-customization/site-design-trigger-flow-tutorial.md b/docs/declarative-customization/site-design-trigger-flow-tutorial.md index 4515f351c..285da5ad0 100644 --- a/docs/declarative-customization/site-design-trigger-flow-tutorial.md +++ b/docs/declarative-customization/site-design-trigger-flow-tutorial.md @@ -1,7 +1,7 @@ --- 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/28/2022 +ms.date: 06/05/2024 ms.localizationpriority: high --- @@ -68,7 +68,7 @@ In order to capture the site creation event and create the corresponding list it "type": "string" }, "creatorEmail": { - "type": "string" + "type": ["string", "null"] }, "createdTimeUTC": { "type": "string" 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 7fa2f83d0..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,7 +1,7 @@ --- 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: 10/20/2022 +ms.date: 08/08/2024 ms.localizationpriority: high --- @@ -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) 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 4f4856987..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,7 +1,7 @@ --- 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: 02/16/2023 +ms.date: 04/23/2025 ms.localizationpriority: high --- @@ -80,7 +80,7 @@ To do this, you must use a Windows PowerShell script with a CSOM (client-side ob [!INCLUDE [pnp-powershell](../../../includes/snippets/open-source/pnp-powershell.md)] -1. Enter `Connect-PnPOnline -Url -UseWebLogin` (replacing `` with the url of the site you wish to opt out of). +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: diff --git a/docs/declarative-customization/view-commandbar-formatting.md b/docs/declarative-customization/view-commandbar-formatting.md index 3ae8b0563..f7f56e8e3 100644 --- a/docs/declarative-customization/view-commandbar-formatting.md +++ b/docs/declarative-customization/view-commandbar-formatting.md @@ -1,21 +1,24 @@ --- title: Command bar customization syntax reference description: Command bar customization syntax reference -ms.date: 08/12/2022 +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. +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 -Array of JSON objects to specify the commands for customization. + +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 @@ -83,25 +86,64 @@ Mandatory property to uniquely identify a command in the Command bar. Valid keys '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. + +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. + +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. + +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,. + +- 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. @@ -130,17 +172,21 @@ The following example shows a sample Command bar formatting JSON to do the follo ``` ## 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, 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. + +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 at 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 theCommand 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 { @@ -166,12 +212,15 @@ The following example shows a sample Command bar formatting JSON to do the follo ``` ## 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 array of strings where the following strings are allowed: + +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. diff --git a/docs/design/design-guidance-overview.md b/docs/design/design-guidance-overview.md index 74fef36f4..1566fe91e 100644 --- a/docs/design/design-guidance-overview.md +++ b/docs/design/design-guidance-overview.md @@ -40,6 +40,44 @@ Accessibility is developing an equal experience for all users that enables indiv +## 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 - [Overview of SharePoint Framework](../spfx/sharepoint-framework-overview.md) diff --git a/docs/design/themes-colors.md b/docs/design/themes-colors.md index 458bb1de4..d2eee4ec8 100644 --- a/docs/design/themes-colors.md +++ b/docs/design/themes-colors.md @@ -1,7 +1,7 @@ --- title: SharePoint themes and colors description: Design principles that help form the current SharePoint themes and color palette. -ms.date: 06/28/2022 +ms.date: 09/04/2024 ms.localizationpriority: high --- @@ -33,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/use-brand-center-fonts-in-spfx-components.md b/docs/design/use-brand-center-fonts-in-spfx-components.md new file mode 100644 index 000000000..04a547908 --- /dev/null +++ b/docs/design/use-brand-center-fonts-in-spfx-components.md @@ -0,0 +1,173 @@ +--- +title: Use SharePoint brand center fonts in SharePoint Framework solutions +description: Developers can use the fonts defined in Brand center in their SharePoint Framework (SPFx) components. This article demonstrates how you can use the fonts defined in the SharePoint brand center in your SPFx components. +ms.date: 04/23/2025 +ms.localizationpriority: high +--- + +# Use SharePoint brand center fonts in SharePoint Framework solutions + +The [SharePoint brand center](/sharepoint/brand-center-overview) offers a centralized branding management application that empowers your brand managers or designated brand owners to help your organization to customize the look and feel of their experiences. This brand asset management system allows customers to manage the colors, fonts, and images, and other assets all in one place. + +Developers can use the fonts defined in Brand center in their SharePoint Framework (SPFx) components. This article demonstrates how you can use the fonts defined in the SharePoint brand center in your SPFx components. + +![Screenshot of the SharePoint brand center](../images/brand-center-spfx-01.png) + +In this article, learn how you can modify your SPFx components to use the same fonts set in the + +## Use SharePoint brand center fonts in SPFx components + +Start by creating a new SharePoint Framework component, such as a web part. + +> [!TIP] +> To learn how to create your first SPFx web part, see [Build your first SharePoint client-side web part (Hello World part 1)](../spfx/web-parts/get-started/build-a-hello-world-web-part.md). + +Within the web part, locate and open the **\*.module.scss** file in the project. For example, if you created a web part named *Hello World", the file will be found in the following location in the project: **./src/webparts/helloWorld/HelloWorldWebPart.module.scss**. + +This file contains the styles for the SPFx component. + +All fonts defined within Brand center are referenced using variables following the naming convention `--fontFamilyCustomFont###`. All start with the prefix `--fontFamily` followed by the *font slot* name. + +For example, to change the primary font in your web part, add the following style to the `.helloWorld` class: + +```css +font-family: var(--fontFamilyCustomFont100, var(--fontFamilyBase)); +``` + +This tells the web part to use the value defined in the SharePoint styling context with the variable `--fontFamilyCustomFont100`, but if that value isn't set, it will default to the `--fontFamilyBase` slot. + +The resulting class will now look like this: + +```css +.helloWorld { + font-family: var(--fontFamilyCustomFont100, var(--fontFamilyBase)); + overflow: hidden; + padding: 1em; + color: "[theme:bodyText, default: #323130]"; + color: var(--bodyText); + &.teams { + font-family: $ms-font-family-fallbacks; + } +} +``` + +Next, repeat this step for any other classes in our style where you want to apply these changes. For example, in the default web part, you'd update the `.welcome` and `.links.a` styles as well, so the resulting **\*.scss** file will look like the following: + +```css +@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'; + +.helloWorld { + font-family: var(--fontFamilyCustomFont100, var(--fontFamilyBase)); + overflow: hidden; + padding: 1em; + color: "[theme:bodyText, default: #323130]"; + color: var(--bodyText); + &.teams { + font-family: $ms-font-family-fallbacks; + } +} + +.welcome { + text-align: center; + font-family: var(--fontFamilyCustomFont100, var(--fontFamilyBase)); +} + +.welcomeImage { + width: 100%; + max-width: 420px; +} + +.links { + a { + font-family: var(--fontFamilyCustomFont100, var(--fontFamilyBase)); + 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 + } + } +} +``` + +### Test the web part + +To test the web part, start the local web browser, but don't launch a browser to the hosted workbench. + +1. Run the command **gulp serve** from the root of the project and include the **--nobrowser** argument: + + ```console + gulp serve --nobrowser + ``` + + > [!IMPORTANT] + > The SharePoint hosted workbench does not support custom fonts defined in the SharePoint brand center. To test your web parts, you'll need to test them on a page in a SharePoint site. + +1. In the console, the **gulp serve** command will output a line that looks similar to the following: + + ```text + [spfx-serve] To load your scripts, use this query string: ?debug=true&noredir=true#debugManifestsFile=https://localhost:4321/temp/build/manifests.js + ``` + + > [!NOTE] + > Debug query string was changed starting from the SPFx verson 1.21 from `https://localhost:4321/temp/manifests.js` to `https://localhost:4321/temp/build/manifests.js` + +1. Open the browser and navigate to a page that you have permission to add a web part to the page. +1. Add the query string from the preceding console message to the URL and load the page. + + When prompted in the **Allow debug scripts** dialog, select **Load debug scripts**. + +1. Next, put the page into edit mode and add your sample web part to the page. +1. Finally, publish the changes. + +With the web part on the page, select one of the custom fonts from the Brand center site: + +1. Select the gear icon in the top right of the Microsoft 365 suite bar, then select **Change the look**. + + ![Screenshot of the SharePoint settings menu](../images/brand-center-spfx-02.png) + +1. On the **Change the look** panel, select **Font**. + + ![Screenshot of the SharePoint setting Change the look panel](../images/brand-center-spfx-03.png) + +1. On the **Font** panel, select one of the fonts to view the changes on your web part. + + ![Screenshot of the SharePoint setting Font panel](../images/brand-center-spfx-04.png) + + Notice the fonts on the page will change, including those in our custom web part: + + ![Screenshot of a custom font selected from Brand central used in the web part](../images/brand-center-spfx-05.png) + +## Brand central font slot reference + +The following table lists all the available font slots from SharePoint brand center that developers can use in their custom SPFx components: + +| Font slot | Custom Font Token | Fluent Design Token | Short Description | Used in Product Location | +| ----------- | ----------------- | ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| Body | CustomFont100 | caption2 | Caption small | | +| Body | CustomFont200 | caption2Strong | Caption medium | News Badge, Image caption, Site WP activity, Avatar Role/Job, Hero Badge | +| Body | CustomFont300 | caption1 | Caption large | Image Overlay | +| Interactive | CustomFont400 | caption1Strong | Label small | Avatar link | +| Interactive | CustomFont500 | caption1Stronger | Label medium | Footer links, Top Navigation links, Hub navigation links, Left navigation, Hero button | +| Interactive | CustomFont600 | body1 | Label large | Button | +| Body | CustomFont700 | body1Strong | Paragraph small | Quick links description, News sub description, Site web part information, Site web part description, Avatar name, Avatar description | +| Body | CustomFont800 | body1Stronger | Paragraph medium | News description, RTE Normal, RTE Table Cell, Hero Description | +| Body | CustomFont900 | body2 | Paragraph large | | +| Headline | CustomFont1000 | subtitle2 | Heading extra small | News subtitle, RTE H4, RTE Table Header, RTE, Table Column, Site WP site title, Call to action text, Hero call to action | +| Headline | CustomFont1100 | subtitle2Stronger | Heading small | Quick Links title, News title, Footer title, RTE H3, RTE Pull quote, Section heading, Hero title, Hero small tile title | +| Headline | CustomFont1200 | subtitle1 | Heading medium | RTE H2, Hero title large | +| Headline | CustomFont1300 | title3 | Heading large | Web part title, Hero tile title | +| Headline | CustomFont1400 | title2 | Heading extra large | | +| Title | CustomFont1500 | title1 | Title small | Hub title | +| Title | CustomFont1600 | largeTitle | Title medium | Page title, Site title | +| Title | CustomFont1700 | display | Title large | | + +> [!TIP] +> Don't forget to include the `--fontFamily` prefix when using one of the custom font slot tokens in your style sheets. + +## See also + +- Video: [Using SharePoint Brand center font settings in custom SPFx solutions](https://www.youtube.com/watch?v=IP19PeHb0Zg) diff --git a/docs/embedded/administration/adminrole.md b/docs/embedded/administration/adminrole.md new file mode 100644 index 000000000..b15f2b7ad --- /dev/null +++ b/docs/embedded/administration/adminrole.md @@ -0,0 +1,83 @@ +--- +title: SharePoint Embedded administrator +description: This article explains the new admin role for SharePoint Embedded. +ms.date: 05/21/2024 +ms.localizationpriority: high +--- + +# The SharePoint Embedded administrator + +The SharePoint Embedded administrator is a dedicated role to manage SharePoint Embedded containers through [SharePoint PowerShell](/powershell/module/sharepoint-online/connect-sposervice) and SharePoint admin center. This role is required for [developer admins](./developer-admin/dev-admin.md) to create new container types through PowerShell cmdlets and also for consuming tenant admins to manage containers created in their tenants. + +The global administrator role already has all the permissions of the SharePoint Embedded administrator role. A global administrator can assign a user the SharePoint Embedded administrator role to act as a consuming tenant admin or a developer administrator for SharePoint Embedded. + +The SharePoint Embedded administrator role is available in Microsoft Entra and Microsoft 365 Admin Center. This role doesn't have access to site management. This means that a SharePoint Embedded administrator can't see 'Active sites' and 'Deleted sites' pages on the SharePoint Admin Center and also can't run site specific PowerShell cmdlets. + +## SharePoint Embedded administrator tasks in the developer tenant + +The following are some of the container-specific commands actions currently supported on PowerShell: + +- Creation of container types + - Creation of a Standard container type with standard billing + - Creation of a Standard container type with direct to customer billing + - Creation of a Trial container type + +- Container type management + - Viewing of container types in the developer tenant + - Editing properties of a container type in the developer tenant + - Configuration properties of a container type in the developer tenant + - Manage billing of applications/ container types for standard billing + +## SharePoint Embedded administrator tasks in consuming tenant + +The following are some of the container-specific commands actions currently supported on PowerShell: + +- Application administration + - Get details of all SharePoint Embedded applications in the tenant + - Get detail of a specific application in the tenant + - Get the permissions of owning applications in the tenant + - Configure External sharing setting of a container of an application in tenant + +- Container administration + - Get details of all containers of an application in the tenant + - Get details of all containers of an application in the tenant sorted by storage + - Get details of a specific container of an application in the tenant + - Set Sensitivity label of a specific container of an application in the tenant + - Soft delete a container of an application in the tenant + - Get details of all soft deleted containers in the tenant + - Restore a soft deleted container of an application in the tenant + - Permanently delete a soft deleted container of an application in the tenant + +The following are some of the actions currently supported on SharePoint Admin Center: + +- View Active container page +- View Deleted container page +- View the detailed information of a container +- Soft delete a container +- Restore a deleted container +- Purge a deleted container + +## Assigning the SharePoint Embedded administrator Role + +The Global admin can assign the SharePoint Embedded Admin role to users through both Entra and Microsoft admin center. + +### Through Entra + +Follow the following steps to assign the role of SharePoint Embedded administrator on Entra: + +1. Sign into Entra as a Global admin +1. Select the **“Users”** tab on the left-hand panel and select **“All users”** +1. Select the user to assign the role of SharePoint Embedded administrator under **“All users”** +1. Select the **“Assigned role”** tab on the left panel +1. Select on **“Add assignments”** button and search for **“SharePoint Embedded”** in the panel that opens +1. Select the 'SharePoint Embedded administrator' option and select on **“Add”** +1. The selected user is assigned the role of SharePoint Embedded administrator + +### Through Microsoft 365 Admin Center + +1. Sign into Microsoft 365 Admin Center as a Global admin +1. Select **“Users”** and select **“Active users”** under it +1. Select the user to assign the role of SharePoint Embedded administrator +1. Select on **“Manage roles”** option under Roles +1. Select **“Admin center access”** and under **“Collaboration”**, select **“SharePoint Embedded administrator”** +1. Select **"Save changes"**. Now the selected user is assigned the role of SharePoint Embedded administrator diff --git a/docs/embedded/administration/billing/billing.md b/docs/embedded/administration/billing/billing.md new file mode 100644 index 000000000..6ef373a92 --- /dev/null +++ b/docs/embedded/administration/billing/billing.md @@ -0,0 +1,125 @@ +--- +title: PAYG billing for SharePoint Embedded +description: This article explains the billing models and how to set up PAYG billing. +ms.date: 03/03/2025 +ms.localizationpriority: high +--- + +# SharePoint Embedded billing + +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 + +With the standard billing model, 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) + +### Pass-through + +With pass-through billing, consumption-based charges are billed directly to the tenant registered to use the SharePoint Embedded application. Admins in the developer tenant don't need to set up a billing profile when creating a pass-through SharePoint Embedded container type. Once the container type is registered 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. + +![Pass Through](../../images/2bill521.png) + +## 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 developer admin needs to set up: + +- An existing SharePoint tenancy +- An Azure subscription in the tenancy +- A resource group attached to the Azure subscription + +## Set up a Standard Billing container type + +For standard billed container types, developer admins should set up billing in their tenant. The Microsoft 365 SharePoint Embedded Administrator serves as the developer admin. Global Administrators in Microsoft 365 can assign users the SharePoint Embedded Administrator role, which already has all the permissions of the SharePoint Embedded Administrator role. The SharePoint Embedded Admin role is available in Microsoft Entra and Microsoft 365 Admin Center. + +SharePoint Embedded Admin can create a container type using the `New-SPOContainerType` cmdlet by providing an Azure subscription, the resource group associated with the subscription, and a region. + +- If you don't have an Azure subscription, you can create one by following the steps here to [create an Azure subscription in your tenancy](/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions), +- If you don't have a resource group, you can create one by following the steps here to [create a resource group](/azure/azure-resource-manager/management/manage-resource-groups-portal) + +```powershell +New-SPOContainerType -ContainerTypeName + -OwningApplicationId + -AzureSubscriptionId + -ResourceGroup + -Region +``` + +> [!IMPORTANT] +> 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. + +### View & Edit billing properties of Standard container type + +You can view the properties of a container type and associated billing properties by using one of the two PowerShell cmdlets: + +1. See all container types and billing properties except associated region: + + ```powershell + Get-SPOContainerType + ``` + +1. See billing properties associated with a container type including region: + + ```powershell + Get-SPOContainerType -ContainerTypeId + ``` + +1. Update Azure subscription or resource group associated with a container type: + + ```powershell + Set-SPOContainerType -ContainerTypeId [-AzureSubscriptionId ] [-ResourceGroup ] + ``` + + +## Set up a Pass-through Billing container type + +For Pass-through Billing container types, the developer admin doesn't have to set up billing in the developer tenant. SharePoint Embedded Admin can create container type using `New-SPOContainerType` cmdlet with `isPassThroughBilling` specified. + +```powershell +New-SPOContainerType -ContainerTypeName + -OwningApplicationId + -isPassThroughBilling +``` + +### [Set Up Guide in Consuming Tenant Admin Center](../consuming-tenant-admin/cta.md#set-up-billing-for-pass-through-app) + +1. In [Microsoft 365 admin center](https://admin.microsoft.com/), select **Setup**, and the view the **Files and Content** section. Select **Automate Content with Microsoft Syntex.** + + ![Microsoft 365 admin center Files and Content](../../images/DTCBilling1.png) + +1. Select **Go to Syntex settings**. +1. Select **Apps** under **Syntex services for**, select **SharePoint Embedded** + + ![Microsoft 365 admin center SharePoint Embedded Billing setting](../../images/DTCBilling2.png) + +1. Follow the instructions on the **SharePoint Embedded** flyer to turn on SharePoint Embedded apps. + +## SharePoint Embedded meters + +To learn more about the supported pay-as-you-go meters, refer to the [SharePoint Embedded meters](meters.md) article. diff --git a/docs/embedded/administration/billing/billingmanagement.md b/docs/embedded/administration/billing/billingmanagement.md new file mode 100644 index 000000000..b2e03cac5 --- /dev/null +++ b/docs/embedded/administration/billing/billingmanagement.md @@ -0,0 +1,57 @@ +--- +title: SharePoint Embedded Billing Management +description: This article describes how to view SharePoint Embedded application consumption in Azure portal. +ms.date: 05/21/2024 +ms.localizationpriority: high +--- + +# SharePoint Embedded Billing Management + +The Microsoft Cost Management portal provides a comprehensive overview of your costs, allowing you to track and analyze your spending for SharePoint Embedded application. This guide walks you through the steps to view your billing details and SharePoint Embedded consumption in the Microsoft Cost Management portal. + +## Step-by-Step Guide + +### Sign in to Azure portal + +1. Open your web browser and navigate to the [Azure portal](https://portal.azure.com/). +1. Sign in using your Azure account credentials. + +### Navigate to Cost Management + Billing + +1. Once signed in, locate the left-hand navigation menu. +1. Select on "Cost Management + Billing". If it's not visible, you can search for it using the search bar at the top of the portal. + + ![Cost Management](../../images/billmanag1.png) + +### Select Your Subscription + +1. In the Cost Management + Billing section, you see a list of your subscriptions. +1. Select the subscription for which you want to view the billing details. + +### View Billing Overview + +1. After selecting your subscription, you'll be taken to the Overview page. +1. Here, you can see a summary of your costs, including current spending, forecasted costs, and any spending anomalies. + +### Access Cost Analysis + +1. For a more detailed view, select "Cost analysis" under the Cost Management section. +1. In the Cost Analysis page, you can customize the date range to view costs for specific periods. +1. Use the filters to break down costs by tags - app ID, tenant ID or container type ID. Filters can also set by Meters, Resources etc. Refer to the [SharePoint Embedded meters](meters.md) article to learn more about the pay-as-you-go meters supported. + +![Meters](../../images/billmanag2.png) + +### Download Invoices + +1. To download invoices, go to the "Invoices" section under Billing. +1. Here, you can view and download your billing invoices for any billing period. + +### Set Up Budgets and Alerts + +1. To better manage your spending, you can set up budgets and alerts. +1. Select "Budgets" under the Cost Management section. + + ![Budgets](../../images/billmanag3.png) + +1. Create a new budget by specifying the amount and the time period. +1. Set up alerts to notify you when spending approaches or exceeds your budget. diff --git a/docs/embedded/administration/billing/meters.md b/docs/embedded/administration/billing/meters.md new file mode 100644 index 000000000..a6f770eea --- /dev/null +++ b/docs/embedded/administration/billing/meters.md @@ -0,0 +1,39 @@ +--- +title: SharePoint Embedded Billing Meters +description: This article describes the meters in SharePoint Embedded. +ms.date: 04/30/2025 +ms.localizationpriority: high +--- + +# SharePoint Embedded Billing Meters + +SharePoint Embedded employs a pay-as-you-go (PAYG) billing model through an Azure subscription. Billing is determined by how much data in GB you store in SharePoint Embedded, transactions used to access and modify the container and container contents, and data that is egressed from the SharePoint Embedded platform. Each of these factors contributes to the overall cost, ensuring that you only pay for the resources and services you use. You can view this usage and billing details in the [Azure Cost Management](https://ms.portal.azure.com/). Both Standard Billing container type and Pass-through Billing container type will use the same meters. + +SharePoint Embedded has three billing meters as shown. Refer to the [product page](https://adoption.microsoft.com/en-us/sharepoint/embedded/) for pricing details. + + +## Storage + +Storage consumption meters in SharePoint Embedded apply to the storage used by files and documents along with their metadata and versions. Storage consumption also includes all content in the recycle bin and deleted container collection within SharePoint Embedded. + +## API Transactions + +Each Microsoft Graph call made explicitly by the SharePoint Embedded application is counted as one transaction and customers are billed based on the transaction count. See the [examples](/graph/api/resources/filestoragecontainer) of Microsoft Graph calls that can be made by a SharePoint Embedded application. + +However, calls made by internal services to the containers, which the application has no control over, are **not** charged. Some examples of such nonchargeable transactions include: + +1. Queries performed by the eDiscovery service to search through container content for compliance or legal purposes. +1. Admin actions taken by the SharePoint Embedded Admin or Global Admin on containers through SharePoint Admin Center or SPO PowerShell. + +## Egress + +Egress refers to the data downloaded from the SharePoint Embedded platform to the customer's client device such as a desktop or mobile device. + +However, certain types of data transfers are exempt from egress charges. These exemptions ensure that customers aren't billed for data transfers occurring within integrated Microsoft services, promoting seamless usage without extra costs for these specific internal operations. Some examples of these exemptions include: + +1. File downloads from the SharePoint Embedded application server to the customer's Office Desktop client aren't charged. +1. File downloads from the SharePoint Embedded application server to the Web Application Companion (WAC) aren't charged. + +## Pay as you go message (private preview) + +SharePoint Embedded agents use the Copilot Studio meter for $0.01/message (messages are the unit that measures agent usage). Each interaction with SharePoint Embedded agent will use twelve (12) messages - 2 messages for the generative answer feature and 10 messages for the tenant graph grounding feature - so customers are billed at $0.12 per interaction with SharePoint Embedded agents. diff --git a/docs/embedded/administration/consuming-tenant-admin/cta.md b/docs/embedded/administration/consuming-tenant-admin/cta.md new file mode 100644 index 000000000..786aa6acf --- /dev/null +++ b/docs/embedded/administration/consuming-tenant-admin/cta.md @@ -0,0 +1,92 @@ +--- +title: Consuming Tenant Admin +description: This article describes the role and responsibilities of Consuming Tenant Admin in SharePoint Embedded. +ms.date: 03/03/2025 +ms.localizationpriority: high +--- + +# Consuming Tenant Admin + +> [!IMPORTANT] +> Assign the SharePoint Embedded Administrator role available in M365 Admin Center or Microsoft Entra to execute SharePoint Embedded Container cmdlets mentioned in this article. +> +> Global Administrators can continue to execute SharePoint Embedded container cmdlets. +> +> A global administrator can assign a user the SharePoint Embedded administrator role to act as a consuming tenant admin for SharePoint Embedded. + +The organizations that use the SharePoint Embedded applications on their Microsoft 365 (Microsoft 365) tenants are the consuming tenants and the persona that is responsible for managing these applications on their Microsoft 365 tenancy is the consuming tenant administrator. Consuming tenant administrators can perform various administrative actions on the SharePoint Embedded applications registered on their Microsoft 365 tenant and on the containers that hold the content. They can also manage tenant level configurations and ensure that data is stored in a secure, protected way that meets customers’ business and compliance policies. In this article, we describe the enterprise manageability features that are supported and can be performed by the consuming tenant administrator. They can do so either using the PowerShell cmdlets or through the SharePoint Administrator Center (SPAC). + +## Consuming Tenant Admin Role + +Microsoft 365 SharePoint Embedded Administrator serves as the consuming tenant admin. Global Administrators in Microsoft 365 can assign users the SharePoint Embedded Administrator. The Global Administrator role already has all the permissions of the SharePoint Embedded Administrator role. The SharePoint Embedded Role is available in Microsoft Entra and Microsoft 365 Admin Center. +For information on [SharePoint Embedded Admin](../adminrole.md) + +## Administration Tools + +Consuming tenant admins can manage SharePoint Embedded applications with the following options: + +### SharePoint Online Management Shell + +On PowerShell, the SharePoint Embedded Admin can run the following cmdlets: + +1. Enumerate applications in a tenant +1. Enumerate containers of an application in a tenant +1. Enumerate containers of an application sorted basis storage +1. Edit the sensitivity label on a container +1. Set sharing capability configuration on a container + +For information on consuming tenant admin in [PowerShell](../consuming-tenant-admin/ctapowershell.md) + +### SharePoint Administrator Center + +The SharePoint Embedded Admin can access the Active and Deleted containers page on SPAC and perform SharePoint Embedded application level and container level actions. This includes the following: + +1. View the Active container page +1. View the Deleted container page +1. View the detailed information of a container +1. Soft delete, restore, and purge deleted containers + +For information on consuming tenant admin in SharePoint Admin see [container management](ctaUX.md) + +## Security and Compliance Administration + +SharePoint Embedded uses Microsoft’s comprehensive compliance and data governance solutions to help organizations manage risks, protect, and govern sensitive data, and respond to regulatory requirements. Security and compliance solutions work in a similar manner in the SharePoint Embedded platform as they do today in the Microsoft 365 platform so that data is stored in a secure, protected way that meets customers’ business and compliance policies while making it easy for Compliance and SharePoint Administrators to enforce critical security and compliance policies on the content. For information on supported security and compliance capabilities, see [Security and Compliance](../../compliance/security-and-compliance.md). + +## Set Up Billing for Pass-through App + +To use Pass-through SharePoint Embedded App, SharePoint Embedded Admin needs to set up Microsoft Syntex billing in [Microsoft 365 admin center](https://admin.microsoft.com/). No user can access any Pass-through SharePoint Embedded apps before a valid billing is set up for the SharePoint Embedded platform. + +### [Meters](../billing/meters.md) + +SharePoint Embedded employs a pay-as-you-go (PAYG) billing model through an Azure subscription. Billing is determined by how much data in GB you store in SharePoint Embedded, transactions used to access and modify the container and container contents, and data that is egressed from the SharePoint Embedded platform. Each of these factors contributes to the overall cost, ensuring that you only pay for the resources and services you use. You can view this usage and billing details in the [Azure Cost Management](https://ms.portal.azure.com/). + +SharePoint Embedded has three billing meters as shown. Refer to the [product page](https://adoption.microsoft.com/en-us/sharepoint/embedded/) for pricing details + +| SharePoint Embedded Service Meters | Meter Unit | +| :--------------------------------: | :------------: | +| Storage | $/GB | +| API Transactions | $/Transactions | +| Egress | $/GB | + +### Set Up Guide + +1. A valid Azure subscription is required. You can create one by following the steps here to [create an Azure subscription](/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions). +1. A valid Azure resource group is required. You can create one by following the steps here to [create a resource group](/azure/azure-resource-manager/management/manage-resource-groups-portal). +1. In [Microsoft 365 admin center](https://admin.microsoft.com/), select **Setup**, and the view the **Files and Content** section. Select **Automate Content with Microsoft Syntex.** + + ![Microsoft 365 admin center Files and Content](../../images/DTCBilling1.png) + +1. Select **Go to Syntex settings**. +1. Select **Apps** under **Syntex services for**, select **SharePoint Embedded** + + ![Microsoft 365 admin center SharePoint Embedded Billing setting](../../images/DTCBilling2.png) + +1. Follow the instructions on the **SharePoint Embedded** flyer to turn on SharePoint Embedded apps. + +### [Billing Management](../billing/billingmanagement.md) + +The [Microsoft Cost Management portal](https://portal.azure.com/#view/Microsoft_Azure_CostManagement/Menu/~/overview/openedBy/AzurePortal) provides a comprehensive overview of your costs, allowing you to track and analyze your spending for SharePoint Embedded application. This guide walks you through the steps to view your billing details and SharePoint Embedded consumption in the Microsoft Cost Management portal. + +### Invalid Billing/Turn off SharePoint Embedded + +If you turn off SharePoint Embedded or disconnect the linked Azure subscription, all users will immediately lose access to any application built on the service along with any read and write permissions. diff --git a/docs/embedded/administration/consuming-tenant-admin/ctaUX.md b/docs/embedded/administration/consuming-tenant-admin/ctaUX.md new file mode 100644 index 000000000..052f26f50 --- /dev/null +++ b/docs/embedded/administration/consuming-tenant-admin/ctaUX.md @@ -0,0 +1,218 @@ +--- +title: Manage containers in SharePoint Admin Center +description: This article describes how administrators can manage containers in the SharePoint Admin Center (SPAC). +ms.date: 07/09/2025 +ms.localizationpriority: high +--- +# Manage SharePoint Embedded containers in SharePoint Admin Center + +The organizations that use the SharePoint Embedded applications on their Microsoft 365 tenants are the consuming tenants and the persona that is responsible for managing these applications on their Microsoft 365 tenancy is the consuming tenant administrator (CTA). Consuming tenant administrators can manage containers through a graphical user interface (GUI) using the [SharePoint Administrator Center](https://go.microsoft.com/fwlink/?linkid=2185219). + +To manage SharePoint Embedded containers, the CTA needs to be assigned the SharePoint Embedded Administrator role. + +For information on the SharePoint Embedded Administrator role, see [SharePoint Embedded Admin](../adminrole.md). + +The following actions are supported in SharePoint Admin Center: + +1. View active containers in the tenant +1. View deleted containers in the tenant +1. View detailed information about a container +1. Delete a container +1. Restore a deleted container +1. Permanently deleted a container +2. Sort active containers in the tenant +3. Filter active containers in the tenant +4. Set sensitivity label on active containers +5. Add users to different roles on a container +6. Reassign users from existing roles on a container +7. Remove users from existing roles on a container + +![Active Containers global admin](../../images/ctaux1.png) + +**SharePoint Embedded Administrator** will only see the "Active containers" and "Deleted containers" page when they sign in to SharePoint Admin Center. + +![Active Containers SPE admin](../../images/ctaux2.png) + +## Active Containers + +The Active Containers page displays all the active containers within the tenant, providing a comprehensive overview and management capabilities. This page includes the following metadata for each container: + +1. **Container name:** Name of the container provided by the container owner. +1. **Application name:** Name of the SharePoint Embedded application the container belongs to. +1. **Publisher:** The name of the organization that owns the application. For all publishers other than Microsoft, the value is currently stored as "Other" +1. **Ownership type:** Mentions whether the container is tenant-owned, user-owned, or group-owned. +1. **Principal owner:** The user whose lifecycle impacts the lifecycle of the container. There is no prinicipal owner for a tenant owned container, while it is a user for a user owned container and a group for a group owned containers. +1. **Storage:** The total storage of the files stored in the containers. +1. **Owners:** Users assigned the owner role on the container. +1. **Owner count:** The count of number of owners of the container. +1. **Sensitivity label:** Name of the label assigned to the container. +1. **Created on:** Date and time when the container was created. + +![Active Container Properties](../../images/ctaux3.png) + +### View details of a container + +The detailed container view provides a deeper dive into container-specific metadata, organized under two tabs: + +1. **General:** This panel displays all the general metadata about a container, usage, and configuration settings. + + ![Container Details](../../images/ctaux4.png) + +1. **Membership:** This panel shows the user permissions for different users associated with the container. The admin can manage the membership on a container through this panel. + +> [!IMPORTANT] +> The SharePoint Embedded platform supports four distinct [roles](../../development/sharing-and-perm.md): Owner, Manager, Writer, and Reader. The SharePoint Embedded application on your tenant may not utilize all four roles and might refer to these roles using different names. + +![SharePoint Embedded Membership Roles](../../images/ctaux5.png) + +## Deleted Containers + +The deleted containers page lists all containers in the tenant's deleted container collection. It lists the following metadata: + +1. Container name +1. Application name +1. Publisher +1. Ownership type +1. Principal owner +1. Storage +1. Owners +1. Sensitivity label +1. Created on +1. **Deleted on**: Date and time when the container was deleted. + +![Container Deletion](../../images/ctaux6.png) + +## Delete a container + +> [!WARNING] +> Deleting a container may cause unexpected issues for the SharePoint Embedded application it belongs to and may interrupt the application's usage. This action should only be performed by admins when absolutely necessary. + +Deleting a container can have implications on the functionality of a SharePoint Embedded app Here are some examples of the potential issues that an application can encounter when deleting a container. + +1. **Data Loss:** Deleting a container removes all its content. If the SharePoint Embedded application relies on the data stored within the deleted container, the app might no longer function as expected or might lose access to critical information. +1. **Broken Links:** If the SharePoint Embedded application contains links or references to the deleted container, those links become broken, leading to errors or malfunctioning features within the app. + +A container can be deleted from the Active containers page for any business reason by the CTA. By default, the delete button is deactivated. On selecting a container, the delete button is activated. The CTA can then select the delete button. + +![Container Deletion Process](../../images/ctaux7.png) + +This opens a side panel that warns the user about the effect on the associated SPE application due to the deletion of a container and informs the user about the restoration policy. The CTA can at this stage either cancel the panel and go back to the active containers page or proceed further with the deleting by clicking on “Delete container”. + +![Container deletion selection](../../images/ctaux8.png) + +The selected container is successfully deleted and moved into the deleted containers page. + +![Deleted SPE Container](../../images/ctaux9.png) + +**Deleted containers are permanently purged after 93 days unless there is a retention policy applied to the containers.** + +## Restore a container + +A container in the deleted container collection can be restored on the Deleted containers page by selecting the corresponding containers by selecting the "Restore" link + +![Restore Button SPE Container](../../images/ctaux10.png) + +Restoration of the container happens in the background and the status of the same is displayed on the top-right corner of the page. Upon successful restoration, the container will be available in the Active Containers page. + +![Restored SPE Container](../../images/ctaux11.png) + +## Permanently delete a container + +> [!WARNING] +> Deleting a container may cause unexpected issues for the SharePoint Embedded application it belongs to and may interrupt the application's usage. This action should only be performed by admins when absolutely necessary. + +The CTA can permanently delete a deleted container from the deleted container collection if they decide to. + +The CTA selects the container to be permanently deleted. The “Permanently delete” button is enabled. + +![Permanent SPE Container deletion](../../images/ctaux12.png) + +Upon clicking the button, a pop-up appears. warning the CTA on the action they're performing. If sure, the CTA can proceed and select “Delete”. Otherwise, the CTA can cancel the action. + +![Container Deletion warning](../../images/ctaux13.png) + +Upon clicking Delete, the container is permanently deleted, and the status of the same appears in the top-right corner of the page. Upon successful deletion, the container is permanently removed from the deleted container collection and can't be restored. + +![SPE Container Deleted](../../images/ctaux15-n.png) + +## Sorting on Active containers page + +The CTA can perform their compliance and storage management tasks better through the use of sorting capabilities on the Active containers page. Currently, sorting is supported on the following columns: +1. Storage +1. Created on + +![ SPE Container Sorting](../../images/sorting.png) + +## Filtering on Active containers page + +The CTA can perform their compliance and storage management tasks better through the use of filtering capabilities on the Active containers page. Currently, filtering is supported on the following columns: + +1. Application name: The filter provides the list of all Microsoft SharePoint Embedded applications along with all SharePoint Embedded applications published by other publishers that is registered in the tenant. +1. Publisher: Describes whether the application is Microsoft-owned or published by an "Other" publisher. +1. Ownership type: The filter provides the options of Tenant, User, and Group, irrespective of the type of containers present in the tenant. +1. Principal owner: The filtering experience is a people picker experience. +1. Owner count: This filter provides a range of owner count for the administrator to choose from. +1. Created on: This filter provides a range of dates for the administrator to choose from. + +> [!IMPORTANT] +> The behaviour of the filtering experience on the Active containers page differs from the experience on the Active sites page in SharePoint Admin Center. + +![ SPE Container Filtering](../../images/filter.png) + +## Searching on Active Containers Page + +The search bar on the Active Containers Page can be used to search containers in the active state by their "container name". +![SPE Container Search](../../images/search.png) + +## Editing the sensitivity label of a container on the Active containers page + +The sensitivity label of a container can be set on the Active container page, on the detailed panel of a container. Under the settings panel, the administrator can set the sensitivity label from a list of available sensitivity label. + +![SPE Container Sensitivity](../../images/sensitivity-label.png) + +## Managing user membership of a container + +The administrator can manage the membership of users of a container on the Active container page, on the detailed panel of a container. Under the membership panel, the administrator can view the four roles and the corresponding users in each role. The administrator can: + +**Add a user to a role:** The administrator can navigate to the desired role using the left panel and click on the Add option. This opens up a picker, using which the administrator can select a user from the tenant and assign the role. In case the selected user is already assigned to a different role, the role is displayed when the role is selected and the operation changes from Add to Reassign. + +![SPE Container owner-one](../../images/add-owners-one.png) + +![SPE Container owner-two](../../images/add-owners-two.png) + +**Reassign user to another role:** The administrator can navigate to the desired user under a role using the left panel. On selecting the user, the Reassign option appears. On selecting the option, a drop-dowm menu appears and the administrator can select the role to which the user needs to be reassigned to. + +![ SPE Container reassingn](../../images/reassign-user.png) + +**Remove user from a role:** The administrator can navigate to the desired user under a role using the left panel. On selecting the user, the Remove option appears. On selecting the option, a pop-up screen appears, and the administrator can confirm the removal of the user from the role. + +![SPE Container remove](../../images/remove-user.png) + +## Sorting on the Deleted Containers Page + +Similar to the sorting experience on the Active containers page, the CTA can use sorting capabilities on the Deleted containers page. Currently, sorting is supported on the following columns: + +1. Storage +1. Created on +1. Deleted on + +![ SPE Container Sorting_on_Delete](../../images/sorting-on-deleted.png) + +## Filtering on the Deleted containers page + +The CTA can perform their compliance and storage management tasks better through the use of filtering capabilities on the Deleted containers page, on the following columns: + +1. Application name: The filter provides the list of all Microsoft SharePoint Embedded applications along with all SharePoint Embedded applications published by other publishers that is registered in the tenant. +2. Publisher: Describes whether the application is Microsoft-owned or published by an "Other" publisher. +3. Ownership type: The filter provides the options of Tenant, User, and Group, irrespective of the type of containers present in the tenant. +4. Principal owner: The filtering experience is a people picker experience. +5. Owner count: This filter provides a range of owner counts for the administrator to choose from. +6. Created on: This filter provides a range of dates for the administrator to choose from. +7. Deleted on: This filter provides a range of dates for the administrator to choose from. + +![ SPE Container Filter_on_Delete](../../images/filter-on-delete.png) + +## Upcoming features + +1. Search on the Deleted containers page +1. Sorting and filtering on the Sensitivity Label column diff --git a/docs/embedded/administration/consuming-tenant-admin/ctapowershell.md b/docs/embedded/administration/consuming-tenant-admin/ctapowershell.md new file mode 100644 index 000000000..6a46cc10d --- /dev/null +++ b/docs/embedded/administration/consuming-tenant-admin/ctapowershell.md @@ -0,0 +1,198 @@ +--- +title: Consuming Tenant Admin PowerShell +description: This article describes how an admin can manage containers through SPO PowerShell. +ms.date: 03/03/2025 +ms.localizationpriority: high +--- + +# SharePoint Embedded container management in PowerShell + +The consuming tenant administrator can manage containers using PowerShell commands, designed for container management. To access these commands, they must be assigned the role of Microsoft 365 SharePoint Embedded Administrator. Global Administrators in Microsoft 365 can assign users the SharePoint Embedded Administrator role. The Global Administrator role inherently includes all permissions of the SharePoint Embedded Administrator role. The SharePoint Embedded Administrator role is available in both Microsoft Entra and the Microsoft 365 Admin Center. + +For more information on assigning the SharePoint Embedded admin role, see the [SharePoint Embedded Administrator](../adminrole.md). + +The following are some of the container-specific command actions currently supported on PowerShell: + +### Application administration + +- Get the details of all SharePoint Embedded applications registered in the tenant +- Get the details of all SharePoint Embedded applications in the tenant sorted by storage +- Get the details of a specific SharePoint Embedded application in the tenant +- Get the permissions of the owning applications in the tenant +- Configure the External sharing setting of a container of a SharePoint Embedded application in the tenant + +### Container administration + +- Get details of all containers of a particular SharePoint Embedded application in the tenant +- Get details of a specific container +- Set the Sensitivity label of a specific container +- Soft delete a container +- Get details of all soft deleted containers +- Restore a soft deleted container +- Permanently delete a soft deleted container + +## Administration through SharePoint PowerShell + +Consuming tenant admin can manage SharePoint Embedded applications with PowerShell commands using [SharePoint Online Management Shell](/powershell/sharepoint/sharepoint-online/connect-sharepoint-online). + +To get started using PowerShell to manage SharePoint Embedded, you have to install the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588) and [connect to SharePoint Online](/powershell/module/sharepoint-online/connect-sposervice). + +> [!IMPORTANT] +> You must use the latest version of SharePoint PowerShell to use container administration cmdlets. + + +## Application Administration + +With PowerShell cmdlets, tenant admin can get a list of SharePoint Embedded applications registered in their Microsoft 365 tenancy. They can also view all the applications that have "read" and/or "write" access and the level of access to these SharePoint Embedded applications. + +The following commands can be used to manage SharePoint Embedded applications registered on your Microsoft 365 tenants: + +```powershell +Get-SPOApplication +``` + +```powershell +Get-SPOApplication -OwningApplicationId +``` + +For more information, see [Get-SPOApplication cmdlet](/powershell/module/sharepoint-online/get-spoapplication). + +### View guest application permissions + +Admins can view the guest application permissions for any SharePoint Embedded application within their tenant using this command: + +```powershell +Get-SPOApplication -OwningApplicationId -ApplicationId +``` + +`OwningApplicationId` is the ID of the SharePoint Embedded application and ApplicationId is the guest application ID that has access to the SharePoint Embedded application. Application Administration cmdlets don't apply to Microsoft Loop. For more information, see [Get-SPOApplication cmdlet](/powershell/module/sharepoint-online/get-spoapplication). + +### Set sharing capability of applications + +Consuming tenant admins can set the sharing capability at an application level to determine whether files of the containers of the application be shared with external guests or not. + +```powershell +Set-SPOApplication -OwningApplicationId – SharingCapability - OverrideTenantSharingCapability <$ OverrideTenantSharingCapability > +``` + +`SharingCapability` can take the following values: `Disabled`; `ExistingExternalUserSharingOnly`; `ExternalUserSharingOnly`; ExternalUserAndGuestSharing + +`$OverrideTenantSharingCapability` can take the following values: `$true`; `$false` + +## Container Administration + +### View Containers + +Admins can get a list of all the containers for a SharePoint Embedded application using the following commands. This command lists all the active containers within the application: + +```powershell +Get-SPOContainer -OwningApplicationId | FT +``` + +The `OwningApplicationId` is the ID of the SharePoint Embedded application. For more information about using this command, see [Get-SPOContainer cmdlet](/powershell/module/sharepoint-online/get-spocontainer). + +> [!NOTE] +> To enumerate Microsoft Loop containers, use Owning App ID: **a187e399-0c36-4b98-8f04-1edc167a0996** for all the cmdlets of container administration. + +### View containers sorted by storage +Consuming tenant admins can also get a list of all the containers of a SharePoint Embedded application sorted by storage using the following commands. + +```powershell +Get-SPOContainer -OwningApplicationId -SortByStorage | FT +``` + +`` can be `Ascending` or `Descending`. + +### View details of a Container + +Consuming tenant admins can get the details of a container within an application using the following command. This command returns more details of a container including StorageUsed, Ownership details, SiteURL, Label information, Owners count, etc. + +Consuming tenant admins can use the following command: + +```powershell +Get-SPOContainer -Identity +Get-SPOContainer -Identity +``` + +Here, the `containerId` is the ID of the container & `siteURL` is the URL of the SharePoint site that is associated with the container. + +### Sensitivity Label of a container + +Consuming tenant admins can set the sensitivity label of a container of an application using the following: + +```powershell +Set-SPOContainer -Identity -SensitivityLabel +``` + +Consuming tenant admins can remove the sensitivity label of a container of an application using the following: + +```powershell +Set-SPOContainer -Identity -RemoveLabel +``` + +The `ContainerId` is the ID of the container whose sensitivity label is being set. + +### Delete containers + +Deleting a container can have implications on the functionality of a SharePoint Embedded app, Here are some examples of the potential issues that an application can encounter when deleting a container. + +- Data Loss: Deleting a container removes all its content. If the SharePoint Embedded application relies on the data stored within the deleted container, the app might no longer function as expected or might lose access to critical information. +- Broken Links: If the SharePoint Embedded application contains links or references to the deleted container, those links become broken, leading to errors or malfunctioning features within the app. +- Permissions Issues: Deleting a container can affect permissions settings. If the SharePoint Embedded app relies on specific permissions granted to the deleted container, it might encounter permission issues and fail to function properly. + +Therefore, it's essential to carefully consider the consequences of deleting a container and ensure that appropriate measures are taken to mitigate any potential issues. + +### Permanent deletion + +When admins delete a Container, it goes into the Recycle Bin. A deleted container can be restored from the Recycle Bin within 93 days. If a container is deleted from the Recycle Bin, or it exceeds the 93-day retention period, it's permanently deleted. Deleting a container deletes everything within it, including all documents and files. + +Admins should notify the Container owners before they delete a Container so they can move their data to another location, and also inform users when the Container is deleted. + +> [!WARNING] +> Deleting a container may cause unexpected issues for the SharePoint Embedded application the Container belongs to and may interrupt usage of the application. + +```powershell +Remove-SPOContainer -Identity +``` + +The `ContainerId` is the ID of the container that is moved to the deleted container collection. For more information about using this command, see [Remove-SPOContainer cmdlet](/powershell/module/sharepoint-online/remove-spocontainer). + +### View deleted containers + +Admins can get a list of deleted containers on the deleted container collection using the following command. For more information about using this command, see [Get-SPODeletedContainer](/powershell/module/sharepoint-online/get-spodeletedcontainer). + +```powershell +Get-SPODeletedContainer +``` + +### Restore deleted containers + +Admins can restore a deleted container from the deleted container collection using the following command. For more information about using this command, see [Restore-SPODeletedContainer cmdlet](/powershell/module/sharepoint-online/get-spodeletedcontainer). + +```powershell +Restore-SPODeletedContainer -Identity +``` + +### Permanently delete containers + +Admins can permanently delete a container from the deleted container collection if the container has no further retention policies applied to it. For more information about using this command, see [Remove-SPODeletedContainer cmdlet](/powershell/module/sharepoint-online/remove-spodeletedcontainer). + +```powershell +Remove-SPODeletedContainer -Identity +``` + +### Guest application permission management + +If permitted, Admins can add, edit, and remove guest application access to SharePoint Embedded applications. A guest application is defined as any application within the enterprise applications of the owning tenant. For more information about using this command, see [Set-SPOApplicationPermission](/powershell/module/sharepoint-online/set-spoapplicationpermission). + +```powershell +Set-SPOApplicationPermission + [[-OwningApplicationId] ] + [[-ApplicationId] ] + [[-PermissionAppOnly] ] + [[-PermissionDelegated] ] +``` + +## Security and Compliance Administration + +SharePoint Embedded uses Microsoft’s comprehensive compliance and data governance solutions to help organizations manage risks, protect, and govern sensitive data, and respond to regulatory requirements. Security and compliance solutions work similarly in the SharePoint Embedded platform as they do today in the Microsoft 365 platform so that data is stored in a secure, protected way that meets customers’ business and compliance policies while making it easy for Compliance and SharePoint Administrators to enforce critical security and compliance policies on the content. For information on supported security and compliance capabilities, see [Security and Compliance](../../compliance/security-and-compliance.md). diff --git a/docs/embedded/administration/developer-admin/dev-admin.md b/docs/embedded/administration/developer-admin/dev-admin.md new file mode 100644 index 000000000..f9621225e --- /dev/null +++ b/docs/embedded/administration/developer-admin/dev-admin.md @@ -0,0 +1,149 @@ +--- +title: Developer Admin +description: This article describes the role and responsibilities of Developer Tenant Admin in SharePoint Embedded. +ms.date: 03/03/2024 +ms.localizationpriority: high +--- +# Developer Admin + +## Overview + +Organizations that use SharePoint Embedded for file management are included in the Developer Ecosystem, which is overseen by developer administrators. These administrators are responsible for managing applications and the container types that have containers, the foundation of an application that needs to store content. Additionally, they can connect billing profiles to their applications. This article describes the management features available to developer administrators. + +## Developer Admin Role + +> [!IMPORTANT] +> Global Administrators can assign the SharePoint Embedded Administrator role available in M365 Admin Center or Microsoft Entra to execute SharePoint Embedded container commandlets mentioned in this article. +> +> Global Administrators can continue to execute SharePoint Embedded container cmdlets. + +A Microsoft 365 SharePoint Embedded Administrator serves as the developer admin. Global Administrators in Microsoft 365 can assign users the SharePoint Embedded Administrator role. The Global Administrator role already has all the permissions of the SharePoint Embedded Administrator role. The SharePoint Embedded Role is available in Microsoft Entra and Microsoft 365 Admin Center. For information on [SharePoint Embedded Administrator](../adminrole.md) role. + +The following are some of the container-specific commands actions currently supported on PowerShell: + +- Creation of container types + - Creation of Standard container type with standard billing + - Creation of Standard container type with direct to customer billing + - Creation of Trial container type +- Container type management + - Viewing of container types in the tenant + - Editing properties of a container type in the tenant + - Configuration properties of a container type in the tenant + - Manage billing of applications/ container types for standard billing + - Removing a container type in the tenant + +### Billing responsibilities of the developer admin + +There are two types of billing models followed: + +Standard billing: +The developer admin is responsible for the billing of SharePoint Embedded applications. The developer admin needs to establish billing for SharePoint Embedded while creating container types given they have owner or contributor permissions on the Azure subscription that they use to establish the billing relationship on the product. To learn more about how to set up billing and manage cost and invoice, read about [PAYG for SharePoint Embedded](../billing/billing.md). + +Direct to Customer billing: +In this model, the customer, or the consuming tenant admin, is responsible for billing. To ensure the Direct to Customer (DTC) Billing model, the developer admin must set the billing property of Direct to customer to enabled. + +## Administration Tools + +Developer admins are able to manage SharePoint Embedded applications with PowerShell commands using SharePoint Online Management Shell. + +To get started using PowerShell to manage SharePoint Embedded, you have to install the SharePoint Online Management Shell and connect to SharePoint Online. + +> [!IMPORTANT] +> You must use the latest version of SharePoint PowerShell to use container type administration cmdlets. + +## PowerShell cmdlets for admin experience + +### Creation of container types + +The developer administrator can create a container type using PowerShell cmdlets. Each container type is associated to an application ID, a one to one mapping, and an Azure subscription ID. The developer administrator can also create Trial container types that have a validity of 30 days to test out SharePoint Embedded. The following [commands](/powershell/module/sharepoint-online/new-spocontainertype) can be used to create SharePoint Embedded container types on the developer admin’s tenant: + +Standard billing container type: + +```powershell +New-SPOContainerType -ContainerTypeName -OwningApplicationId -AzureSubscriptionId -ResourceGroup -Region ​ +``` +Direct to customer billing container type: + +```powershell +New-SPOContainerType -IsPassThroughBilling -ContainerTypeName -OwningApplicationId +``` + +Trial container type: + +```powershell +New-SPOContainerType –TrialContainerType -ContainerTypeName -OwningApplicationId +``` + +OwningApplicationId is the ID of the SharePoint Embedded application. Azure Subscription ID is the ID of the Microsoft Entra ID profile for billing purposes. + +### Viewing of container types + +The developer administrator can view container types and the corresponding applications created in their tenant using PowerShell commandlets. The following commands can be used to view SharePoint Embedded applications created on the developer admin’s tenant: + +```powershell +Get-SPOContainerType​ +Get-SPOContainerType -ContainerTypeId +``` + +### Manage properties of container types + +Using PowerShell cmdlets, the developer administrator can change the properties of container types, both standard and trial. The following commands can be used to change the properties SharePoint Embedded applications created on the developer admin’s tenant: + +```powershell +Set-SPOContainerType -ContainerTypeId + [-OwningApplicationId ] + [-ContainerTypeName ] + [-WhatIf] [-Confirm] +``` + +### Container type configuration properties + +The developer administrator can change container type configuration settings using PowerShell commandlets. The following container type properties can be set: + +1. Discoverability Disabled: Controls if file items inside the container surface in other Microsoft 365 properties (MRU, etc.). +1. Sharing Restricted: Only manager and owner can share files in the container if restricted sharing is true. + +The following commands can be used to change the configuration settings of SharePoint Embedded applications created on the developer admin’s tenant: + +```powershell +Set-SPOContainertypeConfiguration -ContainerTypeId < ContainerTypeId > -DiscoverabilityDisabled $value +``` + +For `DiscoverabilityDisabled` `$value` can be set to `$true`; `$false` + +The default value `$true` - ensures all content is hidden. + +```powershell +Set-SPOContainertypeConfiguration -ContainerTypeId < ContainerTypeId > -SharingRestricted $value +``` + +For `SharingRestricted` `$value` can be set to `$true`; `$false` + +```powershell +Set-SPOContainertypeConfiguration -ContainerTypeId < ContainerTypeId > - DiscoverabilityDisabled $value -SharingRestriced $value +``` + +The developer admin can view the container type configuration settings using the following cmdlet: + +```powershell +Get-SPOContainertypeConfiguration -ContainerTypeId < ContainerTypeId > +``` + +## Manage billing profile of applications/ container types + +The developer administrator can change the billing profile of container types using PowerShell cmdlets. The following commands can be used to change the properties SharePoint Embedded applications created on the developer admin’s tenant: + +```powershell +Set-SPOContainerType -ContainerTypeId + [-AzureSubscriptionId ] + [-ResourceGroup ]​[-WhatIf] + [-Confirm] +``` + +For more information about billing, see [Billing](../billing/billing.md). + +## Roles and Permissions + +The user or admin who creates the billing relationship for SharePoint Embedded needs to have owner or contributor permissions on an Azure subscription. + +If you don't have an Azure subscription, follow steps here to [create a subscription.](/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions) diff --git a/docs/embedded/concepts/security-and-compliance.md b/docs/embedded/compliance/security-and-compliance.md similarity index 63% rename from docs/embedded/concepts/security-and-compliance.md rename to docs/embedded/compliance/security-and-compliance.md index 5079b9a7e..af95b70a3 100644 --- a/docs/embedded/concepts/security-and-compliance.md +++ b/docs/embedded/compliance/security-and-compliance.md @@ -1,17 +1,17 @@ --- title: Security and Compliance description: Details Security and Compliance methods provided by SharePoint Embedded -ms.date: 04/09/2024 +ms.date: 03/03/2025 ms.localizationpriority: high --- # Security and Compliance -Microsoft's SharePoint Embedded provides a faster way to create secure and compliant documents stored in various applications. SharePoint Embedded uses Microsoft’s comprehensive compliance and data governance solutions to help organizations manage risks, protect, and govern sensitive data, and respond to regulatory requirements. Security and compliance solutions will work in a similar manner in the SharePoint Embedded platform as they do today on the Microsoft 365 (Microsoft 365) platform so that data is stored in a secure, protected way that meets customers’ business and compliance policies while making it easy for Compliance and SharePoint Administrators to enforce critical security and compliance policies on the content. +Microsoft's SharePoint Embedded provides a faster way to create secure and compliant documents stored in various applications. SharePoint Embedded uses Microsoft’s comprehensive compliance and data governance solutions to help organizations manage risks, protect, and govern sensitive data, and respond to regulatory requirements. Security and compliance solutions work similarly in the SharePoint Embedded platform as they do today on the Microsoft 365 (Microsoft 365) platform so that data is stored in a secure, protected way that meets customers’ business and compliance policies while making it easy for Compliance and SharePoint Administrators to enforce critical security and compliance policies on the content. In this article, we describe the security and compliance policies that are supported today on content that resides in the SharePoint Embedded platform, and their capabilities and limitations. -Since SharePoint Embedded by design doesn’t have any user interface, some Compliance scenarios necessitating user interaction aren't natively supported. The owning application that governs the Container can choose to support these scenarios and provide the optimal experience to end users by using existing Microsoft Graph API. +Since SharePoint Embedded by design doesn’t have any user interface, some Compliance scenarios necessitating user interaction aren't natively supported. The owning application that governs the container can choose to support these scenarios and provide the optimal experience to end users by using the Microsoft Graph. ## Compliance Policies using Microsoft Purview @@ -23,23 +23,23 @@ Currently, SharePoint Embedded supports the following Compliance features under Get-SPOApplication ``` -1. Retrieve a list of Containers in a SharePoint Embedded application by providing the ApplicationID returned in Step #1 +1. Retrieve a list of containers in a SharePoint Embedded application by providing the ApplicationID returned in Step #1: ```powershell Get-SPOContainer -OwningApplicationId ``` -1. Retrieve the details of a container including the ContainerSiteURL by providing the ContainerID returned in Step #2. +1. Retrieve the details of a container including the ContainerSiteURL by providing the ContainerID returned in Step #2: ```powershell Get-SPOContainer -OwningApplicationId -Identity ``` -For information on how to retrieve the `ContainerSiteURL` to set the various compliance policies described in this article at a Container level, see [Get-SPOContainer](/powershell/module/sharepoint-online/get-spocontainer). +For information on how to retrieve the `ContainerSiteURL` to set the various compliance policies described in this article at a container level, see [Get-SPOContainer](/powershell/module/sharepoint-online/get-spocontainer). ### Audit -The Audit capabilities provided by SharePoint Embedded mirror the existing Audit functionalities currently supported within SharePoint Online. All user and admin operations performed in various applications hosted in SharePoint Embedded are captured, recorded, and retained in your organization's unified audit log. For more information on Audit, see [Auditing solutions in Microsoft Purview](/purview/audit-solutions-overview). +The Audit capabilities provided by SharePoint Embedded mirror the existing Audit functionalities currently supported within SharePoint. All user and admin operations performed in various applications hosted in SharePoint Embedded are captured, recorded, and retained in your organization's unified audit log. For more information on Audit, see [Auditing solutions in Microsoft Purview](/purview/audit-solutions-overview). In addition to existing file properties, Audit events related to SharePoint Embedded are logged with the following more data to help filter the Audit search results to isolate the relevant SharePoint Embedded content: @@ -48,15 +48,16 @@ In addition to existing file properties, Audit events related to SharePoint Embe ![Audit events](../images/sc1.png) + ### eDiscovery Compliance Admins can use eDiscovery tools in Microsoft Purview to search/hold/export content hosted in the SharePoint Embedded platform. For more information on eDiscovery, see [Microsoft Purview eDiscovery solutions](/purview/ediscovery). -To perform an eDiscovery Search on all SharePoint Embedded content, Admins should select on ‘All’ SharePoint Sites when configuring the eDiscovery Search in Microsoft Purview. This enables the Search for content stored in all SharePoint Online Sites and all SharePoint Embedded Containers. +To perform an eDiscovery Search on all SharePoint Embedded content, Admins should select **All** SharePoint Sites when configuring the eDiscovery Search in Microsoft Purview. This enables the Search for content stored in all SharePoint Sites and all SharePoint Embedded containers. ![eDiscovery search](../images/sc2.png) -To limit the eDiscovery Search to one/few SharePoint Embedded Containers, Admins can ‘Choose sites’ under the ‘SharePoint sites’ workload and provide the desired Container URL – +To limit the eDiscovery Search to one/few SharePoint Embedded containers, Admins can **Choose sites** under the **SharePoint sites** workload and provide the desired container URL. ![choose sites in eDiscovery search](../images/sc3.png) @@ -64,37 +65,37 @@ To limit the eDiscovery Search to one/few SharePoint Embedded Containers, Admins SharePoint Embedded supports retention and holds policies on content stored in its applications using the Microsoft Purview compliance portal. For more information on DLM, see [Learn about Microsoft Purview Data Lifecycle Management](/purview/data-lifecycle-management). -The existing retention policy is applied to all SharePoint Embedded Containers if the policy is configured for ‘All sites’. Similarly, creating a new retention/hold policy on *All* SharePoint Sites workload will automatically enforce the policy on all SharePoint Online Sites and all Containers within SharePoint Embedded. +The existing retention policy is applied to all SharePoint Embedded containers if the policy is configured for **All sites**. Similarly, creating a new retention/hold policy on *all* SharePoint Sites workload automatically enforces the policy on all SharePoint Sites and all containers within SharePoint Embedded. ![retention policy](../images/sc4.png) -To selectively enforce the policy on one/few SharePoint Embedded Containers, copy the Container URL and configure the policy to be selectively enforced only on those Container(s). +To selectively enforce the policy on one or more SharePoint Embedded containers, copy the container URL and configure the policy to be selectively enforced only on those containers. ![enforce retention policy](../images/sc5.png) -Since SharePoint Embedded doesn't have a built-in user interface, DLM scenarios requiring user interaction aren't natively supported. For instance, if an end user attempts to apply a retention label on a Container using a SharePoint Embedded application (app), the app governing the access to the Container must furnish that functionality. In such cases, Graph APIs for DLM functionalities can be used. +Since SharePoint Embedded doesn't have a built-in user interface, DLM scenarios requiring user interaction aren't natively supported. For instance, if an end user attempts to apply a retention label on a container using a SharePoint Embedded application (app), the app governing the access to the container must furnish that functionality. In such cases, Graph APIs for DLM functionalities can be used. -### Data Loss Protection (DLP) - Coming soon +### Data Loss Protection (DLP) Using Microsoft Purview, Admins can identify, monitor, and automatically protect sensitive items stored in applications using SharePoint Embedded. For more information on DLP, see  [Learn about data loss prevention](/purview/dlp-learn-about-dlp). -Like retention policies, DLP policies can be enforced on all SharePoint Online Sites and SharePoint Embedded Containers by choosing to configure the policy on ‘All sites’. +Like retention policies, DLP policies can be enforced on all SharePoint Sites and SharePoint Embedded containers by choosing to configure the policy on ‘All sites’. ![DLP Policy](../images/sc6.png) -Admins can also restrict the enforcement of a DLP policy to specific SharePoint Embedded Containers by specifying the relevant Container URL(s) during policy configuration. +Admins can also restrict the enforcement of a DLP policy to specific SharePoint Embedded containers by specifying the relevant container URLs during policy configuration. ![Configure DLP Policy](../images/sc7.png) Several scenarios supported by DLP today need user interaction that isn’t natively supported by SharePoint Embedded. For instance, based on its configuration, a DLP policy that prevents external sharing might allow end users to provide a business justification to override the policy. The client app that renders this DLP-flagged file item needs to support such user interactions. -Policy tips are shown today for files hosted in SharePoint Online so that users are kept informed about DLP-flagged file items and corresponding restrictions. Similarly, for policy tips to be displayed for files hosted in SharePoint Embedded, the client app can choose to provide more support by utilizing the existing Graph APIs for this purpose. +Policy tips are shown today for files hosted in SharePoint so that users are kept informed about DLP-flagged file items and corresponding restrictions. Similarly, for policy tips to be displayed for files hosted in SharePoint Embedded, the client app can choose to provide more support by utilizing the Microsoft Graph for this purpose. -## Security Features +## Security features -### Sensitivity labels on Containers +### Sensitivity labels on containers -Global Administrators and SharePoint Administrators can set and remove sensitivity labels on a SharePoint Embedded Container by using the newly created SharePoint PowerShell cmdlet: +Global Administrators and SharePoint Administrators can set and remove sensitivity labels on a SharePoint Embedded container by using the newly created SharePoint PowerShell cmdlet: ```powershell Set-SPOContainer -Identity -SensitivityLabel @@ -102,9 +103,9 @@ Set-SPOContainer -Identity -SensitivityLabel -BlockDownloadPolicy $true @@ -112,7 +113,7 @@ Set-SPOSite -Identity -BlockDownloadPolicy $true A SharePoint Advanced Management (SAM) license is needed to enforce this policy. Read the full documentation for advanced capabilities at [Block download policy for SharePoint sites and OneDrive](/sharepoint/block-download-from-sites). -### Conditional Access policy (Coming Soon) +### Conditional Access policy SharePoint Embedded supports basic Conditional Access policy configurations such as: @@ -126,4 +127,4 @@ These settings are available with the following PowerShell cmdlet. The `Authoriz Set-SPOContainer -Identity -ConditionalAccessPolicy ``` -To learn more about Conditional Access Policy, see [Control access from unmanaged devices](/sharepoint/control-access-from-unmanaged-devices). +To learn more about conditional access policies, see [Control access from unmanaged devices](/sharepoint/control-access-from-unmanaged-devices). diff --git a/docs/embedded/concepts/admin-exp/billing.md b/docs/embedded/concepts/admin-exp/billing.md deleted file mode 100644 index 6996f7924..000000000 --- a/docs/embedded/concepts/admin-exp/billing.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: PAYG billing for SharePoint Embedded -description: This article explains how to set up PAYG billing -ms.date: 04/09/2024 -ms.localizationpriority: high ---- - -# SharePoint Embedded Billing experience - -This document outlines the steps an admin has to follow to set up billing, evaluate actual and forecast costs, and pay invoices on SharePoint Embedded. - -SharePoint Embedded will be a consumption based Pay-as-you-go (PAYG) offering from SharePoint Online, which means you pay only for what you use. As a Developer admin for SharePoint Embedded, you set up billing on a container type using SharePoint Online Management Shell and manage forecast of actual costs and invoices in Microsoft Azure portal. - -![Billing pay-as-you-go.](../../images/billing-manage.png) - -## Set up Pay-as-you-go (PAYG) for SharePoint Embedded - -To enable PAYG on SharePoint Embedded, you need: - -1. Existing SharePoint tenancy -1. An Azure subscription in the tenancy -1. A resource group attached to the Azure subscription - -## Roles and Permissions - -- Admin who sets up billing relationship for SharePoint Embedded need to have owner or contributor permissions on Azure subscription. -- Admin needs to have a SharePoint Embedded Administrator role to operate billing cmdlets. - -## Steps to establish billing - -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. -1. Create container type using `New-SPOContainerType` cmdlet by providing an **azure subscription**, **resource group** associated with the subscription and a **region**. - - 1. If you don't have an Azure subscription, you can create on by following steps here to [create an Azure subscription in your tenancy](/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions) - 1. If you don't have a resource group, you can create on by following steps here to [create a resource group](/azure/azure-resource-manager/management/manage-resource-groups-portal) - -```powershell -New-SPOContainerType -ContainerTypeName - -OwningApplicationId - -AzureSubscriptionId - -ResourceGroup - -Region -``` - -## Applicable guidelines - -1. Every container type must have an owning application. -1. A single owning app can only own one container type at a time. -1. An Azure subscription can be attached to any number of container types. - -## View/Edit billing properties - -View the properties of billing. You can view properties of a ContainerType and associated billing properties by using one of the two PowerShell cmdlets: - -1. To see all Container Types and billing properties except associated region: - - ```powershell - Get-SPOContainerType - ``` - -1. To see billing properties associated with a container type including region: - - ```powershell - Get-SPOContainerType -ContainerTypeId - ``` - -1. Update Azure subscription or resource group associated with a container type: - - ```powershell - Set-SPOContainerType -ContainerTypeId [-AzureSubscriptionId ] [-ResourceGroup ] - ``` - -## Pricing & PAYG meters - -Review the Pricing and PAYG meters for SharePoint Embedded in the [terms of service](../../terms-of-service.md). - -## Manage consumption and invoices in Azure portal - -1. Sign in to **[Azure Portal](https://portal.azure.com/)**. -1. Search for **Cost Management + Billing**. -1. Select **Cost Analysis** to see: - - - **Actual cost** - - ![Azure Cost Analysis - Actual Cost.](../../images/billing-1.png) - - - Select '**+ Add Filter**' to see breakdown of cost by **containertypeid** and **tenantid** - - Select **Tag** - - In the key-value pair, select **containertypeid** or **tenantid** and select respective **containertypeid** and **tenantid** - - ![Azure Cost Analysis - Filter by Tag.](../../images/billing-2.png) - -1. Select **Billing** on the left navigation to see monthly invoices. -1. Set up **Budget alerts** on cost by following steps [here](/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending). diff --git a/docs/embedded/concepts/admin-exp/cta.md b/docs/embedded/concepts/admin-exp/cta.md deleted file mode 100644 index f96da29c3..000000000 --- a/docs/embedded/concepts/admin-exp/cta.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: Consuming Tenant Admin -description: This article describes the role and responsibilities of Consuming Tenant Admin in SharePoint Embedded. -ms.date: 04/09/2024 -ms.localizationpriority: high ---- - -# Consuming Tenant Admin - -> [!IMPORTANT] -> Assign the SharePoint Embedded Administrator role available in M365 Admin Center or Microsoft Entra to execute SharePoint Embedded Container commandlets mentioned in this article. -> -> Global Administrators can continue to execute SharePoint Embedded container cmdlets. -> -> If you are a SharePoint Administrator, grant yourself the SharePoint Embedded Admin role as well to execute these cmdlets. - -The organizations that use the SharePoint Embedded applications on their Microsoft 365(Microsoft 365) tenants are the consuming tenants and the persona that is responsible for managing these applications on their Microsoft 365 tenancy is the consuming tenant administrator. Consuming tenant administrators can perform various administrative actions on the SharePoint Embedded applications registered on their Microsoft 365 tenant and on the Containers that hold the content. They can also manage tenant level configurations and ensure that data is stored in a secure, protected way that meets customers’ business and compliance policies. In this article, we describe the enterprise manageability features that are supported and can be performed by the consuming tenant administrator. - -## Consuming Tenant Admin Role - -Microsoft 365 SharePoint Embedded Administrator serves as the consuming tenant admin. Global Administrators in Microsoft 365 can assign users the SharePoint Embedded Administrator. The Global Administrator role already has all the permissions of the SharePoint Embedded Administrator role. A SharePoint Administrator can assign themselves the SharePoint Embedded Administrator role to act as a Consuming Tenant Admin for SharePoint Embedded. The SharePoint Embedded Role is available in Microsoft Entra and Microsoft 365 Admin Center. - -## Administration Tools - -Consuming tenant admins are able to manage SharePoint Embedded applications with PowerShell commands using [SharePoint Online Management Shell](/powershell/sharepoint/sharepoint-online/connect-sharepoint-online). - -To get started using PowerShell to manage SharePoint Embedded, you have to install the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588) and [connect to SharePoint Online](/powershell/module/sharepoint-online/connect-sposervice). - -> [!IMPORTANT] -> You need version 16.0.24211.12000 or higher to run the commands for SharePoint Embedded. - -## Application Administration - -With PowerShell cmdlets, tenant admin can get a list of SharePoint Embedded applications registered in their Microsoft 365 tenancy. They can also view all the applications that have "read" and/or "write" access and the level of access to these SharePoint Embedded applications. - -The following commands can be used to manage SharePoint Embedded applications registered on your Microsoft 365 tenants. - -```powershell -Get-SPOApplication - -# or - -Get-SPOApplication -OwningApplicationId - -# or - -Get-SPOApplication -OwningApplicationId -ApplicationId -``` - -OwningApplicationId is the ID of the SharePoint Embedded application and ApplicationId is the ID of the application that has access to the SharePoint Embedded application. Application Administration cmdlets aren't applicable for Microsoft Loop. For more information about using this command, see [Get-SPOApplication cmdlet](/powershell/module/sharepoint-online/get-spoapplication). - -## Container Administration - -### View Containers - -Admins can get a list of all the containers for a SharePoint Embedded application using the following commands. This command lists all the active containers within the application. - -```powershell -Get-SPOContainer -OwningApplicationId | FT -``` - -The `OwningApplicationId` is the ID of the SharePoint Embedded application. For more information about using this command, see [Get-SPOContainer cmdlet](/powershell/module/sharepoint-online/get-spocontainer). To enumerate Microsoft Loop containers, use Owning App ID: a187e399-0c36-4b98-8f04-1edc167a0996 for all the cmdlets of container administration. - -### View details of a Container - -Admins can get the details of a container within an application using the following command. This command returns more details of a container including StorageUsed, Ownership details, SiteURL, Label information etc. - -```powershell -Get-SPOContainer -OwningApplicationId -Identity -``` - -Here, the Identity is the ID of the Container. For more information about using this command, see [Get-SPOContainer cmdlet](/powershell/module/sharepoint-online/get-spocontainer). - -### Delete Containers - -Deleting a container can have implications on the functionality of a SharePoint Embedded app, Here are some examples of the potential issues that an application can encounter when deleting a container. - -- Data Loss: Deleting a container removes all its content. If the SharePoint Embedded application relies on the data stored within the deleted container, the app might no longer function as expected or might lose access to critical information. -- Broken Links: If the SharePoint Embedded application contains links or references to the deleted container, those links become broken, leading to errors or malfunctioning features within the app. -- Permissions Issues: Deleting a container can affect permissions settings. If the SharePoint Embedded app relies on specific permissions granted to the deleted container, it might encounter permission issues and fail to function properly. - -Therefore, it's essential to carefully consider the consequences of deleting a container and ensure that appropriate measures are taken to mitigate any potential issues. - -### Permanent Deletion - -When admins delete a Container, it goes into the Recycle Bin. A deleted container can be restored from the Recycle Bin within 93 days. If a container is deleted from the Recycle Bin, or it exceeds the 93-day retention period, it's permanently deleted. Deleting a container deletes everything within it, including all documents and files. - -Admins should notify the Container owners before they delete a Container so they can move their data to another location, and also inform users when the Container is deleted. - -> [!WARNING] -> Deleting a container may cause unexpected issues for the SharePoint Embedded application the Container belongs to and may interrupt usage of the application. - -```powershell -Remove-SPOContainer -Identity -``` - -The `ContainerId` is the ID of the container that is moved to the deleted container collection. For more information about using this command, see [Remove-SPOContainer cmdlet](/powershell/module/sharepoint-online/remove-spocontainer). - -### View deleted containers - -Admins can get a list of deleted containers on the deleted container collection using the following command. For more information about using this command, see [Get-SPODeletedContainer](/powershell/module/sharepoint-online/get-spodeletedcontainer). - -```powershell -Get-SPODeletedContainer -``` - -### Restore deleted containers - -Admins can restore a deleted container from the deleted container collection using the following command. For more information about using this command, see [Restore-SPODeletedContainer cmdlet](/powershell/module/sharepoint-online/get-spodeletedcontainer). - -```powershell -Restore-SPODeletedContainer -Identity -``` - -### Permanently delete Containers - -Admins can permanently delete a Container from the deleted container collection if the Container has no further retention policies applied to it. For more information about using this command, see [Remove-SPODeletedContainer cmdlet](/powershell/module/sharepoint-online/remove-spodeletedcontainer). - -```powershell -Remove-SPODeletedContainer -Identity -``` - - -## Security and Compliance Administration - -SharePoint Embedded uses Microsoft’s comprehensive compliance and data governance solutions to help organizations manage risks, protect, and govern sensitive data, and respond to regulatory requirements. Security and compliance solutions work in a similar manner in the SharePoint Embedded platform as they do today in Microsoft 365 platform so that data is stored in a secure, protected way that meets customers’ business and compliance policies while making it easy for Compliance and SharePoint Administrators to enforce critical security and compliance policies on the content. For information on supported security and compliance capabilities, see [Security and Compliance](../security-and-compliance.md). diff --git a/docs/embedded/concepts/admin-exp/dev-admin.md b/docs/embedded/concepts/admin-exp/dev-admin.md deleted file mode 100644 index 0dda0cd40..000000000 --- a/docs/embedded/concepts/admin-exp/dev-admin.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: Developer Admin -description: This article describes the role and responsibilities of Developer Tenant Admin in SharePoint Embedded. -ms.date: 04/09/2024 -ms.localizationpriority: high ---- -# Developer Admin - -## Overview - -Organizations that create file management applications with the help of SharePoint Embedded are referred to as Developer Ecosystem (yet to be finalized), and the persona responsible for the management of the applications is called the developer administrator. Developer administrators can perform various administrative actions on the SharePoint Embedded applications created and on the Container types, the blueprint for the containers that hold the content of instances of the application. They can also create and manage trial container types to get started with the SharePoint Embedded experience, attach billing profiles to their application, etc. In this article, we describe the enterprise manageability features that are supported and can be performed by the developer administrator. - -## Developer Admin Role - -A Microsoft 365 SharePoint Embedded Administrator serves as the developer admin. Global Administrators in Microsoft 365 can assign users the SharePoint Embedded Administrator role. The Global Administrator role already has all the permissions of the SharePoint Embedded Administrator role. For information about assigning a user the SharePoint Embedded Administrator role, see Assign admin roles in the Microsoft 365 admin center. - -### Billing responsibilities of Developer admin - -The developer admin need to establish billing for SharePoint Embedded while creating container types given they have owner or contributor permissions on the Azure subscription that they use to establish the billing relationship on the product. To learn more about how to set up billing and manage cost and invoice, read about PAYG for [SharePoint Embedded.](./billing.md). - -## Administration Tools - -Developer admins are able to manage SharePoint Embedded applications with PowerShell commands using SharePoint Online Management Shell. - -To get started using PowerShell to manage SharePoint Embedded, you have to install the SharePoint Online Management Shell and connect to SharePoint Online. - -> [!IMPORTANT] -> You need version 16.0.24211.12000 or higher to run the commands for SharePoint Embedded. - -> [!IMPORTANT] -> Assign the SharePoint Embedded Administrator role available in M365 Admin Center or Microsoft Entra to execute SharePoint Embedded Container commandlets mentioned in this article. -> -> Global Administrators can continue to execute SharePoint Embedded container cmdlets. -> -> If you are a SharePoint Administrator, grant yourself the SharePoint Embedded Admin role as well to execute these cmdlets. - -## PowerShell cmdlets for admin experience - -### Creation of container types - -Using PowerShell cmdlets, the developer administrator can create container types and attach it to an application ID (One to one mapping) and Azure subscription ID. The administrator can also create trial container types that have a validity of 30 days to get a feel of the standard container types. The following commands can be used to create SharePoint Embedded applications on the developer admin’s tenant: - -```powershell -New-SPOContainerType -ContainerTypeName -OwningApplicationId -AzureSubscriptionId -ResourceGroup -Region ​ -``` - -```powershell -New-SPOContainerType –TrialContainerType -ContainerTypeName -OwningApplicationId -``` - -OwningApplicationId is the ID of the SharePoint Embedded application. Azure Subscription ID is the ID of the Microsoft Entra ID profile for billing purposes. - -### Viewing of container types - -Using PowerShell cmdlets, the developer administrator can view container types and the corresponding applications created in their tenant. The following commands can be used to view SharePoint Embedded applications created on the developer admin’s tenant: - -```powershell -Get-SPOContainerType​ -Get-SPOContainerType -ContainerTypeId -``` - -### Manage properties of container types - -Using PowerShell cmdlets, the developer administrator can change the properties of container types, both standard and trial. The following commands can be used to change the properties SharePoint Embedded applications created on the developer admin’s tenant: - -```powershell -Set-SPOContainerType -ContainerTypeId - [-OwningApplicationId ] - [-ContainerTypeName ] - [-WhatIf] [-Confirm] -``` - -## Manage billing profile of applications/ container types - -Using PowerShell cmdlets, the developer administrator can change the billing profile of container types. The following commands can be used to change the properties SharePoint Embedded applications created on the developer admin’s tenant: - -```powershell -Set-SPOContainerType -ContainerTypeId - [-AzureSubscriptionId ] - [-ResourceGroup ]​[-WhatIf] - [-Confirm] -``` - -For more information about billing, see [Billing](./billing.md). - -## Roles and Permissions - -The user or admin who will set up billing relationship for SharePoint Embedded need to have owner or contributor permissions on an Azure subscription. - -If you don't have an Azure subscription, follow steps here to [create a subscription.](/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions) \ No newline at end of file diff --git a/docs/embedded/concepts/app-concepts/app-architecture.md b/docs/embedded/concepts/app-concepts/app-architecture.md deleted file mode 100644 index 94eed054a..000000000 --- a/docs/embedded/concepts/app-concepts/app-architecture.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: App Architecture -description: Anatomy of a SharePoint Embedded application -ms.date: 11/28/2023 -ms.localizationpriority: high ---- - -# SharePoint Embedded App Architecture - -All files and documents in SharePoint Embedded are stored in Containers. All Containers are created and stored within a Microsoft 365 Tenant. The ISV or LOB app then uses the Microsoft Graph API to interact with the dedicated Container(s) for that app. The Containers are part of the Microsoft 365 customer’s tenant regardless of how the app is deployed. - -![SharePoint Embedded Capabilities](../../images/architecture-overview.png) - -## Container Relationship - -- Every Container Type is owned by one SharePoint Embedded Application -- Only the app owning a Container Type might create instances of a Container. -- Container instances must belong to a Container Type. -- An app might instantiate zero or more Container instances for a given Container Type. -- Apps can grant permission to other apps to create, read, update, and/or delete Container instances of Container Types of the owning app, for example, to allow backup/restore or DLP apps to operate on content in those Containers and/or create instances of the Container Type. Note, the owning application is charged for storage in all instances of a Container Type regardless of which app originally instantiated the Container. - -## SharePoint Embedded Containers and Container Types - -Container Type is a property stamped on every Container instance. Each Container Type is owned by one Application; and each Application can own only one Container Type. To learn more about Container Types, see [Container Type](./containertypes.md) - -![SharePoint Embedded Flow](../../images/app-flow7.jpg) diff --git a/docs/embedded/concepts/app-concepts/auth.md b/docs/embedded/concepts/app-concepts/auth.md deleted file mode 100644 index a2bd9e8d3..000000000 --- a/docs/embedded/concepts/app-concepts/auth.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: Authentication and Authorization with SharePoint Embedded -description: This article describes the Authentication process for SharePoint Embedded Applications. -ms.date: 11/28/2023 -ms.localizationpriority: high ---- - -# Authentication and Authorization with SharePoint Embedded - -### SharePoint Embedded Workflow - -1. An app creator (an enterprise or Independent Software Vendor-ISV) builds an app that uses SharePoint Embedded containers - - App created in Microsoft Entra ID - - Container Type creation requested and ContainerTypeID received to develop the app -1. A subscriber (Consuming Tenant) installs the app into a Microsoft 365 tenant -1. The app instantiates a container -1. The app uses Graph APIs to manage files and folders (DriveItems) in the Container (Drive) -1. The app can link to the `webUrl` property of DriveItems to view, edit, and coauthor Office document types in Office Online (via Web browser) -1. The Consuming Tenant security and compliance (S & C) admins can now run Microsoft 365 S & C workflows against the container - -### App-Only vs Delegated - -SharePoint Embedded supports both App-Only and Delegated (App+User) calls for enterprise applications. App-only calls allow applications to utilize the SharePoint Embedded platform to manage containers without a signed-in user; while Delegated calls allow applications to manage containers via the SharePoint Embedded platform on behalf of the signed-in users. - -Both App-Only and Delegated SharePoint Embedded from trusted (or private) client applications are allowed. SharePoint Embedded authorization management blocks public clients from making API calls to create containers, whether they're App-Only or Delegated. - -## Container.Selected Scope - -The [Register Container Type API](register-api-documentation.md) uses the Container.Selected scope. To call it, you must configure this scope in your App manifest. - -> [!NOTE] -> Other SharePoint Embedded Graph APIs run with the `FileStorageContainer.Selected` scope on Microsoft Graph - -### Configure your App Manifest - -In your app manifest you need to: - -Select **Manage > Manifest** from the left-hand navigation. Locate the property `requiredResourceAccess` and edit it so it looks like the following JSON: - -```json -"requiredResourceAccess": [ - { - "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { - "id": "4d114b1a-3649-4764-9dfb-be1e236ff371", - "type": "Scope" - }, - { - "id": "19766c1b-905b-43af-8756-06526ab42875", - "type": "Role" - } - ] - }, - { - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { - "id": "085ca537-6565-41c2-aca7-db852babc212", - "type": "Scope" - }, - { - "id": "40dc41bc-0f7e-42ff-89bd-d9516947e474", - "type": "Role" - } - ] - } -], -``` - -## Required Permissions - -| ScopeName | Type | Description | -|:------------------:|:-----------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| -| Container.Selected | Application | Allows the application to utilize the file storage container platform to manage containers without a signed in user. The specific file storage containers and the permissions granted to them are configured in Microsoft 365 by the developer of each container type. | - -> [!IMPORTANT] -> You must configure the `Container.Selected` scope in your App manifest - -### User Roles - -Any user accessing a container must be a member of the container. Membership to a container is categorized into four roles. If you add a user to a container, the user must be assigned to one of these roles. - -> [!NOTE] -> The calling user creating a new container via delegated calls is automatically assigned the owner role. - -| Role | Description | -| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Reader | This role allows the user to read the properties and the contents of the container. | -| Writer | This role has all permissions a Reader has, plus the permission to create, update, and delete content inside the container, and to update applicable container properties. | -| Manager | This role has all permissions a Writer has, plus the permission to manage membership of the container. | -| Owner | This role has all permissions a Manager has, plus the permission to delete containers. | - -### ContainerTypeID - -Operation calls to SharePoint Embedded are authorized based on both the AppID of the calling application and targeting ContainerTypeID. As part of the SharePoint Embedded onboarding process, SharePoint Embedded partners need to inform the SharePoint Embedded platform the set of operations to authorize for the AppID against the specified ContainerTypeID. Once configured, the AppID is authorized for the set of operations against all container instances of the specific container type. - -## Authorization - -Authorization for SharePoint Embedded calls is a function of the AppID and ContainerTypeID for App-Only calls; and a function of AppID, ContainerTypeID, and User Roles for Delegated (App+User) calls. - -For App-only calls, SharePoint Embedded authorization is determined by the configured permissions tied to the AppID-ContainerTypeID pair. For Delegated calls, SharePoint Embedded authorization is the intersection of the application’s permissions against a container type and the permissions granted to the user’s roles. - -Consider the following examples with the assumptions: - -1. App1 has Create, Read, and Write permissions to ContainerType1; and... -1. UserA is a reader for ContainerX of ContainerType1. - -| Example | Result | Reason | -| --------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------- | -| App1 attempts an App-Only call to write a container of ContainerType1 | Allowed | App1 has the permission to write to containers of ContainerType1 | -| App1 attempts to delete a container of ContainerType1 | Denied | App1 doesn't have the permission to delete containers of ContainerType1. | -| User A makes a delegated request to read from ContainerX on App1 | Allowed | Both UserA and App1 have permissions to read containers of ContainerType1. | -| UserA makes a delegated request to write to ContainerX on App1 | Denied | UserA's role as a reader doesn't grant them write access | diff --git a/docs/embedded/concepts/app-concepts/containertypes.md b/docs/embedded/concepts/app-concepts/containertypes.md deleted file mode 100644 index 7223d17b3..000000000 --- a/docs/embedded/concepts/app-concepts/containertypes.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: SharePoint Embedded Container Types -description: This article explains how Container Types work. -ms.date: 04/09/2024 -ms.localizationpriority: high ---- - -# SharePoint Embedded Container Types - -In SharePoint Embedded, files and documents are stored in Containers, each identified by a Container Type, which is a property stamped on every instance. A Container Type links all Containers to a specific Azure Subscription for billing. A single SharePoint Embedded Application owns each Container Type, and each SharePoint Embedded Application can own only one Container Type. It specifies the access permissions a SharePoint Embedded Application has for all Containers of that type, such as creating, reading, writing, deleting containers, and managing container permissions. - -## Two Kinds of Container Types - -There are two kinds of Container Types that a developer tenant can create: - -1. [Trial Container Types](#trial-container-types) -1. [Standard Container Types](#standard-container-types) - -## Trial Container Types - -To enable customers to explore the development of SharePoint Embedded applications and assess its features, we offer the ability to create a Trial Container Type. Each customer can have only one Trial Container Type in their tenant at a time. The tenant developing the application can utilize Trial Container Types, which aren't linked to a billing profile. In this scenario, the partner tenant remains the same as the consuming tenant. The Trial Container Type remains valid for up to 30 days but can be removed at any time within this period. There are two ways to create a Trial Container Type: - -- You can use [SharePoint Embedded Visual Studio Code Extension](../../getting-started/spembedded-for-vscode.md) to create a Trial Container Type in just a few steps. The Visual Studio Code extension also registers your Container Type and creates Containers for you. -- A Trial Container Type can be created using 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. - -```powershell -New-SPOContainerType -[–TrialContainerType] -[ -ContainerTypeName ] -[ -OwningApplicationId ] -``` - -After a Trial Container Type is created, customers can create up to five active Containers in the trial Container Type. Trial Containers are provided with 1 GB of storage space. The Trial Container Type expires after 30 days, resulting in the loss of access to all Containers created using that Container Type. Customers can create a new Trial Container Type, but doing so requires the deletion of ALL existing Trial Containers. - -> [!NOTE] -> The Trial Container Type is the only Container Type that is restricted to the Partner (creating) tenant and cannot be shared with other consuming tenants. -> -> It is not possible to convert a Trial Container Type and/or the associated Containers to a Standard Container Type. - -## Standard Container Types - -Standard Container Types are associated with a billing profile in [Azure portal](https://portal.azure.com) when they're created. The billing profile includes an Azure Subscription ID and a Region Group. There are two prerequisites to creating s Standard Container: - -- An Azure subscription and Resource Group must be present in the [Azure portal](https://portal.azure.com) -- An App registration must be created in [Microsoft Entra ID](https://entra.microsoft.com) - -## Create a Standard ContainerType - -A developer admin can create a new billable Container Type using the following PowerShell cmdlet. Tenants can create a maximum of five Container Types. Trial Container Types don't count against the maximum number of Container Types that a Partner tenant can create. - -> [!IMPORTANT] -> Assign the SharePoint Embedded Administrator role available in M365 Admin Center or Microsoft Entra to execute SharePoint Embedded Container commandlets mentioned in this article. -> -> Global Administrators can continue to execute SharePoint Embedded container cmdlets. -> -> If you are a SharePoint Administrator, grant yourself the SharePoint Embedded Admin role as well to execute these cmdlets. - -> [!NOTE] -> The user or admin who will set up billing relationship for SharePoint Embedded will need to have owner or contributor permissions on the Azure subscription. - -```powershell -New-SPOContainerType -[–ContainerTypeName ] -[-OwningApplicationId ] -[ -AzureSubscriptionId ] -[ -ResourceGroup ] -[ -Region ] -``` - -## Viewing ContainerTypes - -Developer Admin can view all the SharePoint Embedded Container Types created by them on their tenant using this PowerShell cmdlet. 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 - -In order to create and interact with Containers, you must [register](../app-concepts/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](../app-concepts/register-api-documentation.md). - -## Deleting Trial Container Types - -Developer Admins can only delete Trial Container Types and not Standard Container Types. To delete a trial Container Type, you must remove all Containers of the Trial Container Type first, including from the recycle bin. To remove Containers from the Trial Container Type, refer to [Consuming Tenant Admin](../admin-exp/cta.md#delete-containers). Once all the Containers are deleted, Developer Admins can delete the Container Types using the below PowerShell cmdlet. - -```powershell -Remove-SPOContainerType -[-ContainerTypeId ] -``` \ No newline at end of file diff --git a/docs/embedded/concepts/app-concepts/register-api-documentation.md b/docs/embedded/concepts/app-concepts/register-api-documentation.md deleted file mode 100644 index 2bf426915..000000000 --- a/docs/embedded/concepts/app-concepts/register-api-documentation.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: Register File Storage Container Type Application Permissions -description: Register the Container Type -ms.date: 03/05/2024 -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 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 will determine the settings used in the Consuming Tenant. - -> [!NOTE] -> Only the Owning Application of the Container Type can invoke the registration API in the Consuming Tenant. -> -> The registration API is **NOT** a Graph API and can only be invoked using an AppOnly and a cert-based access token. Learn more about [authentication](./auth.md). - -## 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 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 - -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/concepts/app-concepts/sharing-and-perm.md b/docs/embedded/concepts/app-concepts/sharing-and-perm.md deleted file mode 100644 index 754bcd5d2..000000000 --- a/docs/embedded/concepts/app-concepts/sharing-and-perm.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Sharing and Permissions -description: Outlines Permission Model for SharePoint Embedded -ms.date: 11/28/2023 -ms.localizationpriority: high ---- - -# Sharing and Permissions in SharePoint Embedded - -## Sharing - -The permission model used in SharePoint Embedded is different from the traditional SharePoint model and follows the OneDrive Consumer model. That is, Unlike SharePoint you can't break the permission inheritance. However, you can apply “additive permissions” to the Content (files and folders) that are in a Container. - -### Container Roles - -Every Container has four predefined roles (that can't be extended or modified) that users or Microsoft Entra security groups can be added or removed from: - -- **Owner**: Has full control over the Container -- **Manager**: And being to add, update, and delete content in the Container, they can also maintain permissions of the Container and the content in the Container -- **Writer**: Can add, update, and delete content in the Container -- **Reader**: Can only view content in the Container -If a user is a member of a role, then those permissions apply to all of the content (files and folders) that in that Container. For example, if *UserA* is made a member of the Reader role, then *UserA* is able to view and read all content (files and folders) in that Container. - -## Permissions - -### Additive Permissions - -Your app might have the scenario that you might want to grant extra permissions to a user beyond what they have on the Container. For example, if *UserA* is member of the Reader role, you might want to allow that user to be able to edit a specific document in that Container. To support this scenario, you add and delete additive permissions using the Microsoft Graph APIs: - -| Scenario | Microsoft Graph API(s) | Notes | -| :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Grant an additive permission | [POST /drives/{drive-id}/items/{item-id}/invite](/graph/api/driveitem-invite) | The sendInvitation property must always be false. You can't grant additive permissions to the root folder in a Container as this is essentially the same as adding a User to a role. You can't use AppOnly permissions. | -| Retrieve permissions | [GET /drives/{drive-id}/items/{item-id}/permissions](/graph/api/permission-get) & [GET /drives/{drive-id}/items/{item-id}/permissions/{perm-id}](/graph/api/permission-get), | | -| Delete an additive permission | [DELETE /drives/{drive-id}/items/{item-id}/permissions/{perm-id}](/graph/api/permission-delete) | You can only delete the additive permission on the drive item where it was originally added. | - -In addition, using these APIs have the following dependencies: - -- How Sharing has been configured in the Consuming Tenant -- The type of user that is invoking the API when you're using delegated authorization. - -## Sharing Configuration Settings - -Invoking the additive permission APIs and sharing content is dependent on the Sharing configuration settings in the Consuming Tenant. For example, if the Consuming Tenant has been configured to disable sharing to Guest Users, then your SharePoint Embedded application won't be able to add Guest Users to the Container roles or grant them additive permissions. - -For more information, see: - -- [Sharing & permissions in the SharePoint modern experience - SharePoint in Microsoft 365 | Microsoft Learn](/sharepoint/modern-experience-sharing-permissions#guest-sharing) -- [Manage sharing settings - SharePoint in Microsoft 365 | Microsoft Learn](/sharepoint/turn-external-sharing-on-or-off) - -### Container “Partition” - -The Sharing settings can be defined at the Tenant level and separately at the SharePoint Site and OneDrive “partitions”. For SharePoint Embedded, we have introduced a new “partition” called Containers that will apply to all SharePoint Embedded applications in the Consuming Tenant. - -This can be configured using the PowerShell cmdlet [Set-SPOTenant](/powershell/module/sharepoint-online/set-spotenant) as per this example: - -```powershell -Set-SPOTenant - -SharingCapability ExternalUserAndGuestSharing - -CoreSharingCapability ExistingExternalUserSharing - -OneDriveSharingCapability Disabled - -ContainerSharingCapability ExternalUserAndGuestSharing -``` - -![Sharing Partitions](../../images/SharingPartitions.png) - -Note the following: - -- [Microsoft.Online.SharePoint.PowerShell](/powershell/sharepoint/sharepoint-online/connect-sharepoint-online) version 16.0.23701.0 or later is required to configure the Container “partition” -- Sharing settings for a “partition” can never be more permissive than the Tenant level setting. - -## Guest User Dependencies - -In addition to the Sharing configuration settings, there are a couple of scenarios relating to Guest Users and sharing to be aware of: - -- Guest Users can get unexpected results when granting additive permissions -- Guest Users might not be able to be added via the SharePoint Embedded App - -## Guest User granting Additive Permissions - -When granting additive permissions and the user invoking the API is a Guest User, then you might get unexpected results. - -| Admin User | User being granted additive permissions | Outcome | -| :-------------------- | :-------------------------------------: | :-------- | -| Consuming Tenant user | New | Success | -| Consuming Tenant user | Existing | Success | -| Guest user | New | **Fails** | -| Guest user | Existing | Success | - -The user being granted additive permissions indicate whether that user has previously been granted additive permissions for any content in that specific Container. - -The failure scenario is expected behavior depending on the Consuming Tenant configuration settings. - -If this scenario is required to also succeed for Guest Users, then the following settings need to be set to `True` using the [Set-SPOTenant](/powershell/module/sharepoint-online/set-spotenant) PowerShell cmdlet in the Consuming Tenant: - -- `-AllowGuestUserShareToUsersNotInSiteCollection` - - Setting this to `True` also requires [SharePoint and OneDrive integration with Microsoft Entra B2B](/sharepoint/sharepoint-azureb2b-integration) to be enabled. -- `-ShowPeoplePickerSuggestionsForGuestUsers` - -## Adding Guest Users - -If your SharePoint Embedded application requires the ability to add Guest Users then Sharing must be enabled on the SharePoint content root in the Consuming Tenant (`https://contoso.sharepoint.com`). - -By default, sharing is enabled on the SharePoint content root. However, some Consuming Tenants might have this disabled. - -If this scenario is required, then the SharePoint content root SharingCapability setting needs to be set to any value except disabled using the [Set-SPOSite](/powershell/module/sharepoint-online/set-sposite) PowerShell cmdlet in the Consuming Tenant: - -```powershell -Set-SPOSite -Identity https://contoso.sharepoint.com ` - -SharingCapability ExistingExternalUserSharingOnly -``` diff --git a/docs/embedded/concepts/app-concepts/terms-and-def.md b/docs/embedded/concepts/app-concepts/terms-and-def.md deleted file mode 100644 index a038178e0..000000000 --- a/docs/embedded/concepts/app-concepts/terms-and-def.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Terms and Definitions -description: Important Concepts in SharePoint Embedded -ms.date: 11/28/2023 -ms.localizationpriority: high ---- - -# Terms and Definitions - -Short definitions to key concepts in SharePoint Embedded Application Architecture. - -> All terms are explained in the [Concepts](../app-concepts/app-architecture.md) section. - -**Application Workload**: The collection of applications that have access to a Container type - -**Consuming Tenant**: The tenant in which the SharePoint Embedded Application has been registered and will execute in. - -**Container Type**: A property of Containers that uniquely identifies the SharePoint Embedded Application workload the Container is associated with. - -**Container Type Permissions**: Container Type level configuration describing permissions that SharePoint Embedded Applications have to Container instances of a Container Type. The Owning SharePoint Embedded Application manages the Container Type Permissions. - -**ContainerTypeId**: A GUID specifying which workload owns the Container. For example, the Owning Tenant would generate a ContainerTypeID that is stamped on each of their Containers. - -**Drive**: SharePoint Embedded Containers are considered Drives in Graph. Container IDs and Drive IDs are synonymous. - -**Drive Item**: Any file or folder stored in Drives or Containers are called DriveItems. Containers hold DriveItems. - -**Owning SharePoint Embedded Application**: The SharePoint Embedded Application that was used to originally register the Container Type. - -**Partner Tenant**: Also known as the "Owning Tenant" or "Partner Tenant." The tenant that developed the SharePoint Embedded Application. This is also the tenant that will be invoiced for any instances and usage of Storage Containers of the Container Type that they own. For example, a company Contoso develops a SharePoint Embedded Application that Fabrikam has registered to run. In this case, Contoso is the owning tenant and Fabrikam is the consuming tenant. - -**SharePoint Embedded Application**: An application that uses Storage Containers for storing content. - -**SharePoint Embedded Developer**: The application developer who built the SharePoint Embedded Application. - -**SharePoint Embedded Storage Container (“Container”)**: A storage Container is the top-level Container in SharePoint Embedded. A StorageContainer holds content in the form of Drive and DriveItems. diff --git a/docs/embedded/concepts/content-experiences/search-content.md b/docs/embedded/concepts/content-experiences/search-content.md deleted file mode 100644 index 5caf41535..000000000 --- a/docs/embedded/concepts/content-experiences/search-content.md +++ /dev/null @@ -1,421 +0,0 @@ ---- -title: Search SharePoint Embedded containers and content -description: Overview on how to search SharePoint Embedded containers and content -ms.date: 1/14/2024 -ms.localizationpriority: high ---- - -# Search SharePoint Embedded content - -Use the Microsoft Search API in Microsoft Graph to search SharePoint Embedded containers and content. The Search API lets you scope the container type and file type for your queries by specifying the corresponding parameter in the request body. This article describes some examples. - -> [!NOTE] -> Search API only supports Delegated permissions. - -## Example 1: Search containers by container type - -This example queries all containers by the specified container type. The response includes all container instances of the specified container type in the tenant. - -### Request - -```HTTP -POST /search/query -Content-Type: application/json - -{ - "requests": [ - { - "entityTypes": [ - "drive" - ], - "query": { - "queryString": "ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" - } - } - ] -} -``` - -### Response - -```HTTP -HTTP/1.1 200 OK -Content-type: application/json - -{ - "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", - "value": [ - { - "searchTerms": [], - "hitsContainers": [ - { - "hits": [ - { - "hitId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "rank": 1, - "summary": "Everything about Contoso", - "resource": { - "@odata.type": "#microsoft.graph.drive", - "id": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "createdBy": { - "user": { - "displayName": "Dylan Williams" - } - }, - "lastModifiedDateTime": "2024-01-18T19:45:25Z", - "name": "AllItems.aspx", - "parentReference": { - "sharepointIds": { - "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4" - }, - "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" - }, - "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/Forms/AllItems.aspx" - } - } - ], - "total": 1, - "moreResultsAvailable": false - } - ] - } - ] -} -``` - -## Example 2: Search containers by title -This example queries all containers by a specified container display name. The response includes all container instances in the tenant that match the criteria. - -### Request - -```HTTP -POST /search/query -Content-Type: application/json - -{ - "requests": [ - { - "entityTypes": [ - "drive" - ], - "query": { - "queryString": "Title:'contoso' AND ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" - } - } - ] -} -``` - -### Response - -```HTTP -HTTP/1.1 200 OK -Content-type: application/json - -{ - "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", - "value": [ - { - "searchTerms": [ - "contoso" - ], - "hitsContainers": [ - { - "hits": [ - { - "hitId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "rank": 1, - "summary": "Everything about Contoso", - "resource": { - "@odata.type": "#microsoft.graph.drive", - "id": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "createdBy": { - "user": { - "displayName": "Dylan Williams" - } - }, - "lastModifiedDateTime": "2024-01-18T19:45:25Z", - "name": "AllItems.aspx", - "parentReference": { - "sharepointIds": { - "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4" - }, - "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" - }, - "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/Forms/AllItems.aspx" - } - } - ], - "total": 1, - "moreResultsAvailable": false - } - ] - } - ] -} -``` - -## Example 3: Search containers by container description -This example queries all containers by the specified container type and container description. The response includes all container instances in the tenant that match the criteria. - -### Request - -```HTTP -POST /search/query -Content-Type: application/json - -{ - "requests": [ - { - "entityTypes": [ - "drive" - ], - "query": { - "queryString": "Description:'Everything' AND ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" - } - } - ] -} -``` - -### Response - -```HTTP -HTTP/1.1 200 OK -Content-type: application/json - -{ - "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", - "value": [ - { - "searchTerms": [], - "hitsContainers": [ - { - "hits": [ - { - "hitId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "rank": 1, - "summary": "Everything about Contoso", - "resource": { - "@odata.type": "#microsoft.graph.drive", - "id": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "createdBy": { - "user": { - "displayName": "Dylan Williams" - } - }, - "lastModifiedDateTime": "2024-01-18T19:45:25Z", - "name": "AllItems.aspx", - "parentReference": { - "sharepointIds": { - "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4" - }, - "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" - }, - "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/Forms/AllItems.aspx" - } - } - ], - "total": 1, - "moreResultsAvailable": false - } - ] - } - ] -} -``` - -## Example 4: Search for content by title in a specific container - -This example queries all the content by a specific title in a specific container instance. The response includes all driveItems in the specific container instance that match the criteria. - -### Request - -```HTTP -POST /search/query -Content-Type: application/json - -{ - "requests": [ - { - "entityTypes": [ - "driveItem" - ], - "query": { - "queryString": "Title:'contoso' AND ContainerId:b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0" - } - } - ] -} -``` - -### Response - -```HTTP -HTTP/1.1 200 OK -Content-type: application/json - -{ - "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", - "value": [ - { - "searchTerms": [ - "contoso", - "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0" - ], - "hitsContainers": [ - { - "hits": [ - { - "hitId": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", - "rank": 1, - "summary": "Contoso Detailed Design Contoso Product Specification", - "resource": { - "@odata.type": "#microsoft.graph.driveItem", - "size": 56, - "fileSystemInfo": { - "createdDateTime": "2024-01-18T19:46:48Z", - "lastModifiedDateTime": "2024-01-18T19:46:48Z" - }, - "listItem": { - "@odata.type": "#microsoft.graph.listItem", - "fields": {}, - "id": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" - }, - "id": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", - "createdBy": { - "user": { - "displayName": "Dylan Williams", - "email": "dywilliams@contoso.onmicrosoft.com" - } - }, - "createdDateTime": "2024-01-18T19:46:48Z", - "lastModifiedBy": { - "user": { - "displayName": "Dylan Williams", - "email": "dywilliams@contoso.onmicrosoft.com" - } - }, - "lastModifiedDateTime": "2024-01-18T19:46:48Z", - "name": "contoso.txt", - "parentReference": { - "driveId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "id": "01SHAK4OVPJ5Q5P6YD6VCZHPV7PKILUJ65", - "sharepointIds": { - "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4", - "listItemId": "1", - "listItemUniqueId": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" - }, - "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" - }, - "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/contoso.txt" - } - } - ], - "total": 1, - "moreResultsAvailable": false - } - ] - } - ] -} -``` - -## Example 5: Search by content -This example queries all the content by the specified words across all containers of a specific container type. The response includes all driveItems that match the criteria. - -### Request - -```HTTP -POST /search/query -Content-Type: application/json - -{ - "requests": [ - { - "entityTypes": [ - "driveItem" - ], - "query": { - "queryString": "'contoso' AND ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" - } - } - ] -} -``` - -### Response - -```HTTP -HTTP/1.1 200 OK -Content-type: application/json - -{ - "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)" - "value": [ - { - "searchTerms": [ - "contoso" - ], - "hitsContainers": [ - { - "hits": [ - { - "hitId": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", - "rank": 1, - "summary": "Contoso Detailed Design Contoso Product Specification", - "resource": { - "@odata.type": "#microsoft.graph.driveItem", - "size": 56, - "fileSystemInfo": { - "createdDateTime": "2024-01-18T19:46:48Z", - "lastModifiedDateTime": "2024-01-18T19:46:48Z" - }, - "listItem": { - "@odata.type": "#microsoft.graph.listItem", - "fields": {}, - "id": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" - }, - "id": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", - "createdBy": { - "user": { - "displayName": "Dylan Williams", - "email": "dywilliams@contoso.onmicrosoft.com" - } - }, - "createdDateTime": "2024-01-18T19:46:48Z", - "lastModifiedBy": { - "user": { - "displayName": "Dylan Williams", - "email": "dywilliams@contoso.onmicrosoft.com" - } - }, - "lastModifiedDateTime": "2024-01-18T19:46:48Z", - "name": "contoso.txt", - "parentReference": { - "driveId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", - "id": "01SHAK4OVPJ5Q5P6YD6VCZHPV7PKILUJ65", - "sharepointIds": { - "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4", - "listItemId": "1", - "listItemUniqueId": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" - }, - "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" - }, - "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/contoso.txt" - } - } - ], - "total": 1, - "moreResultsAvailable": false - } - ] - } - ] -} -``` - -## Known Limitation - -- Search requests run in the context of the signed-in user. Search results are only scoped to enforce any access control applied to the items by the user. For example, search results will include all container or container content matching the search criteria and accessible by the user regardless of whether the SharePoint Embedded application is authorized to access. You should specify the desired container type by including the ContainerTypeId as part of your **queryString** when searching for containers or container content to ensure search results are properly scoped. -- For your application to access the containers or container content in search results, it must have access permissions to the corresponding container types. diff --git a/docs/embedded/concepts/content-experiences/user-experiences-overview.md b/docs/embedded/concepts/content-experiences/user-experiences-overview.md deleted file mode 100644 index 6ffe6b5cd..000000000 --- a/docs/embedded/concepts/content-experiences/user-experiences-overview.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Content Experiences Overview -description: Experiences with SharePoint Embedded content -ms.date: 11/14/2023 -ms.localizationpriority: high ---- - -# Content Experiences Overview - -Microsoft's SharePoint Embedded provides a comprehensive set of Content Experience features like Open & Edit of Office Files, File Preview or In-App Search that you can use to build the right user experiences for your applications. - - - -## Open & Edit using Office - -Office documents from SharePoint Embedded Apps can be opened for Viewing, Editing and Collaborating using either Office Online, where your users can work with documents directly on the website, or Desktop apps for a richer viewing and editing experience. Learn more about [Office experiences available on SharePoint Embedded](./office-experience.md). - -You can configure your applications to launch Office clients just the right way when a user selects on an Office document from your application including directly launching Desktop Clients or launching Office clients in a specific mode like View (for read-only content) or in Edit for editor mode. Learn how to [configure the right Office Experience for your Office Documents](../../tutorials/launch-experience.md) - -## Preview Content - -Integrate your app with SharePoint Embedded player plugin to offer File Preview experiences on a wide range of supported file types. You can embed the File Preview experiences either in an iFrame or open a new page. Learn how to [offer File Preview experiences for content on your applications](../../tutorials/using-file-preview.md) - -## Download - -You can use [Microsoft Graph's Download DriveItem API](/graph/api/driveitem-get-content) to offer download file user experiences for your applications. This will generate a short lived, preauthenticated Url allows users to download files from your applications. - -> [!NOTE] -> A direct link to the file lacks the appropriate authorization from your app. If used directly in a browser, this would yield an access denied. - -## In-Application Search - -You can use the Microsoft Search API to query SharePoint Embedded services container content in your application. Search requests run in the context of the signed-in user. Search results are only scoped to enforce any access control applied to the items by the user. For example, search results will include all content matching the search criteria and accessible by the user regardless of whether the SharePoint Embedded application is authorized to access the content. It's recommended to specify the container type accessible by the application in the search request body to ensure search results are properly scoped. - -## Content Discovery in Microsoft 365 - -Your users will be able to discover and share content from your SharePoint Embedded applications in their Recommended, Quick Access or Shared With Me feeds on Microsoft 365 surfaces like Office.com, SharePoint Search results or OneDrive user accounts. This allows your users to use familiar Microsoft 365 experiences to discover content from your applications. In future releases, Microsoft 365 Content Discovery can be configured to be disabled across all Microsoft 365 surfaces. - -### Enable Sharing dialog in Office.com - -> [!NOTE] -> To enable the sharing user experience for your content in Office.com additional application permissions **must** be added at the time of the container type registration process. - -To add more permission to enable sharing dialog, refer to the following code: - -```http -PUT /storageContainerTypes/{containerTypeId}/applicationPermissions -Content-Type: application/json - -{ - "appId": "4765445b-32c6-49b0-83e6-1d93765276ca", - "delegated": ["readContent","writeContent"], - "appOnly": ["none"] -} -``` - -## Recycle Bin - -You can use the Microsoft Graph APIs to either soft-delete or permanent-delete items in containers. Soft-deleted items are moved to the container’s recycle bin and retained for 93 days. During this period, the items can be restored or permanently deleted using the Microsoft Graph APIs. An item in recycle bin is permanently deleted when it exceeds the 93-day retention period. Permanently deleted items can't be restored. - -## Deleted Container Collection - -You can use the SharePoint Embedded services container Graph API to delete containers and move them into the deleted container collection. A deleted container can be restored from the collection within 93 days. If a container is deleted from the collection, or it exceeds the 93-day retention period, it's permanently deleted. diff --git a/docs/embedded/development/app-architecture.md b/docs/embedded/development/app-architecture.md new file mode 100644 index 000000000..d3eb1d73c --- /dev/null +++ b/docs/embedded/development/app-architecture.md @@ -0,0 +1,50 @@ +--- +title: App Architecture +description: Anatomy of a SharePoint Embedded application +ms.date: 05/21/2024 +ms.localizationpriority: high +--- + +# SharePoint Embedded app architecture + +All files and documents in SharePoint Embedded are stored in containers, with all containers and container content created and stored within a Microsoft 365 Tenant. All containers and container content are created, managed, and interacted via the SharePoint Embedded application using Microsoft Graph. + +![SharePoint Embedded Architecture](../images/SPEArch.png) + +## SharePoint Embedded application + +A Microsoft Entra ID application registration. As an owning or guest application to a container type, it has access to containers of that container type. + +## Owning tenant and consuming tenant + +SharePoint Embedded introduces the concepts of owning tenant and consuming tenant. Owning tenant is a Microsoft Entra ID tenant where a container type is created. This is often also the tenant where your SharePoint Embedded application is registered. Consuming tenant is a Microsoft Entra ID tenant where a container type is used. Only a consuming tenant may have containers of such container type. All container and content created via the application is stored within the consuming tenant's Microsoft 365 tenant boundary. + +The same Microsoft Entra ID tenant can be both owning and consuming tenant of a given container type in the SharePoint Embedded ecosystem. + +## Container, container type, and owning application + +A container is the basic storage unit in SharePoint Embedded. Also, a container defines a security and compliance boundary. + +A container type is a SharePoint Embedded resource that defines the relationship, access privileges, and billing accountability between an application and a set of containers. Also, the container type defines behaviors on the set of containers. Learn more about [container types](../getting-started/containertypes.md). + +The container type is represented on each container as an immutable property and is used across the entire SharePoint Embedded ecosystem. Each container type is strongly coupled with one SharePoint Embedded application, which is referred to as the owning application. The owning application developer (the owning tenant) is responsible for creating and managing their container types. SharePoint Embedded mandates a 1:1 relationship between owning application and container type. + +## Access Model + +An application's access to containers and container content is determined by a set of permissions configured between the application and the container type it attempts to access. This set of permission is determined at container Type creation time for owning application. The SharePoint Embedded ecosystem allows applications to access containers of container types it doesn't own. + +In this illustration, multiple applications are deployed in the tenancy, including two apps developed by ISVs (App 1 and 2) and a LOB app (App 3). Each application can access only to the stack of containers of the container type they own. + +![SPE multi app architecture](../images/SPECTDedicated.png) + +In this illustration, both App 1 and App 2 in the tenancy have access to the same container type. Both apps can access the stack of the containers of that type. + +![SPE multi app architecture sharing Container Types](../images/SPECTShared.png) + +#### Example + +Contoso is an ISV and built a human resource management application on SharePoint Embedded. The application is registered and deployed in Fabrikam, an auditing firm. Fabrikam also developed an LOB auditing application on SharePoint Embedded that is used internally. + +In this scenario, both the human resource management application developed by Contoso and the auditing application developed by Fabrikam have their own container type. Contoso is the owning tenant of the human resource management application; and the application is the owning app for its container Type. Likewise, Fabrikam is the owning tenant the auditing application; and the application is the owning app for its container type. In addition, Fabrikam is the consuming tenant for both applications. + +![Example](../images/apparchexample.png) diff --git a/docs/embedded/development/auth.md b/docs/embedded/development/auth.md new file mode 100644 index 000000000..6e20ceb95 --- /dev/null +++ b/docs/embedded/development/auth.md @@ -0,0 +1,164 @@ +--- +title: SharePoint Embedded Authentication and Authorization +description: This article describes the authentication and authorization model for SharePoint Embedded applications. +ms.date: 06/24/2025 +ms.localizationpriority: high +--- + +# SharePoint Embedded authentication and authorization + +To use SharePoint Embedded, your application needs to use Microsoft Graph. Learn more about [Microsoft Graph authentication and authorization](/graph/auth/auth-concepts). Learn more about the [SharePoint Embedded architecture](./app-architecture.md). + +## Overview + +Here are some key principles of SharePoint Embedded authentication and authorization: + +- Applications interact with SharePoint Embedded via Microsoft Graph. +- Applications need container type application permissions to access containers of that container type. +- Applications can only access containers that the user is a member of when using access on behalf of a user. +- Applications can access all containers enabled by their container type application permissions when using access without a user. +- Applications use access on behalf of users whenever possible to enhance security and accountability + +## Pre-Requisites + +- A Microsoft Entra ID application registration. See [register an application](/graph/auth-register-app-v2). +- Your Microsoft Entra ID tenant has a Microsoft 365 subscription + +## Authorization + +SharePoint Embedded operations are exposed via Microsoft Graph. SharePoint Embedded supports [access on behalf of a user](/graph/auth-v2-user) and also [access without a user](/graph/auth-v2-service). + +> [!IMPORTANT] +> Microsoft Graph permissions granted to your application allow it to call SharePoint Embedded endpoints. However, your application must be granted [permission to a container type](#container-type-application-permissions) before it gets access to containers of that type. + +### Access on behalf of a user + +SharePoint Embedded operations [on behalf of a user](/graph/auth-v2-user) require applications to receive consent for Microsoft Graph [`FileStorageContainer.Selected`](/graph/permissions-reference#filestoragecontainerselected) delegated permission. This permission requires admin consent on the consuming tenant before any user from the tenant can consent to it. + +In addition to your application receiving consent for `FileStorageContainer.Selected` on a consuming tenant, the user that it's acting on behalf of is required to have [container permissions](#container-permissions). The effective permissions that the application has are the intersection of the application permissions and the user permissions when acting on behalf of a user. + +> [!IMPORTANT] +> Using SharePoint Embedded on behalf of a user is the recommended approach. This type of access enhances the security of your application. It also improves the auditability of actions performed by your application. + +### Access without a user + +SharePoint Embedded operations [without a user](/graph/auth-v2-service) require applications to receive consent for Microsoft Graph [`FileStorageContainer.Selected`](/graph/permissions-reference#filestoragecontainerselected) application permission. This permission requires admin consent on the consuming tenant. + +> [!NOTE] +> An administrator on the consuming tenant must consent to your application's request for permissions. Learn more [here](/entra/identity/enterprise-apps/grant-admin-consent?pivots=portal). + +### Exceptional access patterns + +Currently, there are two types of operations with exceptional access patterns: + +- [Operations not exposed via Microsoft Graph](#operations-not-exposed-via-microsoft-graph) +- [Operations involving searching SharePoint Embedded content](#operations-involving-searching-sharepoint-embedded-content) +- [Operations that require a user license](#operations-that-require-a-user-license) + +> [!IMPORTANT] +> Consider the repercussions of these exceptional access patterns on how your application and other applications can access SharePoint Embedded content in your container type. + +#### Operations not exposed via Microsoft Graph + +There are two types of operations that aren't accessible via Microsoft Graph today: + +- [Container type management](../getting-started/containertypes.md) on owning tenants, which are performed via PowerShell cmdlets. +- [Container type registration](../getting-started/register-api-documentation.md) on consuming tenants, exposed via SharePoint REST API v2. +- [SharePoint Embedded agent](./declarative-agent/spe-da.md) exposed via SharePoint REST API v2 permissions. + +To perform [container type management](../getting-started/containertypes.md) operations, you must be a [SharePoint Embedded Administrator](/entra/identity/role-based-access-control/permissions-reference#sharepoint-embedded-administrator) or [Global Administrator](/entra/identity/role-based-access-control/permissions-reference#global-administrator). + +To [register a container type](../getting-started/register-api-documentation.md), you must request the `Container.Selected` permission on the `Office 365 SharePoint Online` resource. + +| Scope name | Scope ID | Type | Operation | +| :-------------------: | :----------------------------------: | :---------: | :-----------------------------------------------------------------------------------------------: | +| Container.Selected | 19766c1b-905b-43af-8756-06526ab42875 | Application | In the context of SharePoint Embedded, enables container type registration on a consuming tenant. | + +> [!NOTE] +> Container type management on owning tenants and registration on consuming tenants will become Microsoft Graph operations soon, and this permission will no longer be needed. Stay tuned. + +To use the [SharePoint Embedded agent](./declarative-agent/spe-da.md) experience (in the Preview stage) in your application, you also need the `Container.Selected` permission on the `Office 365 SharePoint Online` resource. + +#### Operations involving searching SharePoint Embedded content + +This section refers only to the search scenarios in [Search Content](./content-experiences/search-content.md), and not the enumeration scenarios. + +To use [Microsoft Search](/microsoftsearch/overview-microsoft-search) on SharePoint Embedded content, you must request the Delegated [`Files.Read.All`](/graph/permissions-reference#filesreadall) Microsoft Graph permission on top of `FileStorageContainer.Selected`, normally used for SharePoint Embedded access. During the Preview stage of this feature, the `Files.Read.All` application permission grants applications access to search capabilities on all SharePoint Embedded content. + +> [!NOTE] +> Microsoft Search support for SharePoint Embedded content is in Preview and is subject to change. The access requirements for Microsoft Search on SharePoint Embedded content will align with the SharePoint Embedded authorization model in the future. Stay tuned. + +#### Operations that require a user license + +SharePoint Embedded is designed to work without the need for end users to have any kind of Microsoft 365 product licenses assigned to them. However, there are certain operations that don't abide by this principle yet. + +##### List containers + +The [List containers](/graph/api/filestorage-list-containers?tabs=http) operation returns a `403 Forbidden` response code if called on behalf of a user that doesn't have a OneDrive. There are plans to remove this dependency soon. This dependency doesn't apply to the List containers operation when called without a user context (app-only mode). + +##### Mention users in Office documents + +The common [Office experience](./content-experiences/office-experience.md) includes reviewing documents and adding comments to those documents. For users to show up in the @mentions people picker, they need to have a Microsoft 365 license assigned to them. + +### Container type application permissions + +SharePoint Embedded applications need to be granted container type application permissions by the owner application before they can access containers of the given container type. Container type application permissions are granted to applications via [container type registration](../getting-started/register-api-documentation.md). + +| Permission | Description | +| -------------------- | ------------------------------------------------------------------------------------------------------------------ | +| None | Has no permissions to any containers or content of this container type. | +| ReadContent | Can read the content of containers of this container type. | +| WriteContent | Can write content to containers for this container type. This 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. | +| ManageContent | Can manage the content of the container | +| Full | Has all permissions for containers of this container type. | + +> [!NOTE] +> The combination of Microsoft Graph permissions and container type application permissions encompasses the client authorization for applications. + +### Container permissions + +Any user accessing a container must be a member of the container. Membership to a container [grants users container permissions](/graph/api/filestoragecontainer-post-permissions). These permissions define the access level that users have on a given container. Container permissions only apply to access on behalf of a user and not to access without a user. A SharePoint Embedded application accessing containers without a user gets the full access defined in its [container type application permissions](#container-type-application-permissions) instead. + +> [!IMPORTANT] +> The calling user creating a new container via delegated calls is automatically assigned the Owner role. + +| Permission | Description | +| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Reader | This role allows the user to read the properties and the contents of the container. | +| Writer | This role has all the permissions a Reader has, plus the permission to create, update, and delete content inside the container, and to update applicable container properties. | +| Manager | This role has all the permissions a Writer has, plus the permission to manage membership of the container. | +| Owner | This role has all the permissions a Manager has, plus the permission to delete containers. | + +## What's next + +Here are some actions you can take next: + +1. Configure your SharePoint Embedded [application manifest](/entra/identity-platform/reference-app-manifest#requiredresourceaccess-attribute) (you can use [Microsoft Entra PowerShell](/powershell/entra-powershell/manage-apps#assign-permissions-to-an-app) or the [Azure CLI](/cli/azure/ad/app/permission#az-ad-app-permission-add)) to request the required permissions: + + - Microsoft Graph (resourceAppId: `00000003-0000-0000-c000-000000000000`) + - `FileStorageContainer.Selected` (type: `Scope`, ID: `085ca537-6565-41c2-aca7-db852babc212`) to access containers on consuming tenants + - Office 365 SharePoint Online (resourceAppId: `00000003-0000-0ff1-ce00-000000000000`) + - `Container.Selected` (type: `Role`, ID: `19766c1b-905b-43af-8756-06526ab42875`) to register a container on consuming tenants + +1. [Grant admin consent](/entra/identity-platform/v2-admin-consent) to your application on both owning and consuming tenants (which can be the same tenant). + + > [!NOTE] + > The `Container.Selected` application permission is hidden, which can cause issues with granting admin consent using the Enterprise apps pane in the Azure portal. Instead, [construct the admin consent URL](/entra/identity-platform/v2-admin-consent#request-the-permissions-from-a-directory-admin) and provide it to your Microsoft Entra directory administrator. For example: + > + > `https://login.microsoftonline.com/{tenant}/v2.0/adminconsent?client_id={client_id}` + > + > Make sure the Microsoft Entra directory administrator [confirms a successful response](/entra/identity-platform/v2-admin-consent#successful-response). + +1. [Create a new container type](../getting-started/containertypes.md) on the owning tenant. +1. [Register a container type](../getting-started/register-api-documentation.md) on the consuming tenant. +1. [Create a container](/graph/api/filestoragecontainer-post) diff --git a/docs/embedded/concepts/content-experiences/office-experience.md b/docs/embedded/development/content-experiences/office-experience.md similarity index 67% rename from docs/embedded/concepts/content-experiences/office-experience.md rename to docs/embedded/development/content-experiences/office-experience.md index cfc255c57..4add48ca4 100644 --- a/docs/embedded/concepts/content-experiences/office-experience.md +++ b/docs/embedded/development/content-experiences/office-experience.md @@ -1,40 +1,36 @@ --- title: Office Experiences description: Overview of Office experiences with SharePoint Embedded content -ms.date: 11/28/2023 +ms.date: 06/18/2025 ms.localizationpriority: high --- -# Office File Experiences for SharePoint Embedded Apps +# Office file experiences for SharePoint Embedded -Office File Experiences for SharePoint Embedded platform will work in a similar manner to Microsoft 365 (Microsoft 365) platform. +Office file experiences for SharePoint Embedded platform will work in a similar manner to Microsoft 365 platform. - +Office documents from SharePoint Embedded apps can be opened for viewing and editing in Office web or in the Office application for a richer viewing and editing experience. AutoSave feature saves your files automatically as your user's work and is enabled for each Word, Excel, and PowerPoint file stored in your SharePoint Embedded Application Apps. -## Opening Office Documents from SharePoint Embedded Apps +## View or restore a previous version of an Office document from SharePoint Embedded -Office documents from SharePoint Embedded Apps can be opened for Viewing and Editing in Office Online, where your users can work with documents directly on the website, or in Desktop apps for a richer viewing and editing experience. AutoSave feature saves your files automatically as your user's work and is enabled for each Word, Excel and PowerPoint file stored in your SharePoint Embedded Application Apps. +Versioning is automatically enabled on each Word, Excel, and PowerPoint file stored in your SharePoint Embedded Apps, that helps your users to see what changes have been made in a file, compare different versions, or restore the version you want. This is incredibly important to your users if a mistake was made, a previous version is preferred, or in multi-user coauthoring scenarios when your users are collaborating with others and someone makes changes your users didn't want in a file. -## View or Restore a Previous Version of Office Document from SharePoint Embedded Apps +## Collaborating on Office documents from SharePoint Embedded -Versioning is automatically enabled on each Word, Excel and PowerPoint file stored in your SharePoint Embedded Application Apps that helps your users see what changes have been made in a file, compare different versions, or restore the version you want. This is incredibly important to your users if a mistake was made, a previous version is preferred or in multi-user coauthoring scenarios when your users are collaborating with others and someone makes changes your users didn't want in a file. +It's simple for your users to collaborate on your SharePoint Embedded Application's Office documents – they can **Share documents** with specific peers or with people outside your organization by Creating a shareable link to use wherever needed, Send an email invitation or @mention in comments to tag someone for feedback and, **Collaborate in real time** by co-authoring in Office with SharePoint Embedded Applications. -## Collaborating on Office Documents from SharePoint Embedded Apps - -It's simple for your users to collaborate on your SharePoint Embedded Application's Office documents – they can **Share documents** with specific peers or with people outside your organization by Creating a shareable link to use wherever needed, Send an Email Invitation or @mention in comments to tag someone for feedback and, **Collaborate in real time** by co-authoring in Office with SharePoint Embedded Applications. +> [!NOTE] +> Mentions require target users to [have an Microsoft 365 license assigned to them](../auth.md#mention-users-in-office-documents). +> +> Mentions are restricted to people inside the consuming tenant's organization. Mentions exclude guests and users from other tenants in a multitenant setting. ### Share your documents -#### Send an Email Invite +#### Send an email invite -Share your SharePoint Embedded documents by Sending an email invitation to specific people: +Share your SharePoint Embedded documents by sending an email invitation to specific people: - Select Share, start typing the email addresses or contact names of people you want to share with. When you begin to enter info in the box, you can also choose a contact from the list that appears. - Include a message if you want and hit Send. @@ -43,7 +39,7 @@ Share your SharePoint Embedded documents by Sending an email invitation to speci Creating a shareable link makes it simple to share your SharePoint Embedded document in an email, document, or IM. -- Select Share, Copy Link and Paste the link wherever you want +- Select Share, Copy Link, and Paste the link wherever you want - Change any permissions of the link if needed #### Co-Author @@ -54,25 +50,25 @@ If you want others to edit with you, you can easily share files and collaborate - A presence indicator shows where someone is making changes. See any changes right as they're being made. - See changes made by others and see what's happened while you were away. -### Levels of sharing access +#### Levels of sharing access There are different options for sharing SharePoint Embedded Application Office Documents from: | If you want to … | Sharing Setting to Set | | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Allow Anyone who receives the link access to SharePoint Embedded Application File | **Anyone**  gives access to anyone who receives this link, whether they receive it directly from you or forwarded from someone else. This might include people outside of your organization. | +| Allow Anyone who receives the link access to SharePoint Embedded Application File | **Anyone**  gives access to anyone who receives this link, whether they receive it directly from you or are forwarded from someone else. This might include people outside of your organization. | | Allow anyone in your organization to access to your SharePoint Embedded Application File | **People in \** gives anyone in your organization who has the link access to the file, whether they receive it directly from you or forwarded from someone else. | | Secure your SharePoint Embedded Application docs only to specific people. | When you need to prevent recipients from forwarding a shared link, use the **Specific People**  permission. **Specific people**  gives access only to the people you specify, although other people might already have access. If people forward the sharing invitation, only people who already have access to the item will be able to use the link. | | Reshare the link with specific people | **People with existing access**  can be used by people who already have access to the document or folder. It doesn't change the permissions on the item. Use this if you just want to send a link to somebody who already has access. | -## Breadcrumb properties on Office Documents from SharePoint Embedded Application Apps +## Breadcrumb properties on Office documents from SharePoint Embedded Breadcrumb properties are used by Office clients to display breadcrumb-style elements within Office client UI that aid your users in associating Office files with your Application. > [!NOTE] -> We recommend specifying 'Current Channel' to take advantage of Breadcrumb patterns and future enhancements to Office Apps. Learn more about [specifying update channels for Office Apps](/deployoffice/updates/overview-update-channels) +> We recommend specifying 'Current Channel' to take advantage of Breadcrumb patterns and future enhancements to Office Apps. Learn more about [specifying update channels for Office Apps](/deployoffice/updates/overview-update-channels). -Breadcrumb patterns for SharePoint Embedded Application Apps are constructed from Container properties configured for your Apps. The following diagram maps the container properties to breadcrumb presentation in Office clients: +Breadcrumb patterns for SharePoint Embedded Application Apps are constructed from container properties configured for your Apps. The following diagram maps the container properties to breadcrumb presentation in Office clients: ![Screenshot of breadcrumb pattern in SharePoint Embedded Applications](../../images/office2.png) diff --git a/docs/embedded/development/content-experiences/search-content.md b/docs/embedded/development/content-experiences/search-content.md new file mode 100644 index 000000000..98afb1bd1 --- /dev/null +++ b/docs/embedded/development/content-experiences/search-content.md @@ -0,0 +1,832 @@ +--- +title: Search SharePoint Embedded containers and content +description: Overview on how to search SharePoint Embedded containers and content +ms.date: 03/28/2025 +ms.localizationpriority: high +--- + +# Search SharePoint Embedded content + +Use the [Microsoft Search](/microsoftsearch/overview-microsoft-search) API in Microsoft Graph to search SharePoint Embedded containers and content. The Search API lets you scope the container type and file type for your queries by specifying the corresponding parameter in the request body. This article describes some examples. + +> [!NOTE] +> +> 1. Searching SharePoint Embedded content is in Preview stage and is subject to change. Please refer to the [exceptional access pattern](../auth.md#operations-involving-searching-sharepoint-embedded-content) that describes its current permission requirements. +> 1. Search API only supports Delegated permissions. +> 1. Your search requests must specify and set the `includeHiddenContent` parameter if your application has opted out of content discoverability in Microsoft 365. Learn more about [SharePoint Embedded content discoverability](./user-experiences-overview.md). + +## Example 1: Search containers by container type + +This example queries all containers by the specified container type with the SharePoint Embedded application opted out from content discoverability on Microsoft 365. The response includes all container instances (`drive`) of the specified container type in the tenant: + +### Request + +```HTTP +POST /search/query +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": [ + "drive" + ], + "query": { + "queryString": "ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json + +{ + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", + "value": [ + { + "searchTerms": [], + "hitsContainers": [ + { + "hits": [ + { + "hitId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "rank": 1, + "summary": "Everything about Contoso", + "resource": { + "@odata.type": "#microsoft.graph.drive", + "id": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "createdBy": { + "user": { + "displayName": "Dylan Williams" + } + }, + "lastModifiedDateTime": "2024-01-18T19:45:25Z", + "name": "AllItems.aspx", + "parentReference": { + "sharepointIds": { + "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4" + }, + "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" + }, + "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/Forms/AllItems.aspx" + } + } + ], + "total": 1, + "moreResultsAvailable": false + } + ] + } + ] +} +``` + +## Example 2: Search containers by title + +This example queries all containers by a specified container display name and the SharePoint Embedded application didn't opt out from content discoverability on Microsoft 365. The response includes all container instances in the tenant that match the criteria: + +### Request + +```HTTP +POST /search/query +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": [ + "drive" + ], + "query": { + "queryString": "Title:'contoso' AND ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" + } + } + ] +} +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json + +{ + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", + "value": [ + { + "searchTerms": [ + "contoso" + ], + "hitsContainers": [ + { + "hits": [ + { + "hitId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "rank": 1, + "summary": "Everything about Contoso", + "resource": { + "@odata.type": "#microsoft.graph.drive", + "id": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "createdBy": { + "user": { + "displayName": "Dylan Williams" + } + }, + "lastModifiedDateTime": "2024-01-18T19:45:25Z", + "name": "AllItems.aspx", + "parentReference": { + "sharepointIds": { + "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4" + }, + "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" + }, + "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/Forms/AllItems.aspx" + } + } + ], + "total": 1, + "moreResultsAvailable": false + } + ] + } + ] +} +``` + +## Example 3: Search containers by container description + +This example queries all containers by the specified container type and container description, with the SharePoint Embedded application opted out from content discoverability on Microsoft 365. The response includes all container instances in the tenant that match the criteria: + +### Request + +```HTTP +POST /search/query +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": [ + "drive" + ], + "query": { + "queryString": "Description:'Everything' AND ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json + +{ + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", + "value": [ + { + "searchTerms": [], + "hitsContainers": [ + { + "hits": [ + { + "hitId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "rank": 1, + "summary": "Everything about Contoso", + "resource": { + "@odata.type": "#microsoft.graph.drive", + "id": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "createdBy": { + "user": { + "displayName": "Dylan Williams" + } + }, + "lastModifiedDateTime": "2024-01-18T19:45:25Z", + "name": "AllItems.aspx", + "parentReference": { + "sharepointIds": { + "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4" + }, + "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" + }, + "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/Forms/AllItems.aspx" + } + } + ], + "total": 1, + "moreResultsAvailable": false + } + ] + } + ] +} +``` + +## Example 4: Search for content by title in a specific container + +This example queries all the content by a specific title in a specific container instance, with the SharePoint Embedded application opted out from content discoverability on Microsoft 365. The response includes all `driveItems` in the specific container instance that match the criteria: + +### Request + +```HTTP +POST /search/query +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": [ + "driveItem" + ], + "query": { + "queryString": "Title:'contoso' AND ContainerId:b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json + +{ + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", + "value": [ + { + "searchTerms": [ + "contoso", + "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0" + ], + "hitsContainers": [ + { + "hits": [ + { + "hitId": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", + "rank": 1, + "summary": "Contoso Detailed Design Contoso Product Specification", + "resource": { + "@odata.type": "#microsoft.graph.driveItem", + "size": 56, + "fileSystemInfo": { + "createdDateTime": "2024-01-18T19:46:48Z", + "lastModifiedDateTime": "2024-01-18T19:46:48Z" + }, + "listItem": { + "@odata.type": "#microsoft.graph.listItem", + "fields": {}, + "id": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" + }, + "id": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", + "createdBy": { + "user": { + "displayName": "Dylan Williams", + "email": "dywilliams@contoso.onmicrosoft.com" + } + }, + "createdDateTime": "2024-01-18T19:46:48Z", + "lastModifiedBy": { + "user": { + "displayName": "Dylan Williams", + "email": "dywilliams@contoso.onmicrosoft.com" + } + }, + "lastModifiedDateTime": "2024-01-18T19:46:48Z", + "name": "contoso.txt", + "parentReference": { + "driveId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "id": "01SHAK4OVPJ5Q5P6YD6VCZHPV7PKILUJ65", + "sharepointIds": { + "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4", + "listItemId": "1", + "listItemUniqueId": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" + }, + "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" + }, + "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/contoso.txt" + } + } + ], + "total": 1, + "moreResultsAvailable": false + } + ] + } + ] +} +``` + +## Example 5: Search by content + +This example queries all the content by the specified words across all containers of a specific container type, with the SharePoint Embedded application opted out from content discoverability on Microsoft 365. The response includes all `driveItems` that match the criteria: + +### Request + +```HTTP +POST /search/query +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": [ + "driveItem" + ], + "query": { + "queryString": "'contoso' AND ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json + +{ + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)" + "value": [ + { + "searchTerms": [ + "contoso" + ], + "hitsContainers": [ + { + "hits": [ + { + "hitId": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", + "rank": 1, + "summary": "Contoso Detailed Design Contoso Product Specification", + "resource": { + "@odata.type": "#microsoft.graph.driveItem", + "size": 56, + "fileSystemInfo": { + "createdDateTime": "2024-01-18T19:46:48Z", + "lastModifiedDateTime": "2024-01-18T19:46:48Z" + }, + "listItem": { + "@odata.type": "#microsoft.graph.listItem", + "fields": {}, + "id": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" + }, + "id": "01SHAK4OWIBDXV4NG2JVFLSGUXVKZ5VF5E", + "createdBy": { + "user": { + "displayName": "Dylan Williams", + "email": "dywilliams@contoso.onmicrosoft.com" + } + }, + "createdDateTime": "2024-01-18T19:46:48Z", + "lastModifiedBy": { + "user": { + "displayName": "Dylan Williams", + "email": "dywilliams@contoso.onmicrosoft.com" + } + }, + "lastModifiedDateTime": "2024-01-18T19:46:48Z", + "name": "contoso.txt", + "parentReference": { + "driveId": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "id": "01SHAK4OVPJ5Q5P6YD6VCZHPV7PKILUJ65", + "sharepointIds": { + "listId": "26d6a67d-bd07-4646-9c5b-85b0e519d6f4", + "listItemId": "1", + "listItemUniqueId": "5eef08c8-da34-4a4d-b91a-97aab3da97a4" + }, + "siteId": "contoso.sharepoint.com,05031a50-e9c7-474c-889e-7cf44659a5b2,e00b849e-3cec-4ade-8f7b-96d1f0f598fa" + }, + "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_05031a50-e9c7-474c-889e-7cf44659a5b2/Document Library/contoso.txt" + } + } + ], + "total": 1, + "moreResultsAvailable": false + } + ] + } + ] +} +``` +## Example 6: Search containers by container custom property + +This example queries all containers by the specified custom property key:value pair, with the SharePoint Embedded application that has opted out from content discoverability on Microsoft 365. The response includes all containers that match the criteria: + +> [!NOTE] +> The custom property name must be appended with the text "OWSTEXT" in the query string. + +### Request + +```HTTP +POST /search/query +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": [ + "drive" + ], + "query": { + "queryString": "customPropertyNametOWSTEXT:customPropertyValue AND ContainerTypeId:498c6855-8f0e-0de7-142e-4e9ff86af9ae" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json + +{ + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", + "value": [ + { + "searchTerms": [], + "hitsContainers": [ + { + "hits": [ + { + "hitId": "b!C4Psl-ZZZkaZINVay8RKt2fqu3agJbVNlIUjNuIzqlPhOJMrr7ThS4aR8L8XdZu4", + "rank": 1, + "summary": "Everything about Contoso", + "resource": { + "@odata.type": "#microsoft.graph.drive", + "id": "b!UBoDBcfpTEeInnz0Rlmlsp6EC-DsPN5Kj3uW0fD1mPp9ptYmB71GRpxbhbDlGdb0", + "createdBy": { + "user": { + "displayName": "Dylan Williams" + } + }, + "lastModifiedDateTime": "2024-08-02T17:31:06Z", + "name": "AllItems.aspx", + "parentReference": { + "sharepointIds": { + "listId": "2b9338e1-b4af-4be1-8691-f0bf17759bb8" + }, + "siteId": "contoso.sharepoint.com,97ec830b-59e6-4666-9920-d55acbc44ab7,76bbea67-25a0-4db5-9485-2336e233aa53" + }, + "webUrl": "https://contoso.sharepoint.com/contentstorage/CSP_97ec830b-59e6-4666-9920-d55acbc44ab7/Document Library/Forms/AllItems.aspx" + } + } + ], + "total": 1, + "moreResultsAvailable": false + } + ] + } + ] +} +``` +## Example 7: Search for content with specific content properties in the response body and sort the results + +This example queries container content by specific words and requires the response to include all specified attributes on the content. Properties that are [sortable](/sharepoint/technical-reference/crawled-and-managed-properties-overview) can be used to sort the results. + +### Request + +```HTTP +POST /search/query +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": [ + "driveItem" + ], + "query": { + "queryString": "Everything about contoso" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + }, + "fields": [ + "SampleOWSText", + "id", + "name", + "parentReference", + "file", + "folder", + "webUrl", + "createdDateTime", + "lastModifiedDateTime", + "size", + "fileSystemInfo", + "createdBy", + "lastModifiedBy", + "fileSystemInfo", + "fileSystemInfo" + ], + "sortProperties": [ + { + "name": "Created", + "isDescending": false + } + ] + } + ] +} +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json + +{ + "@odata.context": "https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searchResponse)", + "value": [ + { + "searchTerms": [ + "everything", + "about", + "contoso" + ], + "hitsContainers": [ + { + "hits": [ + { + "hitId": "017JL52SWZQ2M5MULUKFBIL7SZ56EB4V2Z", + "rank": 1, + "summary": "Everything about Contoso", + "resource": { + "@odata.type": "#microsoft.graph.driveItem", + "size": 17363, + "fileSystemInfo": { + "createdDateTime": "2024-06-20T21:49:03Z", + "lastModifiedDateTime": "2024-04-01T16:57:00Z" + }, + "listItem": { + "@odata.type": "#microsoft.graph.listItem", + "id": "d69986d9-7451-4251-85fe-59ef881e5759", + "fields": { + "sampleOWSText": "Sample Value", + "id": "AAAAAH_MwHAjYctMtjgTN1cWJnYHAApvY20ubJFGtzLui9sETKcAAAAAASsAAApvY20ubJFGtzLui9sETKcAAAAAJqsAAA2", + "size": 17363, + "createdBy": "Dylan Williams" + } + }, + "id": "017JL52SWZQ2M5MULUKFBIL7SZ56EB4V2Z", + "createdBy": { + "user": { + "displayName": "Dylan Williams", + "email": "dywilliams@contoso.onmicrosoft.com" + } + }, + "createdDateTime": "2024-06-20T21:49:03Z", + "lastModifiedBy": { + "user": { + "displayName": "Dylan Williams", + "email": "dywilliams@contoso.onmicrosoft.com" + } + }, + "lastModifiedDateTime": "2024-04-01T16:57:00Z", + "name": "Constoso Details.docx", + "parentReference": { + "driveId": "b!rWzsZXXFWEOeeP31bSE5BTjn_6qC3dFNloUBMv62EMilewHuRwQrQau-zcJu2BT0", + "id": "017JL52SXQSKBKPB7VKZCJE5ZSWUN4LZDZ", + "sharepointIds": { + "listId": "ee017ba5-0447-412b-abbe-cdc26ed814f4", + "listItemId": "1", + "listItemUniqueId": "d69986d9-7451-4251-85fe-59ef881e5759" + }, + "siteId": "contoso.sharepoint.com,65ec6cad-c575-4358-9e78-fdf56d213905,aaffe738-dd82-4dd1-9685-0132feb610c8" + }, + "webUrl": "https://contoso.sharepointt.com/contentstorage/CSP_65ec6cad-c575-4358-9e78-fdf56d213905/Document Library/Constoso Details.docx" + } + } + ], + "total": 1, + "moreResultsAvailable": false + } + ] + } + ] +} +``` + +## Known Limitations + +- Search requests run in the context of the signed-in user. Search results are only scoped to enforce any access control applied to the items by the user. For example, search results will include all container or container content matching the search criteria and accessible by the user regardless of whether the SharePoint Embedded application is authorized to access. You should specify the desired container type by including the ContainerTypeId as part of your **queryString** when searching for containers or container content to ensure search results are properly scoped. +- For your application to access the containers or container content in search results, it must have access permissions to the corresponding container types. + +## Enumerate (filter) SharePoint Embedded content + +Content can also be enumerated using URL parameters to return specific content in SharePoint Embedded containers. This does not use the search API to retrieve items. See the [enumerate query parameter](/graph/filter-query-parameter?tabs=http) for reference. + +## Example 1: enumerate content by a specific column property and view the results + +This example enumerates the specified container content by the column property that is on the item: + +### Request + +```HTTP +GET https://graph.microsoft.com/v1.0/drives/{{ContainerID}}/items?$filter=startswith(listitem/fields/{{ColumnProperty}}, '{{Value}}')&$expand=listitem($expand=fields) +``` + +### Response + +```HTTP +HTTP/1.1 200 OK +Content-type: application/json +{ + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#drives('b%21CORq-a8orUGIrd3_z9t1_vjCBSeqM3JKhDglEU3DIDvEl-Hms0qoQ7QCWYNQfGOF')/items(listItem(fields()))", + "value": [ + { + "@odata.etag": "\"{B8051D89-836E-4B8E-BD2B-7634BAC92825},21\"", + "@microsoft.graph.downloadUrl": "https://.sharepoint.com/contentstorage/CSP_f96ae408-28af-41ad-88ad-ddffcfdb75fe/_layouts/15/download.aspx?UniqueId=b8051d89-836e-4b8e-bd2b-7634bac92825&Translate=false&tempauth=v1.eyJzaXRlaWQiOiJmOTZhZTQwOC0yOGFmLTQxYWQtODhhZC1kZGZmY2ZkYjc1ZmUiLCJhcHBfZGlzcGxheW5hbWUiOiJTUEUtQmFzZWJhbGwiLCJhcHBpZCI6ImZiN2NmNTIwLWNiMzMtNDViZi1hMjM4LWFlNTFkMzE2NjY1ZiIsImF1ZCI6IjAwMDAwMDAzLTAwMDAtMGZmMS1jZTAwLTAwMDAwMDAwMDAwMC9wdWNlbGlrZW50ZXJwcmlzZS5zaGFyZXBvaW50LmNvbUAxNTNhNmViZS1mZjYyLTRiY2UtYjFiYy1hMWVkYTNiYzY2NDUiLCJleHAiOiIxNzMxNjE3MDE3In0.CgoKBHNuaWQSAjY5EgsIzpKzp9W7wj0QBRoNMjAuMTkwLjEzNS40MioscW54cjFGalBneHh2N1lGTkp1dUpxTFZWdFFIS1hOQ2RlQ3EvUUk2aHhlcz0wuAE4AUIQoWPmC1YwAABF4iHcgCWrfkoQaGFzaGVkcHJvb2Z0b2tlbnIpMGguZnxtZW1iZXJzaGlwfDEwMDM3ZmZlOWE5NDg5ZGRAbGl2ZS5jb216ATKCARIJvm46FWL_zksRsbyh7aO8ZkWSAQVTdGV2ZZoBB1B1Y2VsaWuiASdzdGV2ZUBwdWNlbGlrZW50ZXJwcmlzZS5vbm1pY3Jvc29mdC5jb22qARAxMDAzN0ZGRTlBOTQ4OUREsgFyY29udGFpbmVyLnNlbGVjdGVkIGFsbGZpbGVzLnJlYWQgYWxsZmlsZXMud3JpdGUgY29udGFpbmVyLnNlbGVjdGVkIGFsbHNpdGVzLnJlYWQgYWxscHJvZmlsZXMucmVhZCBhbGxwcm9maWxlcy5yZWFkyAEB.tfaYgtjhQxMctJeHUWb9RU7CChHXqFHT0FaM9Dt7J9I&ApiVersion=2.1", + "createdDateTime": "2024-09-20T16:46:00Z", + "eTag": "\"{B8051D89-836E-4B8E-BD2B-7634BAC92825},21\"", + "id": "01UELPCREJDUC3Q3UDRZF32K3WGS5MSKBF", + "lastModifiedDateTime": "2024-11-01T08:14:28Z", + "name": "ClaimExample-1.docx", + "size": 2299607, + "webUrl": "https://.sharepoint.com/contentstorage/CSP_f96ae408-28af-41ad-88ad-ddffcfdb75fe/_layouts/15/Doc.aspx?sourcedoc=%7BB8051D89-836E-4B8E-BD2B-7634BAC92825%7D&file=ClaimExample-1.docx&action=default&mobileredirect=true", + "cTag": "\"c:{B8051D89-836E-4B8E-BD2B-7634BAC92825},5\"", + "commentSettings": { + "commentingDisabled": { + "isDisabled": false + } + }, + "createdBy": { + "application": { + "displayName": "SPEContainerType", + "id": "fb7cf520-cb33-45bf-a238-ae51d316665f" + }, + "user": { + "displayName": "SharePoint App" + } + }, + "lastModifiedBy": { + "application": { + "displayName": "SPEContainerType", + "id": "fb7cf520-cb33-45bf-a238-ae51d316665f" + }, + "user": { + "displayName": "Steve Pucelik", + "email": "Steve@.onmicrosoft.com" + } + }, + "parentReference": { + "driveId": "b!CORq-a8orUGIrd3_z9t1_vjCBSeqM3JKhDglEU3DIDvEl-Hms0qoQ7QCWYNQfGOF", + "driveType": "other", + "id": "01UELPCRF6Y2GOVW7725BZO354PWSELRRZ", + "path": "/drives/b!CORq-a8orUGIrd3_z9t1_vjCBSeqM3JKhDglEU3DIDvEl-Hms0qoQ7QCWYNQfGOF/root:", + "sharepointIds": { + "listId": "e6e197c4-4ab3-43a8-b402-5983507c6385", + "listItemUniqueId": "c4782251-bdd3-4766-a747-b2a2f51c3a00", + "siteId": "f96ae408-28af-41ad-88ad-ddffcfdb75fe", + "siteUrl": "https://.sharepoint.com/contentstorage/CSP_f96ae408-28af-41ad-88ad-ddffcfdb75fe", + "tenantId": "153a6ebe-ff62-4bce-b1bc-a1eda3bc6645", + "webId": "2705c2f8-33aa-4a72-8438-25114dc3203b" + } + }, + "file": { + "mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "hashes": { + "quickXorHash": "DMzi0kCsuukcHlMXiPX9tmTCXtA=" + } + }, + "fileSystemInfo": { + "createdDateTime": "2024-09-20T16:46:00Z", + "lastModifiedDateTime": "2024-11-01T08:14:28Z" + }, + "shared": { + "scope": "unknown" + }, + "listItem@odata.context": "https://graph.microsoft.com/v1.0/$metadata#drives('b%21CORq-a8orUGIrd3_z9t1_vjCBSeqM3JKhDglEU3DIDvEl-Hms0qoQ7QCWYNQfGOF')/items('01UELPCREJDUC3Q3UDRZF32K3WGS5MSKBF')/listItem(fields())/$entity", + "listItem": { + "@odata.etag": "\"{B8051D89-836E-4B8E-BD2B-7634BAC92825},21\"", + "createdDateTime": "2024-09-20T16:46:00Z", + "eTag": "\"{B8051D89-836E-4B8E-BD2B-7634BAC92825},21\"", + "id": "23", + "lastModifiedDateTime": "2024-11-01T08:14:28Z", + "webUrl": "https://.sharepoint.com/contentstorage/CSP_f96ae408-28af-41ad-88ad-ddffcfdb75fe/_layouts/15/Doc.aspx?sourcedoc=%7BB8051D89-836E-4B8E-BD2B-7634BAC92825%7D&file=ClaimExample-1.docx&action=default&mobileredirect=true", + "createdBy": { + "application": { + "displayName": "SPEContainerType", + "id": "fb7cf520-cb33-45bf-a238-ae51d316665f" + }, + "user": { + "displayName": "SharePoint App" + } + }, + "lastModifiedBy": { + "application": { + "displayName": "SPEContainerType", + "id": "fb7cf520-cb33-45bf-a238-ae51d316665f" + }, + "user": { + "displayName": "Steve Pucelik", + "email": "Steve@M.onmicrosoft.com" + } + }, + "parentReference": { + "id": "0", + "path": "Document Library", + "siteId": "f96ae408-28af-41ad-88ad-ddffcfdb75fe" + }, + "contentType": { + "id": "0x0101004368E78BC3115C4CAD94FEA35E0F9D90", + "name": "Document" + }, + "fields@odata.context": "https://graph.microsoft.com/v1.0/$metadata#drives('b%21CORq-a8orUGIrd3_z9t1_vjCBSeqM3JKhDglEU3DIDvEl-Hms0qoQ7QCWYNQfGOF')/items('01UELPCREJDUC3Q3UDRZF32K3WGS5MSKBF')/listItem/fields/$entity", + "fields": { + "@odata.etag": "\"{B8051D89-836E-4B8E-BD2B-7634BAC92825},21\"", + "id": "23", + "FileLeafRef": "ClaimExample-1.docx", + "": "", + "ContentType": "Document", + "Created": "2024-09-20T16:46:00Z", + "AuthorLookupId": "1073741822", + "Modified": "2024-11-01T08:14:28Z", + "EditorLookupId": "7", + "_CheckinComment": "", + "LinkFilenameNoMenu": "ClaimExample-1.docx", + "LinkFilename": "ClaimExample-1.docx", + "DocIcon": "docx", + "FileSizeDisplay": "2299607", + "ItemChildCount": "0", + "FolderChildCount": "0", + "_ComplianceFlags": "", + "_ComplianceTag": "", + "_ComplianceTagWrittenTime": "", + "_ComplianceTagUserId": "", + "_CommentCount": "", + "_LikeCount": "", + "_DisplayName": "Confidential \\ Internal only", + "AppAuthorLookupId": "1", + "AppEditorLookupId": "1", + "Edit": "0", + "_UIVersionString": "19.0", + "MediaServiceImageTags@odata.type": "#Collection(microsoft.graph.Json)", + "MediaServiceImageTags": [] + } + } + } + ] +} +``` + +## Example 2: Enumerate content by a specific column property and Order the results + +This example enumerates the specified container content by the column property that is on the item and will order the results by the column specified: + +### Request + +```HTTP +GET https://graph.microsoft.com/v1.0/drives/{{ContainerID}}/items?$filter=listitem/fields/{{ColumnProperty}} eq '{{Value}}'&$select=id,name,lastModifiedDateTime,size&$expand=listitem($expand=fields)&$orderby=createdDateTime desc +Headers: +Content-Type: application/json +Prefer: HonorNonIndexedQueriesWarningMayFailRandomly +``` + +> [!NOTE] +> +> When a container has more than 5,000 items and you are using the enumerate method with the OrderBy clause, you must include the following in the header of your request. +> +> `Content-Type: application/json` +> `Prefer: HonorNonIndexedQueriesWarningMayFailRandomly` +## Example 3: Enumerate content by mulitple column properties and Order the results + +This example enumerates the specified container content by the column property you specify and the name of the document (listitem/fields/FileLeafRef) that is on the item and will order the results by the column specified: + +### Request + +```HTTP +GET https://graph.microsoft.com/v1.0/drives/{{ContainerID}}/items?$filter=listitem/fields/{{ColumnProperty1}} eq '{{Value}}' AND listitem/fields/FileLeafRef eq '{{Value}}' &$select=id,name,lastModifiedDateTime,size&$expand=listitem($expand=fields)&$orderby=createdDateTime desc +Headers: +Content-Type: application/json +Prefer: HonorNonIndexedQueriesWarningMayFailRandomly +``` \ No newline at end of file diff --git a/docs/embedded/development/content-experiences/user-experiences-overview.md b/docs/embedded/development/content-experiences/user-experiences-overview.md new file mode 100644 index 000000000..2cf79b470 --- /dev/null +++ b/docs/embedded/development/content-experiences/user-experiences-overview.md @@ -0,0 +1,61 @@ +--- +title: Content Experiences Overview +description: Experiences with SharePoint Embedded content +ms.date: 07/30/2024 +ms.localizationpriority: high +--- + +# User experiences overview + +SharePoint Embedded provides a comprehensive set of user experience features like open and editing Office files, file preview, or in-app search that you can use to build the right user experiences for your applications. + +## Open & edit using Office + +Office documents from SharePoint Embedded applications can be opened for viewing, editing, and collaborating using either the web or Office applications for a richer viewing and editing experience. Learn more about [Office experiences available on SharePoint Embedded](./office-experience.md). + +You can set up your applications to launch Office when a user selects an Office document within your application. This includes options to directly launch an Office application or to open it in a specific mode, such as view (for read-only content) or edit (for editing mode). Learn how to [configure the right Office Experience for your Office Documents](../tutorials/launch-experience.md) + +## Preview content + +Integrate your application with SharePoint Embedded player plugin to offer file preview experiences on a wide range of supported file types. You can embed the file preview experiences either in an iFrame or open a new page. Learn how to [offer File Preview experiences for content on your applications](../tutorials/using-file-preview.md) + +## Download + +You can use [Microsoft Graph's Download DriveItem API](/graph/api/driveitem-get-content) to offer download file user experiences for your applications. This will generate a short-lived, pre-authenticated URL that allows users to download files from your applications. + +> [!NOTE] +> A direct link to the file lacks the appropriate authorization from your application. If used directly in a browser, this would yield an access denied. + +## Content discovery in Microsoft 365 + +You can control how your content appears in the Microsoft 365 experience. The default behavior is SharePoint Embedded application content will be hidden in Microsoft 365 environments including office.com, oneDrive.com, or other Microsoft intelligent file discovery features. The default behavior also excludes Copilot for Microsoft 365 from grounding with your SharePoint Embedded application content. + +If you want to opt into the Microsoft 365 experience, during container type creation, you can change the default settings using cmdlet [Set-SPOContainerTypeConfiguration](../../administration/developer-admin/dev-admin.md#container-type-configuration-properties) as per this example: + +```powershell +Set-SPOContainerTypeConfiguration + -ContainerTypeID + -discoverabilityDisabled $False +``` + +In this way, your files will be integrated into the Microsoft 365 environment, participating in intelligent file discovery. + +> [!NOTE] +> +> 1. If you modify the settings after creating some content, it may take up to 30 days for these changes to achieve full consistency across all consuming tenants. +> 1. To enable the sharing user experience for your content in Office.com, additional application permissions **must** be added at the time of the container type registration process. To add more permission to enable sharing dialog, refer to the following code: + +```http +PUT /storageContainerTypes/{containerTypeId}/applicationPermissions +Content-Type: application/json + +{ + "appId": "4765445b-32c6-49b0-83e6-1d93765276ca", + "delegated": ["readContent","writeContent"], + "appOnly": ["none"] +} +``` + +## Recycle bin + +You can use Microsoft Graph to either delete or permanently delete items in containers. Deleted items are moved to the container’s recycle bin and retained for 93 days. During this period, the items can be restored or permanently deleted using Microsoft Graph. An item in the recycle bin is permanently deleted when it exceeds the 93-day retention period. Permanently deleted items can't be restored. diff --git a/docs/embedded/development/declarative-agent/spe-da-adv.md b/docs/embedded/development/declarative-agent/spe-da-adv.md new file mode 100644 index 000000000..54b6c5c3a --- /dev/null +++ b/docs/embedded/development/declarative-agent/spe-da-adv.md @@ -0,0 +1,315 @@ +--- +title: SharePoint Embedded agent Advanced Topics +description: Learn how the semantic index powers Retrieval-Augmented Generation (RAG) to provide accurate, context-aware AI responses in SharePoint Embedded agent. +ms.date: 06/10/2025 +ms.localizationpriority: high +--- + +# SharePoint Embedded agent Advanced Topics Overview + +This advanced guide covers how the semantic index powers Retrieval-Augmented Generation (RAG) to provide accurate, context-aware AI responses. We explore how these concepts work together to ensure your agent retrieves relevant information from your data and returns grounded answers. + +## Caveats + +### Configuration + +#### Required Container Type Configuration + +##### DiscoverabilityDisabled + +The [`discoverabilityDisabled`](../../administration/developer-admin/dev-admin.md#container-type-configuration-properties) property controls whether Microsoft 365 can discover [drive items](/graph/api/resources/driveitem) within a specific container type. + +If you’re updating an existing container type to set this property to `false`, allow up to **24 hours** for the configuration change to fully propagate before: + +- Creating new containers, +- Uploading files to containers, or +- Using SPE agent to interact with folders or files. + +This ensures the agent can correctly access and surface the content. + +Here is an example of how to set `discoverabilityDisabled` to `false` with [Set-SPOContainerTypeConfiguration](/powershell/module/SharePoint-online/set-spocontainertypeconfiguration#examples) + +```powershell +Set-SPOContainerTypeConfiguration -ContainerTypeId 4f0af585-8dcc-0000-223d-661eb2c604e4 -DiscoverabilityDisabled $false +``` + +Discoverability can also be disabled using the Visual Studio Code SharePoint Embedded extension + +![Using the VS Code extension for SPE to set DiscoverabilityDisabled to false](../../images/speco-vscodeextensiondisablediscovery.png) + +##### CSP Policies + +The Content-Security-Policy (CSP) for embedded chat hosts ensures that only specified hosts can load the chat component. Specifically, the `CopilotEmbeddedChatHosts` setting is used in a [Content-Security-Policy](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy) header as a `frame-ancestors` value. This helps in securing the application by restricting which domains can embed the chat component. + +The SPE Administrator on the owning tenant can set this setting by using the `Set-SPOContainerTypeConfiguration` cmdlet: + +```powershell +# Note this MUST be run in Windows PowerShell. It will not work in PowerShell. +Import-Module -Name "Microsoft.Online.SharePoint.PowerShell" +Connect-SPOService "https://-admin.sharepoint.com" +# Login with your admin account. +# ... + +Set-SPOContainerTypeConfiguration -ContainerTypeId XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -CopilotEmbeddedChatHosts @("http://localhost:3000", "https://contoso.sharepoint.com", "https://fabrikam.com") + +# This will set the container type configuration “CopilotEmbeddedChatHosts” accordingly. +# Replication of this configuration on consuming tenants can take up to 24 hours +# ... + +# Confirm setting value +Get-SPOContainerTypeConfiguration -ContainerTypeId XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + +# On a consuming tenant, you may confirm the setting value as follows +Get-SPOApplication -OwningApplicationId | Select-Object CopilotEmbeddedChatHosts + +OwningApplicationId : +OwningApplicationName : SharePoint Embedded App +Applications : {} +CopilotEmbeddedChatHosts : {http://localhost:3000, https://contoso.sharepoint.com, https://fabrikam.com} +``` + +> [!NOTE] +> +> If this configuration isn't set, the [Content-Security-Policy](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy) is by default set to +> [frame-ancestors](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors): "none", which means no one can embed the agent. + +A SharePoint Embedded Administrator on a consuming tenant may override the values specified by the owning application, by using the consuming tenant cmdlets: + +- [Set-SPOApplication](/powershell/module/SharePoint-online/set-spoapplication) to set the `CopilotEmbeddedChatHosts` property. +- [Get-SPOApplication](/powershell/module/SharePoint-online/get-spoapplication) to get the `CopilotEmbeddedChatHosts` property. + +> [!NOTE] +> +> A consuming tenant override must be a subset of what the owning tenant configured for `CopilotEmbeddedChatHosts`. An administrator +> in a consuming tenant cannot set values that the application owner has not specified for the container type. The override capabilities +> is intended for consuming tenant administrators to enable the agent in only a subset of hosts that the owning application has defined. + +Here's an example of how a consuming tenant can override the setting: + +```powershell +# Note this MUST be run in Windows PowerShell. It will not work in PowerShell. +Import-Module -Name "Microsoft.Online.SharePoint.PowerShell" +Connect-SPOService "https://-admin.sharepoint.com" +# Login with your admin account. +# ... + +Set-SPOApplication -OwningApplicationId XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -CopilotEmbeddedChatHosts @("https://contoso.sharepoint.com", "https://fabrikam.com") + +# This will set the container type configuration “CopilotEmbeddedChatHosts” accordingly +# Note that @("https://contoso.sharepoint.com", "https://fabrikam.com") is a subset of what we defined in the owning tenant +# Those values were @("http://localhost:3000", "https://contoso.sharepoint.com", "https://fabrikam.com") + +# Confirm the configuration + +Get-SPOApplication -OwningApplicationId | Select-Object CopilotEmbeddedChatHosts + +OwningApplicationId : +OwningApplicationName : SharePoint Embedded App +Applications : {} +CopilotEmbeddedChatHosts : {https://contoso.sharepoint.com, https://fabrikam.com} +``` + +#### Optional Configuration + +##### Authentication and 3P Cookies + +The `iframe` used by SharePoint Embedded agent authenticates users using third-party cookies. If third-party cookies are disabled in the user's browser, the iframe can't authenticate automatically. In this case, a popup prompts the user to sign in manually, ensuring that authentication can still be completed. + +## Advanced Topics + +### Application Scoping + +Application scoping in SharePoint Embedded agent (SPE agent) involves defining the boundaries and context within which the tool operates, ensuring its features and capabilities are tailored to meet the specific needs of different applications. This process helps customize the agent's functionality, making it more effective and relevant for various use cases. + +When SPE agent users query the LLM, it will only have access to files that the **User+Application** have access to. The effective permissions for the agent session will be the intersection of your SharePoint Embedded application's permissions and the user's permissions. + +![Venn Diagram with SPE application access on left, SPE agent in middle and consuming tenant user on right, overlapped area is what agent can access](../../images/speco-appscopingvenn.png) + +### Information Architecture + +Files in SharePoint Embedded are naturally [semantic indexed](spe-da-adv.md#semantic-index). This semantic index underpins retrieval augmented generation [(RAG)](spe-da-adv.md#retrieval-augmented-generation-rag) workflows by providing relevant context from your stored content at query time. In essence, it [grounds](spe-da-adv.md#grounding) the AI responses, ensuring they directly reference accurate information in your containers rather than relying on general knowledge alone. + +![How RAG works in SPE](../../images/speco-ragm365.png) + +With SharePoint Embedded agent, you can further ground the large language models (LLM) response on [specific files or drive items.](spe-da-adv.md#scoping-your-agent-to-specific-content). + +### Semantic index + +[Learn more about semantic index for Microsoft 365 Copilot here](/microsoftsearch/semantic-index-for-copilot) + +The semantic index allows for quick and accurate searches based on data similarity. This means it can find the most relevant information not just by exact matches, but also by understanding the context and meaning. + +### Retrieval-Augmented Generation (RAG) + +RAG enables you to reference relevant source materials stored in a repository at runtime. The data is retrieved from the index and is used to augment the prompt sent to the large language model (LLM). Some benefits of RAG​: + +- Treat data sources as knowledge without having to train your model​ +- Uses search (retrieval) results as additional context in your prompt​ +- Generates the output using the prompt and the supplied context + +The LLM uses the data to inform and construct the response. + +​![The flow of a RAG query](../../images/speco-ragquery.png) + +### Grounding + +Grounding in the context of SPE agent refers to the process of providing input sources to the large language model (LLM) related to the user's prompt. This helps improve the specificity of the prompt and ensures that the responses are relevant and actionable to the user's specific task. The data the agent is grounded on will be the contents of the container type in the agent application. Behind the scenes, SPE agent uses Microsoft 365 Copilot. [Learn more about Microsoft 365 Copilot architecture](/copilot/microsoft-365/microsoft-365-copilot-architecture). + +### Scoping your agent to specific content + +SharePoint Embedded (SPE) agent has the ability to restrict the data sources it has access to. The sample code below shows the available data source types. [This example](https://github.com/microsoft/SharePoint-Embedded-Samples/blob/main/Samples/spe-typescript-react-azurefunction/react-client/src/providers/ChatController.ts#L15) shows how to configure the SDK. + +```typescript +export type IDataSourcesProps = + | IFileDataSource + | IFolderDataSource + | IDocumentLibraryDataSource + | ISiteDataSource + | IWorkingSetDataSource + | IMeetingDataSource; + +export enum DataSourceType { + File = 'File', + Folder = 'Folder', + DocumentLibrary = 'DocumentLibrary', + Site = 'Site', + WorkingSet = 'WorkingSet', + Meeting = 'Meeting' +} +``` + +#### Supported document types for scoping + +[Reference - File Formats Support By copilot](https://support.microsoft.com/topic/file-formats-supported-by-copilot-1afb9a70-2232-4753-85c2-602c422af3a8) + +**Documents**: PDF, DOCX, XLSX, PPTX + +**Text-based Files**: RTF, TXT, CSV, LOG, INI, CONFIG + +**Audio**: WAV + +**Programming Languages**: PY, JS, JSX, JAVA, PHP, CS, C, CPP, CXX, H, HPP, M, COFFEE, DART, LUA, PL, PM, RB, RS, SWIFT, GO, KT, KTS, R, SCALA, T, TS, TSX + +**Shell Scripts**: BASH, SH, ZSH + +**Markup and Documentation**: HTML, CSS, MD, RMD, TEX, LATEX + +**Database Languages**: SQL + +**Data Serialization Formats**: IPYNB, JSON, TOML, YAML, YML + +##### Language/Locale + +The agent `iframe` dynamically loads localization settings to ensure that the chat interface is displayed in the appropriate language. These settings are derived from SharePoint, which provides a comprehensive set of localization options. + +When the agent iframe is initialized, it retrieves the current localization settings from SharePoint. These settings dictate the language and regional preferences for the chat interface, ensuring that all UI elements, messages, and interactions are presented in the user's preferred language. + +You can have this localized by setting your language options in the SharePoint account settings: [Change your personal language and region settings - Microsoft Support](https://support.microsoft.com/office/change-your-personal-language-and-region-settings-caa1fccc-bcdb-42f3-9e5b-45957647ffd7). + +> [!NOTE] +> +> If your M365 language setting is different from your SharePoint account language setting, your M365 language setting takes precedence. You can change your M365 language setting here: [Change your display language in Microsoft 365](https://support.microsoft.com/topic/change-your-display-language-and-time-zone-in-microsoft-365-for-business-6f238bff-5252-441e-b32b-655d5d85d15b). + +An additional locale option can be passed in through the `ChatLaunchConfig` to further set the language the agent responds in: + +```typescript + const [chatConfig] = React.useState({ + header: ChatController.instance.header, + theme: ChatController.instance.theme, + zeroQueryPrompts: ChatController.instance.zeroQueryPrompts, + suggestedPrompts: ChatController.instance.suggestedPrompts, + instruction: ChatController.instance.pirateMetaPrompt, + locale: "en", + }); +``` + +###### Locale Options + +Here are some examples of locale options you can use: + +| Locale Code | Common Name | +|--------------|------------------------------------------| +| af | Afrikaans | +| en-gb | English (UK) | +| he | Hebrew | +| kok | Konkani | +| nn-no | Norwegian (Nynorsk) | +| sr-latn-rs | Serbian (Latin, Serbia) | +| am-et | Amharic | +| es | Spanish | +| hi | Hindi | +| lb-lu | Luxembourgish | +| or-in | Odia (India) | +| sv | Swedish | +| ar | Arabic | +| es-mx | Spanish (Mexico) | +| hr | Croatian | +| lo | Lao | +| pa | Punjabi | +| ta | Tamil | +| as-in | Assamese | +| et | Estonian | +| hu | Hungarian | +| lt | Lithuanian | +| pl | Polish | +| te | Telugu | +| az-latn-az | Azerbaijani (Latin, Azerbaijan) | +| eu | Basque | +| hy | Armenian | +| lv | Latvian | +| pt-br | Portuguese (Brazil) | +| th | Thai | +| bg | Bulgarian | +| fa | Persian | +| id | Indonesian | +| mi-nz | Maori (New Zealand) | +| pt-pt | Portuguese (Portugal) | +| tr | Turkish | +| bs-latn-ba | Bosnian (Latin, Bosnia and Herzegovina) | +| fi | Finnish | +| is | Icelandic | +| mk | Macedonian | +| quz-pe | Quechua (Peru) | +| tt | Tatar | +| ca-es-valencia | Catalan (Valencian) | +| fil-ph | Filipino (Philippines) | +| it | Italian | +| ml | Malayalam | +| ro | Romanian | +| ug | Uyghur | +| ca | Catalan | +| fr-ca | French (Canada) | +| ja | Japanese | +| mr | Marathi | +| ru | Russian | +| uk | Ukrainian | +| cs | Czech | +| fr | French | +| ka | Georgian | +| ms | Malay | +| sk | Slovak | +| ur | Urdu | +| cy-gb | Welsh (UK) | +| ga-ie | Irish (Ireland) | +| kk | Kazakh | +| mt-mt | Maltese (Malta) | +| sl | Slovenian | +| uz-latn-uz | Uzbek (Latin, Uzbekistan) | +| da | Danish | +| gd | Scottish Gaelic | +| km-kh | Khmer (Cambodia) | +| nb-no | Norwegian (Bokmål) | +| sq | Albanian | +| vi | Vietnamese | +| de | German | +| gl | Galician | +| kn | Kannada | +| ne-np | Nepali (Nepal) | +| sr-cyrl-ba | Serbian (Cyrillic, Bosnia and Herzegovina)| +| zh-cn | Chinese (Simplified) | +| el | Greek | +| gu | Gujarati | +| ko | Korean | +| nl | Dutch | +| sr-cyrl-rs | Serbian (Cyrillic, Serbia) | +| zh-tw | Chinese (Traditional) | diff --git a/docs/embedded/development/declarative-agent/spe-da.md b/docs/embedded/development/declarative-agent/spe-da.md new file mode 100644 index 000000000..3e7026291 --- /dev/null +++ b/docs/embedded/development/declarative-agent/spe-da.md @@ -0,0 +1,72 @@ +--- +title: SharePoint Embedded agent +description: Details usage and billing for SharePoint Embedded agents +ms.date: 05/12/2025 +ms.localizationpriority: high +--- + +# Overview + +> [!NOTE] +> +> SharePoint Embedded agent is currently in private preview. Stay tuned for latest API and SDK changes on this page. +> +> SPE agent consumption-based model will be available in May 2025! Starting May 1st, standard billing model will be available to all private preview customers and this rollout is expected to complete by May 15th. This means that starting May 15th, to use SPE agent within an SPE application, you will need to use standard Container Type. SPE Agent interactions, including those from Microsoft 365 Copilot license users, will be billed to the Azure subscription associated with your Container Type. Learn more about [SharePoint Embedded billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement). +> +> We are actively working on enabling Direct-to-Customer billing model for SPE agent. Stay tuned for more announcements. + +SharePoint Embedded agent enables you to add AI capabilities into your application through a simple SDK. This chat control offers the following features: + +- Reason over documents in SharePoint Embedded containers using RAG. +- Developers can configure the application code to limit the search scope to files, folders, and containers. +- Developers can customize and configure chat control including starter prompts, suggested prompts, colors and more. + +Watch this demo to learn more about how to configure this functionality. + +> [!VIDEO https://www.youtube.com/embed/30i7q09EtQo?si=MwLtbrGKnzv7a6My] + +## Why use SharePoint Embedded agent + +SharePoint Embedded agent harness a semantic index to power Retrieval-Augmented Generation (RAG), securely referencing your data within the Microsoft 365 boundary at query time. This ensures accurate, grounded AI responses while reducing reliance on broad knowledge models. A pay-as-you-go billing model is on the horizon, aligning costs with actual usage. + +![Diagram illustrating SPE agent is AI ready](../../images/speco-apparch.png) + +## How to use SharePoint Embedded agent + +### How to build your agent + +Currently, you can use the React SDK library written in TypeScript to build your application. Plans to support additional frameworks and environments will be announced. The SDK is configured with the containerId instance of your containerType, as well as the authorization and authentication token logic you provide through a callback. It will embed itself as an iFrame into your host application. By default, the iFrame is given a `frame-ancestors` property that prevents it from being embedded by any host until configured. Details are provided below. + +#### SPE TypeScript React Application + +Follow the [quick start guide](../tutorials/spe-da-vscode.md) to get started with a prebuilt sample application. + +### API Documentation + +The SharePoint Embedded React TypeScript NPM Package, available at [here](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/feature/copilot-react-sdk/sharepointembedded-chatembedded-react/docs/index.md), provides the SDK for integrating SharePoint Embedded agent into your client applications. + +## Frequently Asked Questions + +### Is consumption-based billing available for SPE agent? + +Yes, starting May 15th you will need to use standard Container Type to use SPE agent within an SPE application. SharePoint Embedded agent interactions, including those from Microsoft 365 Copilot license users, will be billed to the Azure subscription associated with your Container Type. Learn more about [SharePoint Embedded billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement) + +***Trial Container Types expire after 30 days, for this reason we recommend starting off with Standard Container types. There is no upgrade path from Trial to Standard container types.*** + +### Should I use a standard or trial Container Type? + +Once consumption-based billing is enabled, we will be disabling the use of this feature with Trial Container Types and it will only be enabled on Standard Container Types going forward. Please follow this [guide](../../getting-started/containertypes.md) to get started on creating your Standard Container Type. + +## SharePoint Embedded agent Support + +### Chat Control Feedback Dialog + +If you encounter any issues with the chat control, please use the thumbs up or down feedback buttons to report the problem. This method is preferred for sending feedback because it provides us with telemetry data that helps us diagnose and troubleshoot the issue more effectively. + +When you click the thumbs down button, a feedback dialog will appear. Please include any relevant information in this dialog. + +![SPE agent Feedback Modal preview](../../images/speco-feedbackcombined.png) + +## Advanced Topics Overview + +The [advanced topics](spe-da-adv.md) delve into how SharePoint Embedded agent use a semantic index to facilitate Retrieval-Augmented Generation (RAG), ensuring responses are accurately grounded in your stored content. You’ll also learn how to scope your agent to specific data sources, set up various file formats, and configure locale options to tailor the agent experience. By exploring concepts like grounding, semantic indexing, and RAG workflows, you can optimize your agent’s effectiveness and maintain security within the Microsoft 365 boundary. diff --git a/docs/embedded/concepts/fluid.md b/docs/embedded/development/fluid.md similarity index 89% rename from docs/embedded/concepts/fluid.md rename to docs/embedded/development/fluid.md index 39eb9fcb7..84d879d7f 100644 --- a/docs/embedded/concepts/fluid.md +++ b/docs/embedded/development/fluid.md @@ -1,7 +1,7 @@ --- title: Fluid Framework in SharePoint Embedded Applications description: Details Fluid Integration with SharePoint Embedded Applications -ms.date: 03/06/2024 +ms.date: 05/21/2024 ms.localizationpriority: high --- @@ -19,10 +19,10 @@ Start [building](https://github.com/microsoft/FluidExamples/) in the Fluid [Samp ### Get started with SharePoint Embedded -Try SharePoint Embedded for free by creating a [Trial Container Type](./app-concepts/containertypes.md). +Try SharePoint Embedded for free by creating a container type for [trial purposes](../getting-started/containertypes.md). 1. Set up a free trial [Microsoft 365 tenant](https://www.microsoft.com/microsoft-365/enterprise/microsoft365-plans-and-pricing). Alternatively, you can use an existing tenant if you have admin credentials. -1. Sign into the [SharePoint Embedded Visual Studio Code Extension](.././getting-started/spembedded-for-vscode.md) and follow the steps to create an application and Trial Container Type. +1. Sign into the [SharePoint Embedded Visual Studio Code Extension](../getting-started/spembedded-for-vscode.md) and follow the steps to create an application and container type for trial purposes. ## Prerequisites @@ -32,17 +32,17 @@ To get started building with Fluid Framework, you need: 1. **SharePoint Embedded Application**: Ensure that you register your application in [Microsoft Entra ID](https://entra.microsoft.com/). If you don't have a SharePoint Embedded application, refer to the [earlier section](#get-started-with-sharepoint-embedded). 1. **Application (Client) ID**: Obtain the `ClientID` for your SharePoint Embedded Application. 1. **Container Type Information**: - - Identify the `ContainerTypeId` associated with your app’s Container Type. + - Identify the `ContainerTypeId` associated with your app’s container type. 1. **Containers**: - - Make sure you have *at least* one Container created of the same Container Type linked to your SharePoint Embedded Application. + - Make sure you have *at least* one container created of the same container type linked to your SharePoint Embedded Application. ## Get started with Fluid ### Access App information -You need the `ClientID` from your application and the `ContainerTypeId` associated with the Containers created on that application. +You need the `ClientID` from your application and the `ContainerTypeId` associated with the containers created on that application. -The `ClientID` is essential for acquiring the correct access tokens when working with Fluid Framework and documents. The `ContainerTypeId` is necessary for accessing Containers associated with your SharePoint Embedded application. +The `ClientID` is essential for acquiring the correct access tokens when working with Fluid Framework and documents. The `ContainerTypeId` is necessary for accessing containers associated with your SharePoint Embedded application. If you used the [Visual Studio Code Extension](../getting-started/spembedded-for-vscode.md), you can [export](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode#export-postman-environment) your Postman Environment to easily view your both your `ContainerTypeId` and `ClientID`. diff --git a/docs/embedded/concepts/app-concepts/limits-calling.md b/docs/embedded/development/limits-calling.md similarity index 78% rename from docs/embedded/concepts/app-concepts/limits-calling.md rename to docs/embedded/development/limits-calling.md index 4b1f46d6c..feb4fd012 100644 --- a/docs/embedded/concepts/app-concepts/limits-calling.md +++ b/docs/embedded/development/limits-calling.md @@ -1,7 +1,7 @@ --- title: Limits and Calling Patterns -description: This article explains the limits of SharePoint Embedded -ms.date: 11/28/2023 +description: This article explains the limits of SharePoint Embedded. +ms.date: 05/21/2024 ms.localizationpriority: high --- @@ -10,18 +10,18 @@ ms.localizationpriority: high This document explains the limits of SharePoint Embedded during public preview. > [!NOTE] -> These are preview limits which are subject to change. +> These are preview limits that are subject to change. ## Size limits -The following table defines the size limits of containers" +The following table defines the size limits of containers: | Resource | Limit | | --------------------------------------------------------- | ------------------------------------------------------ | -| Container types that a partner tenant can create | 5* | +| Container types that a partner tenant can create | 25* | | Container types that an app can own | 1 | -| Containers of a container type per tenant | 100k* | -| Storage per container type per tenant | 100 TB* | +| Containers of a container type per consuming tenant | 100k* | +| Storage per container type per consuming tenant | 100 TB* | | Files and folders per container | 30M | | Storage per container | 25 TB | | Files and folders with additive permissions per container | 5k | @@ -36,7 +36,7 @@ The following table defines the size limits of containers" ### Patterns and best practices -When applications hit service limits, you'll receive an HTTP status code 429 ("Too many requests"). You might also receive an HTTP status code 503 ("Server Too Busy"). +When applications hit service limits, you receive an HTTP status code 429 ("Too many requests"). You might also receive an HTTP status code 503 ("Server Too Busy"). In general, the following are the best practices to handle throttling: @@ -44,7 +44,7 @@ In general, the following are the best practices to handle throttling: - Avoid request spikes. - Honor the `Retry-After` HTTP header. -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` might result in more throttling. +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` might result in more throttling. ## API rate limits @@ -53,7 +53,7 @@ SharePoint Embedded provides various APIs. Different APIs have different costs d | Resource units per request | Operations | | -------------------------- | -------------------------------------------------------------------------- | | 1 | Single item query, such as get item | -| 2 | Multi item query, such as list children Create, update, delete and upload | +| 2 | Multi-item query, such as list children, create, update, delete, and upload | | 5 | All permission resource operations, including $expand=permissions | > [!NOTE] diff --git a/docs/embedded/development/sharing-and-perm.md b/docs/embedded/development/sharing-and-perm.md new file mode 100644 index 000000000..4c63f4843 --- /dev/null +++ b/docs/embedded/development/sharing-and-perm.md @@ -0,0 +1,55 @@ +--- +title: Sharing and Permissions +description: Outlines Permission Model for SharePoint Embedded +ms.date: 03/03/2025 +ms.localizationpriority: high +--- + +# Sharing and permissions in SharePoint Embedded + +## Additive permissions + +In SharePoint Embedded, content always inherits permissions from its parent hierarchy. While you can't alter this inherited permission structure, you can extend access within a container by applying "additive permissions" to specific files and folders. For instance, if _UserA_ belongs to the Reader role, you can grant the user edit permission to a particular document in that container using Microsoft Graph: + +| Scenario | Microsoft Graph API(s) | Notes | +| :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Grant an additive permission | [POST /drives/{drive-id}/items/{item-id}/invite](/graph/api/driveitem-invite) | The sendInvitation property must always be false. You can't grant additive permissions to the root folder in a container as this is essentially the same as adding a User to a role. You can't use AppOnly permissions. | +| Retrieve permissions | [GET /drives/{drive-id}/items/{item-id}/permissions](/graph/api/permission-get) & [GET /drives/{drive-id}/items/{item-id}/permissions/{perm-id}](/graph/api/permission-get), | | +| Delete additive permissions | [DELETE /drives/{drive-id}/items/{item-id}/permissions/{perm-id}](/graph/api/permission-delete) | You can only delete the additive permission on the drive item where it was originally added. | + +## Role-based sharing setting + +SharePoint Embedded offers a role-based sharing model that allows developers to configure file-sharing permissions based on container permission roles, offering a choice between restrictive and open sharing models. By default, the sharing setting is configured to the open model, permitting unrestricted content sharing by all users. This sharing setting is part of [container type configuration](../getting-started/containertypes.md#configuring-container-types). This configuration can only be set by the application owner's developers. To learn more about container permission roles, refer to [Authentication and Authorization with SharePoint Embedded](auth.md#container-permissions). + +### Restrictive sharing model + +Only container members who are either the Owner or Manager roles are permitted to add new permissions to files. + +### Open sharing model + +Any container members and guests with edit permissions can add new permissions to this file. + +This can be configured using the PowerShell cmdlet [Set-SPOcontainerTypeConfiguration](../administration/developer-admin/dev-admin.md#container-type-configuration-properties) as per this example: + +```powershell +Set-SPOcontainerTypeConfiguration + -containerTypeID + -sharingRestricted $false +``` + +## Sharing configuration setting + +By default, SharePoint Embedded application sharing configuration is the same as the consuming tenant-sharing configuration. For example, if the consuming tenant is configured to disable sharing for guests, then the SharePoint Embedded application is unable to add guests to container roles or grant them additive permissions. + +### Application external sharing override + +For SharePoint Embedded applications, sharing configurations can be adjusted at the application level. Consuming tenant admin can configure permissions that are different than tenant-level sharing settings. For example, if a tenant's sharing setting prohibits sharing with guests, SharePoint Embedded applications can be configured to allow guest sharing. So, all containers within that SharePoint Embedded application would have the ability to include guests or extend another permission, while other SharePoint Embedded applications and SharePoint maintain restricted sharing permissions. + +This setting can only be set by consuming tenant SharePoint Embedded admin, and can be configured using the latest PowerShell cmdlet [Set-SPOApplication](../administration/consuming-tenant-admin/ctapowershell.md#set-sharing-capability-of-applications) as shown in this example: + +```powershell +Set-SPOApplication + -OwningApplicationID + -OverrideTenantSharingCapability $true + -SharingCapability +``` diff --git a/docs/embedded/tutorials/doc-processing-acs.md b/docs/embedded/development/tutorials/doc-processing-acs.md similarity index 92% rename from docs/embedded/tutorials/doc-processing-acs.md rename to docs/embedded/development/tutorials/doc-processing-acs.md index a101d4ec4..2d450bf9e 100644 --- a/docs/embedded/tutorials/doc-processing-acs.md +++ b/docs/embedded/development/tutorials/doc-processing-acs.md @@ -1,7 +1,7 @@ --- title: Document Processing with Azure Cognitive Services description: Enabling document processing with Azure Cognitive Services. -ms.date: 02/26/2024 +ms.date: 03/03/2025 ms.localizationpriority: high --- @@ -17,14 +17,14 @@ To set up automatic AI processing with your current SharePoint application upon 1. Get the delta changes of the container. You're currently able to get the notification whenever there's any change in our container and will now get the files that are added or updated. 1. Call Azure Cognitive Services’s Document Intelligence service API. You'll need to create an Azure AI resource to use the API to extract the fields from an image and get the extracted files. You might store them as shown in this tutorial or you might process them as you like. -![document processing schema](../images/Document-Processing.png) +![document processing schema](../../images/Document-Processing.png) > [!TIP] > To learn more about the Microsoft Graph APIs used in this tutorial, see [Track changes for a Drive](/graph/api/driveitem-delta), [Get a DriveItem resource](/graph/api/driveitem-get), and [Upload or replace the contents of a DriveItem](/graph/api/driveitem-put-content). ## Get the delta changes of a container -Open **GraphProvider.ts** and implement the method `getDriveChanges` to get the list of changed items. +Open **GraphProvider.ts** and implement the method `getDriveChanges` to get the list of changed items: ```typescript public static async getDriveChanges(driveId: string): Promise { @@ -57,7 +57,7 @@ public static async getDriveChanges(driveId: string): Promise { } ``` -Implement the method `getDriveItem` to fetch a file from a container. +Implement the method `getDriveItem` to fetch a file from a container: ```typescript public static async getDriveItem(driveId: string, itemId: string): Promise { @@ -65,7 +65,7 @@ public static async getDriveItem(driveId: string, itemId: string): Promise } ``` -Create a new file **ReceiptProcessor.ts** and implement a method `processDrive`. +Create a new file **ReceiptProcessor.ts** and implement a method `processDrive`: ```typescript export abstract class ReceiptProcessor { @@ -104,7 +104,7 @@ To use the Azure Cognitive Services Document Intelligence APIs, you need to crea After this step, you should have an endpoint and a key ready to use. -Now open **ReceiptProcessor.ts** to create method `dac` to store the Azure Cognitive Services credentials. +Now open **ReceiptProcessor.ts** to create method `dac` to store the Azure Cognitive Services credentials: ```typescript private static dac = new DocumentAnalysisClient( @@ -131,7 +131,7 @@ private static async getDriveItemStream(url: string): Promise { } ``` -Create method `analyzeReceiptStream` to get the OCR fields through Azure Cognitive Services processing. Here we're taking the `prebuilt-invoice` model, but other models can be chosen. +Create method `analyzeReceiptStream` to get the OCR fields through Azure Cognitive Services processing. Here we're taking the `prebuilt-invoice` model, but other models can be chosen: ```typescript private static async analyzeReceiptStream(stream: Readable): Promise { @@ -151,7 +151,7 @@ private static async analyzeReceiptStream(stream: Readable): Promise { } ``` -Create method `removeUnwantedFields` to remove the undesirable fields in Azure Cognitive Services’s response. +Create a method `removeUnwantedFields` to remove the undesirable fields in Azure Cognitive Services’s response: ```typescript private static removeUnwantedFields(fields: any) { @@ -176,4 +176,4 @@ public static async addDriveItem(driveId: string, parentId: any, fileName: strin Now, restart the demo app and set up the tunneling using ngrok and delta change subscription on the container again. -If you add/update any file (supported formats: 'JPEG', 'JPG', 'PNG', 'BMP', 'TIFF', 'PDF') in this container, you should see a new JSON file created and containing the fields extracted from the file. +If you add/update any file (supported formats: JPEG, JPG, PNG, BMP, TIFF, PDF) in this container, you should see a new JSON file created and containing the fields extracted from the file. diff --git a/docs/embedded/tutorials/launch-experience.md b/docs/embedded/development/tutorials/launch-experience.md similarity index 97% rename from docs/embedded/tutorials/launch-experience.md rename to docs/embedded/development/tutorials/launch-experience.md index bda2b7703..e0b92344d 100644 --- a/docs/embedded/tutorials/launch-experience.md +++ b/docs/embedded/development/tutorials/launch-experience.md @@ -1,7 +1,7 @@ --- title: Configure Default Launch Experience for your Office Files description: Configure Default Launch Experience for your Office Files -ms.date: 11/28/2023 +ms.date: 05/21/2024 ms.localizationpriority: high --- @@ -45,7 +45,7 @@ To open your files directly in the Office desktop clients, you need to create an :"|""|" ``` -Use the following table to replace the segments above: +Use the following table to replace the preceding segments: - **scheme-name**: the name of the application, for example: *ms-excel* - **command-name**: diff --git a/docs/embedded/tutorials/metadata.md b/docs/embedded/development/tutorials/metadata.md similarity index 97% rename from docs/embedded/tutorials/metadata.md rename to docs/embedded/development/tutorials/metadata.md index bed4cc4d1..1973c22b9 100644 --- a/docs/embedded/tutorials/metadata.md +++ b/docs/embedded/development/tutorials/metadata.md @@ -7,7 +7,7 @@ ms.localizationpriority: high # Using Metadata with SharePoint Embedded Containers -In SharePoint Embedded, columns can be added to [Containers](../concepts/app-concepts/containertypes.md) to address scenarios requiring custom metadata via Microsoft Graph APIs. Content in the container can then set desired values for corresponding metadata. Metadata is schematized and can be queried. Note the APIs to create and manage columns are on the container instances level – an application is responsible for defining and managing the columns across its containers. +In SharePoint Embedded, columns can be added to [Containers](../../getting-started/containertypes.md) to address scenarios requiring custom metadata via Microsoft Graph APIs. Content in the container can then set desired values for corresponding metadata. Metadata is schematized and can be queried. Note the APIs to create and manage columns are on the container instances level – an application is responsible for defining and managing the columns across its containers. ## Authorization and Authentication @@ -471,4 +471,4 @@ Content-type: application/json {"name": "c.docx", "size": 391, "listitem/fields/TestField": "33" } ] } -``` +``` \ No newline at end of file diff --git a/docs/embedded/development/tutorials/migrate-abs-to-spe.md b/docs/embedded/development/tutorials/migrate-abs-to-spe.md new file mode 100644 index 000000000..d9994ba3d --- /dev/null +++ b/docs/embedded/development/tutorials/migrate-abs-to-spe.md @@ -0,0 +1,374 @@ +--- +title: Tutorial to Migrate from Azure Blob Storage container to SharePoint Embedded container +description: Tutorial in how to migrate from Azure Blob Storage container to SharePoint Embedded container Using C# +ms.date: 07/31/2024 +ms.localizationpriority: high +--- + +# Tutorial For Migrating Content From Azure Blob Storage Container To SharePoint Embedded Container + +## Purpose + +This tutorial will guide you through migrating content from Azure Blob Storage (ABS) to SharePoint Embedded (SPE) using C#. This is useful for customers who have 500 docs in the blob storage container. + +### Prerequisites + +1. A Microsoft Entra ID application registration. See [register an application](/graph/auth-register-app-v2). +1. Your Microsoft Entra ID tenant has a [Microsoft 365 subscription](/training/m365/). +1. A Microsoft Entra ID tenant. If you don't have a tenant, create a [free Azure account to get a free subscription](https://azure.microsoft.com/free/). +1. An account with at least the Global Administrator or SharePoint Embedded Administrator role. +1. .NET Core SDK [version 8.0.303](https://dotnet.microsoft.com/download/dotnet/8.0) +1. Dotnet environment to run the sample app + + - It can be run on Windows, Linux and macOS + +1. SharePoint Embedded container + + - For more information on how to set up a [SPE container](https://aka.ms/start-spe) + +1. Azure Blob Storage container + + - For more information on how to set up an [ABS container](/azure/storage/blobs/storage-blobs-introduction) + +## Authentication + +### Azure Blob Storage + +1. Credentials - Container-level Shared Access Signature (SAS) URL. +1. Permission - Read and List + +### SharePoint Embedded + +1. An [Azure account](https://portal.azure.com) +1. A SharePoint Tenant where you'll create your containers and its Tenant ID +1. An onboarded application ID (sometimes called client ID) and its corresponding ContainerTypeId +1. Create a new App Registration in [Microsoft Entra ID portal](https://entra.microsoft.com). +1. In the App Registration, add a new Mobile & Console application platform in [Microsoft Entra ID App Registration Authenticate portal](https://entra.microsoft.com) + + ![Screenshot of Microsoft Entra ID application configuration](../../images/app-registration-console-platform.png) + +1. A ContainerType +1. A Container +1. Having the application registered in the consuming tenant (even if the owner of the application is the same as the consuming) +1. Having the containerType registered in the consuming tenant (even if the owner of the CT is the same as the consuming) +1. Consuming tenant user name and password credentials - will be required to authenticate the Microsoft Graph client +1. Permission - "User.Read", "FileStorageContainer.Selected" + +## Migrating Data from Azure Blob Storage container to SharePoint Embedded container + +### Description + +This section provides code snippets on how to accomplish the migration. All the validation has been removed for readability. + +### Connecting to Azure Blob Storage Container + +```c# +_containerClient = new BlobContainerClient(new Uri(_containerLevelSASUrl)); +``` + +### Connecting to SharePoint Embedded + +```c# +string[] _scopes = { "User.Read", "FileStorageContainer.Selected" }; +InteractiveBrowserCredentialOptions interactiveBrowserCredentialOptions = new InteractiveBrowserCredentialOptions() + { + ClientId = clientId, + RedirectUri = new Uri("http://localhost"), + }; +InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveBrowserCredentialOptions); + +_graphClient = new GraphServiceClient(interactiveBrowserCredential, scopes, null); + +// Will open up a browser to provide your consuming tenant admin credentials +var user = await _graphClient.Me.GetAsync(); +``` + +### Getting the blob list + +```c# +var blobs = new List(); +await foreach (var blobItem in _containerClient.GetBlobsAsync()) +{ + blobs.Add(blobItem.Name); +} +return blobs; +``` + +### Thread pooling + +```c# +private CountdownEvent _countdown; + +// This is how the thread pool knows how many files are being migrated +_countdown = new CountdownEvent(blobs.Count); +``` + +### FileStructure + +```c# +public class FileStructure +{ + public string blobName { get; set; } + public string parentFolderId { get; set; } +} +``` + +### Traverse blob list + +```c# +// It creates a new folder in the destination. The name of the folder is the blob's container name. +// root means it is the root of the document library. +// If you want to copy it to another drive item, you can put the drive item ID here. +containerFolder = await _graphClient.CreateFolder(_containerName, "root"); + +// Traverse the blob list +foreach (var blobName in fileList) +{ + FileStructure fs = new FileStructure() { blobName = blobName }; + + // This function parses the flat file into the folder hierarchy and creates the folder structure in the destination. It will retrieve the parentFolderId that the file should be copied to. + // If you are going to copy it to root you can comment this line out. The parentFolderId will be containerFolder.Id + fs.parentFolderId = TraverseBlobName(fs, containerFolder.Id) + + // This is where the thread pool happens. + // It takes in a callback function and an Object parameter. + ThreadPool.QueueUserWorkItem(MigrateFile, fs); +} + +// Call so the program doesn't end, it waits for all the files to be processed +_countdown.Wait(); +``` + +### Traverse blob name + +```c# +// Parse for folder path not including the file name and put it in an array +var pathSegments = filePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); +string[] directoriesParts = pathSegments.Take(pathSegments.Length - 1).ToArray(); + +// Traverse the folder listing and create 1 folder at a time +string relativePath = _containerName; +string newFolderId = parentFolderId; +foreach (string folderName in directoriesParts) +{ + string newPath = relativePath + _separator + folderName; + ... + + DriveItem subFolder = await _graphClient.CheckIfItemExists(folderName, newFolderId); + if (subFolder == null) + { + subFolder = await _graphClient.CreateFolder(folderName, newFolderId); + ... + } + newFolderId = subFolder.Id; + + relativePath = newPath; +} + +return newFolderId; +``` + +### Check if the item exists + +```c# +var item = await _graphClient.Drives[_containerId].Items[parentFolderId].ItemWithPath(itemPath).GetAsync(); +``` + +### Create folder + +```c# +var folder = new DriveItem +{ + Name = folderName, + Folder = new Folder(), + AdditionalData = new Dictionary() + { + { "@microsoft.graph.conflictBehavior", "fail" } + } +}; +var createdFolder = await _graphClient.Drives[_containerId].Items[parentFolderId].Children.PostAsync(folder); +``` + +### Migrate File + +```c# +// The parameter must be of type Object. +internal async void MigrateFile(Object stateInfo) +{ + var fileStructure = (FileStructure)stateInfo; + + // Check if the file exists in the destination. If it exists + // - don't upload + // - check if the file is newer in the source than the destination - then upload + ... + + // Migrate the file + // This is where you download the blob as a stream from abs (code below) + ... + + // Then upload the stream to SPE (code below) + ... + + // Signal the countdown event that a file has been migrated + _countdown.Signal(); + + return; +} +``` + +### Downloading From The Blob From ABS As A Stream + +```c# +BlobClient blobClient = _containerClient.GetBlobClient(blobName); + +MemoryStream memoryStream = new MemoryStream(); +await blobClient.DownloadToAsync(memoryStream); +memoryStream.Position = 0; // Reset the stream position to the beginning +``` + +### Uploading The Stream To SPE + +```c# +int _maxChunkSize = 320 * 1024; + +var uploadSessionRequestBody = new CreateUploadSessionPostRequestBody() +{ + AdditionalData = new Dictionary + { + // Fail is set here, so it doesn't get upload again if it already exist + { "@microsoft.graph.conflictBehavior", "fail" } + } +}; + +var uploadSession = await _graphClient.Drives[_containerId] + .Items[parentFolderId] + .ItemWithPath(fileName) + .CreateUploadSession + .PostAsync(uploadSessionRequestBody); + +// The stream is the same stream from the downloading the blob +var fileUploadTask = new LargeFileUploadTask(uploadSession, memoryStream, _maxChunkSize, _graphClient.RequestAdapter); +IProgress progress = new Progress(prog => Console.WriteLine($"Uploaded {fileName} {prog} bytes")); + +// Check uploadResult.UploadSucceeded to see if it is successful +var uploadResult = await fileUploadTask.UploadAsync(progress); +``` + +## Overview Of The Sample App + +### Description + +A sample app called **MigrateABStoSPE** that is designed to migrate files from an Azure Blob Storage (ABS) container to a SharePoint Embedded (SPE) container. The code snippets provided in the **Migrating Data from Azure Blob Storage container to SharePoint Embedded container** are from the sample app. + +It uses Azure.Storage.Blobs and Newtonsoft.Json libraries for working with ABS and JSON data respectively. The app authenticates with both ABS and SPE using client credentials and performs the migration of files. + +### Packages + +1. Microsoft Graph SDK (version 5.56.0) +1. Azure.Identity (version 1.12.0) +1. Azure.Storage.Blobs (version 12.21.0) +1. CommandLineParser (version 2.9.1) +1. Newtonsoft.Json (13.0.3) + +### Out Of Scope + +1. How to deal with files that already exist in the destination - it fails, it doesn't overwrite or rename +1. How to deal with ABS version newer than the destination - it fails because the file already exists in the destination + +### Running The Sample App + +1. Open a terminal or command prompt. +1. Navigate to the directory where the Program.cs file is located. +1. Make sure you have the .NET Core SDK installed on your machine. You can check this by running the command dotnet --version in the terminal. If the command isn't recognized, you can download and install the .NET Core SDK from the official Microsoft website. +1. Once you have confirmed that the .NET Core SDK is installed, you can build the application by running the command `dotnet build`. This will compile the code and generate the necessary binaries. +1. After the build process is complete, you can run the application by executing the command dotnet run followed by the required arguments. The required arguments are: + + - The container-level SAS URL: This is an Azure Blob container level SAS URL. It provides access to the container and its blobs. + - The SPE tenant ID: This is the tenant you're authenticating against in the SPE. + - The SPE client ID: This is the client you're authenticating against in the SPE. + - The SPE container ID: This is the container you're migrating content to in the SPE. For more information on how to get the [container ID](/graph/api/filestorage-list-containers) + - (optional) File name with full path that contains the blob list. + - (optional) File name with full path where to output failed blobs. + +For example, the command to run the application with the required arguments would look like this: + +`dotnet run Program.cs -- --sasurl "" --tenantid "" --clientid "" --containerid "" [ --blobfile "" --outputfile "" ]` + +### Blob and SPE Item Structure + +ABS container doesn't adhere to a folder structure, all the blobs are stored in a flat listing structure. When migrating to SPE, the sample app parses the blob name and creates the folder structure in the container ID provided, with the container name as the top folder. If you're migrating to the root folder, you can ignore this section. + +**Source** + +- Container Name: Container1 + - Blob name: FolderA/blob1.txt + - Blob name: FolderA/FolderB/blob2.txt + - Blob name: FolderA/FolderB/FolderC/blob3.txt + +**Destination** + +- Drive Item folder + - Container1 + - FolderA + - blob1.txt + - FolderB + - blob2.txt + - FolderC + - blob3.txt + +## Handling Errors and Exceptions + +### Common Issues + +1. File already exists in the destination + + - This app checks to see if the file name exists in the destination before it uploads. If there's a file with the exact same name, it will not do the upload again. It will print to stdout a message that the file already exists. To fix it, you can either delete the file from the destination or change the conflictBehavior to replace and not call `CheckIfItemExists` on upload. + +1. The file for the list of blobs isn't found +1. The format for the list of blobs - one blob per line, without quotes around the blob name +1. Not giving enough permission to access the ABS container + + - The minimum permissions are Read and List + +1. Not giving enough permissions to the SPE container + + - The required scope is "User.Read" and "FileStorageContainer.Selected" + - Remember to grant admin consent + - Remember to create the mobile & console platform app + +## Testing the Migration + +### Verification + +1. When the file is queued, it will print to stdout +1. It will print the stats of the total blobs that were processed: total, success, exists in destination, and failed. +1. If there are errors, it will send the failed blob list to a file. The file name will be printed to stdout. It will also, print a command for an incremental re-run. + +## Conclusion + +### Summary + +In this tutorial, we explored how to migrate content from ABS container to SPE container. By following the steps outlined, writing your own app to migrate content should be easy. + +To recap, we: + +1. Authenticated with ABS and Graph +1. How to use a thread pool to queue migration of blob +1. Check if the item exists in destination +1. Retrieved the blob list from ABS container +1. Uploaded the blob to the SPE container + +Understanding these steps is crucial for migrating content from ABS container to SPE container. Now, try implementing these steps in your own projects and see the difference it makes! + +Happy coding! + +### Next Steps + +- For more information about Blob Storage, see [Blob Storage documentation](/azure/storage/blobs/storage-blobs-introduction). +- For more information about SPE, see [SharePoint Embedded documentation](https://aka.ms/start-spe). + +## Appendix + +### Code Repository + +The sample app can be found in the [SharePoint Embedded Samples repository](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/main/Samples/migrate-abs-to-spe). diff --git a/docs/embedded/development/tutorials/spe-da-vscode.md b/docs/embedded/development/tutorials/spe-da-vscode.md new file mode 100644 index 000000000..1a75bcce5 --- /dev/null +++ b/docs/embedded/development/tutorials/spe-da-vscode.md @@ -0,0 +1,355 @@ +--- +title: SharePoint Embedded agent Tutorial +description: Sharepoint Embedded agent tutorial with the SDK and the VS Code SharePoint Embedded Extension +ms.date: 06/10/2025 +ms.localizationpriority: high +--- + +# Tutorial for getting started with SharePoint Embedded agent + +## Prerequisites + +> [!NOTE] +> +> 1. You will need to create a SharePoint Embedded application. If you don't have one, you can easily build a sample application using the instructions [here](#getting-started-using-the-sharepoint-embedded-visual-studio-code-extension). +> 1. You must specify a standard container type 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. 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). +> +> - Set the **CopilotChatEmbeddedHosts** property of your container type configuration to `http://localhost:8080` to be able to work through the quick start below, refer to [the CSP section above for more information](../declarative-agent/spe-da-adv.md#csp-policies). +> - Set the **DiscoverabilityDisabled** property of your container type configuration to `false` so that the agent can find the files in your created container. Refer to the [Discoverability Disabled section above for more information](../declarative-agent/spe-da-adv.md#discoverabilitydisabled). +> - Ensure that Copilot for Microsoft 365 is available for your organization. You have two ways to get a developer environment for Copilot: +> - A sandbox Microsoft 365 tenant with M365 Copilot (available in limited preview through [TAP membership](https://developer.microsoft.com/microsoft-365/tap)). +> - An [eligible Microsoft 365 or Office 365 production environment](/microsoft-365-copilot/extensibility/prerequisites#customers-with-existing-microsoft-365-and-copilot-licenses) with a M365 Copilot license. + +## Getting started using the SharePoint Embedded SDK + +### 1. Install the SDK into your React repo + +```console +# Install the SDK with npm + +npm install "https://download.microsoft.com/download/970802a5-2a7e-44ed-b17d-ad7dc99be312/microsoft-sharepointembedded-copilotchat-react-1.0.9.tgz" +``` + +#### If you want to verify checksums + +In MacOS/Linux + +```console +version="1.0.9"; + +url="https://download.microsoft.com/download/970802a5-2a7e-44ed-b17d-ad7dc99be312/microsoft-sharepointembedded-copilotchat-react-1.0.9.tgz"; + +expected_checksum="3bdf19830ffc098b253cc809f969f50fba236ad95fe85123e7b15c7cf58ecf6b"; + +package_path="microsoft-sharepointembedded-copilotchat-react-$version.tgz"; + +curl -o $package_path $url && [ "$(sha256sum $package_path | awk '{ print $1 }')" == "$expected_checksum" ] && npm install $package_path || { echo "Checksum does not match. Aborting installation."; rm $package_path; } +``` + +In Windows: + +```powershell +$version = "1.0.9" +$url = "https://download.microsoft.com/download/970802a5-2a7e-44ed-b17d-ad7dc99be312/microsoft-sharepointembedded-copilotchat-react-1.0.9.tgz" +$expected_checksum = "3BDF19830FFC098B253CC809F969F50FBA236AD95FE85123E7B15C7CF58ECF6B" +$package_path = "microsoft-sharepointembedded-copilotchat-react-$version.tgz" + +Invoke-WebRequest -Uri $url -OutFile $package_path + +$calculated_checksum = Get-FileHash -Path $package_path -Algorithm SHA256 | Select-Object -ExpandProperty Hash + +if ($calculated_checksum -eq $expected_checksum) { + Write-Output "Checksum matches. Installing the package..." + npm install $package_path +} else { + Write-Output "Checksum does not match. Aborting installation." +} +Remove-Item $package_path +``` + +### 2. Create an `authProvider` object + +This is an object that matches this interface: + +```typescript +export interface IChatEmbeddedApiAuthProvider { + // The hostname for your tenant. Example: https://m365x10735106.sharepoint.com + hostname: string; + // This function will be called when an SPO token is required + // Scope needed: ${hostname}/Container.Selected + getToken(): Promise; +} +``` + +Example usage in app: + +```typescript +// In your app: +import { IChatEmbeddedApiAuthProvider } from '@microsoft/sharepointembedded-copilotchat-react'; + +const authProvider: IChatEmbeddedApiAuthProvider = { + hostname: 'https://m365x10735106.sharepoint.com', + getToken: requestSPOAccessToken, +}; +``` + +Example implementation of `getToken` (you need to customize it): + +```typescript +// +async function requestSPOAccessToken() { + // Use your app's actual msalConfig + const msalConfig = { + auth: { + clientId: "{Your Entra client ID}", // this can likely point to process.env.REACT_APP_CLIENT_ID if you have set it in your .env file + }, + cache: { + // https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/caching.md + /* + Cache Location | Cleared on | Shared between windows/tabs | Redirect flow supported + ----------------- ---------- ------------------------- ------------------------ + sessionStorage | window/tab close | No | Yes + localStorage | browser close | Yes | Yes + memoryStorage | page | refresh/navigation | No | No + */ + cacheLocation: 'localStorage', + storeAuthStateInCookie: false, + }, + }; + + const containerScopes = { + scopes: [`${authProvider.hostname}/Container.Selected`], + redirectUri: '/' + }; + + const pca = new msal.PublicClientApplication(msalConfig); + let containerTokenResponse; + + // Consent FileStorageContainer.Selected scope + try { + // attempt silent acquisition first + containerTokenResponse = await pca.acquireTokenSilent(containerScopes); + return containerTokenResponse.accessToken; + } catch (error) { + if (error instanceof InteractionRequiredAuthError) { + // fallback to interaction when silent call fails + containerTokenResponse = await pca.acquireTokenPopup(containerScopes); + return containerTokenResponse.accessToken; + } + else { + console.log(error); + } + } +} +``` + +### 3. Create a React state to store your `chatApi` in + +```typescript +const [chatApi, setChatApi] = React.useState(null); +``` + +Example: + +```typescript +import React from 'react'; +import { ChatEmbedded, ChatEmbeddedAPI, IChatEmbeddedApiAuthProvider } from '@microsoft/sharepointembedded-copilotchat-react'; + +//... +async function requestSPOAccessToken() { + //... +} + +const authProvider: IChatEmbeddedApiAuthProvider = { + hostname: 'https://m365x10735106.sharepoint.com', + getToken: requestSPOAccessToken, +}; + +function App() { + const [chatApi, setChatApi] = React.useState(null); + + return ( + //... + ); +} +``` + +### 4. Add the `ChatEmbedded` component into your react app + +```typescript +import React from 'react'; +import { ChatEmbedded, ChatEmbeddedAPI, IChatEmbeddedApiAuthProvider } from '@microsoft/sharepointembedded-copilotchat-react'; + +//... +async function requestSPOAccessToken() { + //... +} + +const authProvider: IChatEmbeddedApiAuthProvider = { + hostname: 'https://m365x10735106.sharepoint.com', + getToken: requestSPOAccessToken, +}; + +function App() { + const [chatApi, setChatApi] = React.useState(null); + + return ( + //... + + //... + ); +} +``` + +### 5. Use the `chatApi` object in your state to open the chat and run it + +In the example above, call it this way to open the chat. + +```typescript +await chatApi.openChat(); +``` + +You may choose to pass in launch configurations + +```typescript +import { IconName, IconStyle } from './sdk/types'; + +//... +const zeroQueryPrompts = { + headerText: "This is my Starter Prompt", + promptSuggestionList: [{ + suggestionText: 'Hello', + iconRegular: { name: IconName.ChatBubblesQuestion, style: IconStyle.Regular }, + iconHover: { name: IconName.ChatBubblesQuestion, style: IconStyle.Filled }, + }] +}; + +const launchConfig: ChatLaunchConfig = { + header: 'My Awesome Chat', + zeroQueryPrompts, + suggestedPrompts: ["What are my files?",], + instruction: "Response must be in the tone of a pirate", + locale: "en", +}; + +await chatApi.openChat(launchConfig); +``` + +Full example: + +```typescript +import React from 'react'; +import { ChatEmbedded, ChatEmbeddedAPI, IChatEmbeddedApiAuthProvider } from '@microsoft/sharepointembedded-copilotchat-react'; + +//... +async function requestSPOAccessToken() { + //... +} + +const authProvider: IChatEmbeddedApiAuthProvider = { + hostname: 'https://m365x10735106.sharepoint.com', + getToken: requestSPOAccessToken, +}; + +function App() { + const [chatApi, setChatApi] = React.useState(null); + + React.useEffect(() => { + const openChat = async () => { + if (!chatApi) { + return; + } + + await chatApi.openChat(); + }; + + openChat(); + }, [chatApi]); + + + return ( + //... + setChatApi(api)} + authProvider={authProvider} + containerId={container.id} + style={{ width: 'calc(100% - 4px)', height: 'calc(100vh - 8px)' }} + /> + //... + ); +} +``` + +### 6. Your AI chat should be loaded successfully + +## Getting started using the SharePoint Embedded Visual Studio Code Extension + +### Quick Start + +> [!NOTE] +> When using standard container types with the VS Code extension, [DisableDiscoverability](../declarative-agent/spe-da-adv.md#discoverabilitydisabled) and [Grant admin consent](/entra/identity/enterprise-apps/grant-admin-consent?pivots=portal) features are currently not supported. This will need to be done using the [SPO Admin Powershell](/powershell/sharepoint/sharepoint-online/connect-sharepoint-online). + +1. Follow this guide up to the [Load Sample App section](../../getting-started/spembedded-for-vscode.md#load-sample-app) with the Visual Studio Code Extension +1. Within the extension, right click on the owning application, and select `Run sample apps -> Typescript + React + Azure Functions` + + ![Using the SPE VS Code extension to create a TypeScript React Azure Functions project](../../images/speco-runsampleapp.png) + +1. Allow for the extension to copy and create client secrets + + > [!CAUTION] + > Caution for production environments, storing secrets in plain text poses a security risk. + + ![SPE VS Code notification alerting it will copy app secrets in plain text on local machine](../../images/speco-createappsecret.png) + + If the application does not already have a client secret, the extension will ask to create one for you. + + ![SPE VS Code notification prompting user to allow it to create a secret for the application if it does not exist.](../../images/speco-createclientsecret.png) + +1. Select a folder to host the application, this will clone the following [repository for SharePoint Embedded Samples](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/main/Samples/spe-typescript-react-azurefunction) into the folder + + ![windows File Explorer folder to save project on local machine](../../images/speco-cloneproject.png) + + Next, when prompted, open the folder + + ![VS Code extension with the SPE React Typescript + Azure Functions sample application cloned on local machine and open in VS Code](../../images/speco-vscodeclonedproject.png) + +1. Navigate to `react-client\src\components\ChatSideBar.tsx` and uncomment this section + + ![VS Code file explorer with ChatSideBar.tsx in open window with relevant code to uncomment highlighted](../../images/speco-uncommentchatsidebar.png) + +1. Navigate to `react-client\src\routes\App.tsx` and set the React state of the `showSidebar` variable to `true` + + ![VS Code file explorer with App.tsx open with line of showSidebar variable useState function input changed from false to true to enable showing chat side bar](../../images/speco-setshowsidebartrue.png) + +1. You can follow the instructions of the `README.md` file in the root of the project for further npm commands. Run `npm run start` in the root of the project to start your application with the SPE agent functionality enabled. + + > [!NOTE] + > `npm run start` Should be done in the root folder of the sample project. `\SharePoint-Embedded-Samples\Samples\spe-typescript-react-azurefunction` + + ![VS Code terminal in root folder of SPE Typescript project cloned earlier and npm run start command typed in](../../images/speco-runnpmrunstart.png) + +1. Sign in with a user who has a Microsoft 365 Copilot license enabled. + + ![SPE Typescript App running in Edge with sign in buttons](../../images/speco-reacttypescripthomepage.png) + +1. Navigate to the `containers` page, create one if you do not have any yet + + ![SPE Typescript App running in edge in /containers sub page with modal of user c reatign a container called ContosoCompanyContainer](../../images/speco-createcontosocontainer2.png) + + After it has been created, you will see it here: + + ![SPE Typescript App running in edge with a created container from above ContosoCompanyContainer](../../images/speco-createdcontainer.png) + +1. Click the container and upload your files. Once a container has been created and you have navigated inside it, your agent chat experience will become enabled. + + ![SPE Typescript App running in edge inside a created container page of ContosoCompanyContainer](../../images/speco-spechatenabled.png) + +### Examples + +The [SharePoint Embedded Samples](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/main/Samples/spe-typescript-react-azurefunction) repository has examples for how to use SharePoint Embedded in your custom applications. diff --git a/docs/embedded/tutorials/using-file-preview.md b/docs/embedded/development/tutorials/using-file-preview.md similarity index 99% rename from docs/embedded/tutorials/using-file-preview.md rename to docs/embedded/development/tutorials/using-file-preview.md index 26fa330fb..08c9602a2 100644 --- a/docs/embedded/tutorials/using-file-preview.md +++ b/docs/embedded/development/tutorials/using-file-preview.md @@ -1,7 +1,7 @@ --- title: File Previews description: Preview SharePoint Embedded content -ms.date: 02/14/2024 +ms.date: 05/21/2024 ms.localizationpriority: high --- diff --git a/docs/embedded/tutorials/using-webhooks.md b/docs/embedded/development/tutorials/using-webhooks.md similarity index 86% rename from docs/embedded/tutorials/using-webhooks.md rename to docs/embedded/development/tutorials/using-webhooks.md index 709f45d16..b0511b294 100644 --- a/docs/embedded/tutorials/using-webhooks.md +++ b/docs/embedded/development/tutorials/using-webhooks.md @@ -1,7 +1,7 @@ --- title: Using Webhooks description: Use webhooks with SharePoint Embedded. -ms.date: 02/26/2024 +ms.date: 03/03/2025 ms.localizationpriority: high --- @@ -16,17 +16,17 @@ You'll use webhooks to invoke the Azure Cognitive Services APIs from the applica 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 the purposes of this tutorial, you'll be employing the former by utilizing ngrok and then subscribing to the changes by making a POST call. +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) +![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`. +Open the **index.ts** file and add an endpoint `onReceiptAdded`: ```typescript server.post('/api/onReceiptAdded', async (req, res, next) => { @@ -40,13 +40,13 @@ server.post('/api/onReceiptAdded', async (req, res, next) => { }); ``` -You also need to add the query parser plugin at the top of this file so that it runs at server startup. +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 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. +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'); @@ -74,15 +74,17 @@ export const onReceiptAdded = async (req: Request, res: Response) => { ## Connect to Graph and subscribe to changes -Follow the [documentation](https://ngrok.com/docs/getting-started/) to create a tunnel for your backend server by utilizing ngrok. +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) +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. 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/enable-sharepoint-embedded.md b/docs/embedded/getting-started/enable-sharepoint-embedded.md deleted file mode 100644 index 4ec9cd033..000000000 --- a/docs/embedded/getting-started/enable-sharepoint-embedded.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Enable SharePoint Embedded -description: Steps to Enable SharePoint Embedded for use -ms.date: 11/28/2023 -ms.localizationpriority: high ---- - -# Enable SharePoint Embedded - -During Public Preview, by default, SharePoint Embedded applications won't be enabled for use on the Microsoft 365 tenant. To create or register SharePoint Embedded applications in the tenant, tenant admins must review the terms of service and enable the settings in [SharePoint admin center](https://go.microsoft.com/fwlink/?linkid=2185219). This document explains the steps to enable SharePoint Embedded applications on a Microsoft 365 tenant. - -## Who can enable SharePoint Embedded? - -Users assigned to the SharePoint Administrator role have access to the [SharePoint admin center](https://go.microsoft.com/fwlink/?linkid=2185219) and can enable SharePoint Embedded applications for their tenant. For information about assigning a user, the SharePoint Administrator role, see [Assign admin roles in the Microsoft 365 admin center.](/microsoft-365/admin/add-users/assign-admin-roles). - -Global Administrators in Microsoft 365 can assign users the SharePoint Administrator. The Global Administrator role already has all the permissions of the SharePoint Administrator role. - -## Steps to Enable SharePoint Embedded - -1. Sign in to [SharePoint admin center](https://go.microsoft.com/fwlink/?linkid=2185219) as a SharePoint Administrator or a Global Administrator. -1. In the SharePoint Admin Center, select **Settings** from the left-hand navigation. - - ![Step 2 - Select 'Settings' in the navigation.](../images/SharePointEmbeddedToS-1.jpg) - -1. Select **SharePoint Embedded** app in the settings page. The app will be “disabled” if the tenant admin hasn't enabled the settings before. - - ![Step 3 - Select 'SharePoint Embedded' on the 'Settings' page.](../images/SharePointEmbeddedToS-2.jpg) - -1. In the **SharePoint Embedded** panel, read the [terms of service](../terms-of-service.md) before enabling the application. - - ![Step 4 - Read the Terms of Service.](../images/SharePointEmbeddedToS-3.jpg) - -1. Select the check box and select on the **Enable** button to begin using your SharePoint Embedded application on the tenant. - - ![Step 5 - Enable SharePoint Embedded on the tenant.](../images/SharePointEmbeddedToS-4.jpg) - -Your SharePoint Embedded application is now available for use on your tenant. - -![Confirmation panel after enabling SharePoint Embedded](../images/SharePointEmbeddedToS-5.jpg) - -## Next Steps - -Once SharePoint Embedded is enabled for your organization, developers can start creating a SharePoint Embedded application from the following module: [Microsoft Learning: SharePoint Embedded - building applications](/training/modules/sharepoint-embedded-create-app/). 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 index 2214e8b32..343a842f5 100644 --- a/docs/embedded/getting-started/spembedded-for-vscode.md +++ b/docs/embedded/getting-started/spembedded-for-vscode.md @@ -1,80 +1,176 @@ --- title: SharePoint Embedded for Visual Studio Code description: Installation and getting started with SharePoint Embedded for Visual Studio Code -ms.date: 1/30/2024 +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 with SharePoint Embedded application development. With the extension, developers can: +The SharePoint Embedded Visual Studio Code extension helps developers get started for free with SharePoint Embedded application development. -1. Create and configure Microsoft Entra ID app registrations for use with SharePoint Embedded -1. Create and manage [free trial container types](../concepts/app-concepts/containertypes.md#trial-container-types) -1. Create more guest apps on a [free trial container type](../concepts/app-concepts/containertypes.md#trial-container-types) -1. Load one of the [sample apps](https://github.com/microsoft/SharePoint-Embedded-Samples) and auto-populate its runtime configuration -1. Export Container Type and Microsoft Entra ID app settings to a Postman Environment file for use with the [SharePoint Embedded Postman Collection](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/main/Postman) +> [!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). -## Installing SharePoint Embedded for Visual Studio Code +## Install SharePoint Embedded for Visual Studio Code -To get started with the SharePoint Embedded Visual Studio Code extension, you need to have [Visual Studio Code](https://code.visualstudio.com/) installed on your machine. +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. -Next, you need to install the [SharePoint Embedded Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=SharepointEmbedded.ms-sharepoint-embedded-vscode-extension) from the Visual Studio Marketplace. You can find the extension by searching for "SharePoint Embedded" in the Visual Studio Code Extensions view, or by visiting the previous link. +![SharePoint Embedded VS Extensions](../images/vsx-images/n1downloadvsx.png) -![SharePoint Embedded on Visual Studio Code Marketplace](../images/spe-vscode-marketplace.png) +### Sign in with admin credentials -Once you have installed the extension, you can access it from the Visual Studio Code Activity Bar, where you'll see a new icon for SharePoint Embedded. Clicking on the icon will open the SharePoint Embedded view, where you can perform various tasks related to SharePoint Embedded application development. +To use the extension, you must sign in to a Microsoft 365 tenant with an administrator account. -## Getting Started +![Install](../images/vsx-images/n2vsx-signin.png) -### Sign In +- Authentication opens a new tab in an external browser to grant permissions -To use the extension, you'll need to sign into a Microsoft 365 tenant with an administrator account. + ![authorize and authenticate the extension to your M365 Entra tenant](../images/vsx-images/auth-allow-extension-uri.png) -![Sign in](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/636d45f9-5912-4e2c-9a50-8f5efa472638) +- 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) -If you don't have administrator access to a Microsoft 365 tenant, get your own tenant with the [Microsoft 365 Developer Program](https://developer.microsoft.com/microsoft-365/dev-program). +After successful authorization, select open on the dialog to be redirected to VSCode: -### Create a Free Trial Container Type +![authorization completed in browser now redirecting to visual studio code](../images/vsx-images/auth-redirect.png) -Once you've signed in, the first (and only) thing to do next is to create a [free trial container type](../concepts/app-concepts/containertypes.md#trial-container-types). A free trial container type lets you get started calling SharePoint Embedded APIs and building a proof-of-concept application using SharePoint Embedded. +## Create a container type with a trial configuration -![Create Free Trial Container Type](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/a8186b2b-bdf9-400b-820b-2e6ebe51d393) +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 free trial container types at this time. Paid container types must be made using the SharePoint Online PowerShell Module. +> 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 +## 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. +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) -![Create App](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/944ecf1b-491c-4e5c-b887-73a5d709e9c5) +- 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. -#### Name your Free Trial Container Type +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. -Once you have a Microsoft Entra ID application, the last step is to provide a name for your new free trial container type. +![function api console logs](../images/vsx-images/fn-api-logs.png) -![Name Container Type](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/f465d36e-57e8-472a-9d10-7374a28b24b1) +![client app console logs](../images/vsx-images/client-app-logs.png) -### Load Sample App +Once both applications are running successfully: -With a 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. This allows you to immediately run the sample app on your local machine. +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 -![Load Sample App](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/da40cd67-83b3-4da9-b743-159edd2802fa) +![home-page-for-spe-sample-app](../images/vsx-images/spe-sample-app-home.png) -### Export Postman Environment +> [!IMPORTANT] +> This sample application stores authentication secrets in plain text for development purposes only. Never use this configuration in a production 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 Postman and immediately call the SharePoint Embedded APIs. +### Troubleshooting -![Export Postman Environment](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/a549866d-55e0-4a25-b173-fc532cc7b49e) +If you encounter issues: -![Postman Import](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/06884e97-7a4c-41ea-8c19-c0eecfd2e624) +- **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 -### Add a Guest App to your Free Trial Container Type +## Export Postman Environment -You can use the extension to add one or more guest apps to your existing free trial container type. Guest apps can be used to create different applications that have access to the same set of Containers. For example, you might have one app that delivers your Web experiences, another for mobile experiences, and another for background processing. You can specify both the delegated and application permissions on each guest application you create. +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. -![Guest App Permissions](https://github.com/microsoft/SharePoint-Embedded-VS-Code-Extension/assets/108372230/d3394cf6-b174-4c07-8cca-fe742cade70b) +![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/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/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/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-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/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/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/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/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/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 index 845f9ea81..9f707d52e 100644 --- a/docs/embedded/overview.md +++ b/docs/embedded/overview.md @@ -1,7 +1,7 @@ --- 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: 11/28/2023 +ms.date: 08/17/2024 ms.localizationpriority: high --- @@ -9,19 +9,25 @@ ms.localizationpriority: high 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 installs/registers a SharePoint Embedded application in their Microsoft 365 tenant, SharePoint Embedded creates another SharePoint partition within their tenant. This storage partition doesn't have a user interface but instead, the documents in the partition are only accessible via APIs. This means that all documents will be accessible to the ISV or 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. +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 slightly like 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 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. SharePoint Embedded applications provide the user experience layer for accessing and managing content, using some of the rich content capabilities that Microsoft 365 offers such as: +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 @@ -50,11 +56,17 @@ Microsoft 365 customers have different entitlements related to storage, usage, a 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 pricing for SharePoint Embedded, see [Pricing](./terms-of-service.md). +> 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: -## Getting Started with SharePoint Embedded +- [Free trial: SharePoint Embedded for Visual Studio Code](./getting-started/spembedded-for-vscode.md) -You can get started building on SharePoint Embedded from the following Microsoft Learning modules: +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/adoptions-and-use.md b/docs/embedded/scenarios-and-use-cases.md similarity index 89% rename from docs/embedded/adoptions-and-use.md rename to docs/embedded/scenarios-and-use-cases.md index 0cefd4804..2c199f287 100644 --- a/docs/embedded/adoptions-and-use.md +++ b/docs/embedded/scenarios-and-use-cases.md @@ -1,7 +1,7 @@ --- -title: Adoptions and Use Case Scenarios -description: Adoptions and Use Cases for SharePoint Embedded -ms.date: 11/28/2023 +title: Scenarios and Use Cases +description: Scenarios and Use Cases for SharePoint Embedded +ms.date: 05/21/2024 ms.localizationpriority: high --- @@ -35,7 +35,7 @@ Where your application is enabling a business-critical or time sensitive process ### 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 can 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. +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. diff --git a/docs/embedded/terms-of-service.md b/docs/embedded/terms-of-service.md deleted file mode 100644 index f5f061765..000000000 --- a/docs/embedded/terms-of-service.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: SharePoint Embedded Public Preview Terms and Conditions -description: Public Preview Terms and Conditions -ms.date: 11/28/2023 -ms.localizationpriority: high ---- - -# Microsoft SharePoint Embedded (“SharePoint Embedded”) Paid Public Preview Terms and Conditions - -“Company” means the Enterprise customer that uses these Preview Features. - -**By using Microsoft SharePoint Embedded, you accept these Terms and Conditions and all rights and obligations within. If you do not agree to these Terms and Conditions, DO NOT use SharePoint Embedded.** These Terms and Conditions govern the use of the Microsoft Offering as described below. - -“Feedback” is all suggestions, comments, feedback, ideas, or know how, in any form, that Customer provides to Microsoft. It does not include sales forecasts, financial results, future release scheduled, marketing plans and high-level product plans or feature lists for anticipated products. - -**MICROSOFT OFFERING:** The goal of the Paid SharePoint Embedded Product preview (“Feature Preview”) is to gain insight into a way to provide third party partners and customers a more efficient, performant, secure, reliable, and cost-effective ability to fulfill product requirements for document repository through integration and consumption of an enterprise-grade, compliant document repository service to meet their business needs, by providing native compatibility with and alignment to the privacy and security offerings of M365 including the ability to utilize the native M365 experiences with these documents stored in SharePoint Embedded. SharePoint Embedded creates and manages storage containers where an app can store files and documents as part of their app. - -**FEATURE PREVIEW:** Company agrees that Microsoft may enable the Feature Preview upon acceptance and receipt of Company’s acceptance of these terms. To terminate this agreement during the Preview Period, Company must contact Microsoft at: SharePointEmbedded@microsoft.com. Microsoft may change or discontinue the Feature Preview at any time with or without notice. Microsoft may also choose not to make the Feature Preview generally commercially available. - -**Microsoft will enable SharePoint Embedded that allows developers to:** - -Create a free trial SharePoint Embedded containers to quickly get hands on with feature and explore its capabilities. These free trial containers are not intended to store durable data and are automatically deleted in 30 days. Setup billing using an Azure subscription which allows developers to build durable applications. These storage containers will be charged as per the pricing schedule below. -Prerequisite Requirements to enable SharePoint Embedded pay-as-you-go are: - -1. An Azure subscription with admin access as owner or contributor on the subscription -1. A Microsoft 365 tenancy with either M365 admin access or SharePoint Online admin access -1. An Azure resource group linked to the subscription - -No SLA applies to this Feature Preview. - -**THE FEATURE PREVIEW IS PROVIDED “AS-IS,” “WITH ALL FAULTS,” AND “AS AVAILABLE.”** Microsoft provides no performance guarantee for the Feature Preview (including accompanying URLs provided for embedded or unauthenticated viewing) and Company bears the risk of using it. The Feature Preview is not included in the SLA for Microsoft Syntex and may not be covered by customer support. - -## LICENSE - -If Company provides input, including feedback, Company grants to Microsoft, without charge, the non-exclusive License to make, modify, distribute, or otherwise commercialize the Input as part of any Microsoft offering. - -Company retains all right, title and interest in and to the input. The above license does not extend to any technologies that may also be necessary to make or use any offering or portion thereof that incorporates the input but are not themselves expressly part of the Input (e.g., enabling technologies). - -## PAYMENT TERMS - -SharePoint Embedded uses pay-as-you-go (PAYG) billing through an Azure subscription. Billing is determined by how much data in GB you store in SharePoint Embedded, transactions used to modify and data that is egressed while using application built on SharePoint Embedded. Company will be able to view this usage as meter events through the Azure subscription it chooses. - -SharePoint Embedded Feature Preview pricing is as follows: - -| SharePoint Embedded Service Meters | Meter Unit | Price | -| :--------------------------------: | :----------: | :------: | -| Storage | $/GB/Day | $0.00667 | -| Graph API Transactions | $/1 API call | $0.00050 | -| Express Egress | $/GB | $0.12 | - -## TERMINATION FOR NON-PAYMENT - -In case the Company’s Azure subscription goes into an unhealthy stage of deleted, cancelled or suspended, we will prevent creation of containers and container types in SharePoint Embedded until the subscription is back to a healthy state. Company will have 30 days to restore the subscription to an active state. If no action is taken by the Company to bring the subscription back to active state in 30 days, we will delete the data from systems after these 30 days. Upon reactivation, Company must also pay for SharePoint Embedded usage for the days the subscription was in an unhealthy state. - -## INFORMATION USE AND DISCLOSURE - -With respect to the SharePoint Embedded, Microsoft may access or disclose information about Company, its account, and the content of its communications in order to: - -1. provide, operate, and improve Microsoft services; -1. comply with the law or respond to lawful requests or legal process; or -1. protect the rights or property of Microsoft or our customers, including the enforcement of Microsoft’s agreements or policies governing the use of the SharePoint Embedded services. - -## LENGTH OF OBLIGATIONS; DISCLOSURE - -**Preview Period.** The Preview Period continues in effect until April 30, 2024, or 30 days after Commercial General Availability of the Preview Feature, whichever is first. Company may terminate their use of the Preview Feature at any time. Terminating use of the Preview Feature will not change any of the rights, licenses granted, or duties made while the Preview Period is in effect. Termination is defined as: - -1. the Company’s termination of use of the Preview Feature and/or -1. the Preview Period ends. - -**Effects upon Termination by Company.** Once terminated by Company, Company will no longer have access to SharePoint Embedded APIs and any SharePoint Embedded containers created as part of preview will be automatically deprovisioned by Microsoft and Company will no longer have access to it. Company is responsible for any data migration out of their SharePoint Embedded containers before termination of this Agreement. - -This Agreement cannot be extended. Microsoft may also choose not to make the Microsoft Offering generally commercially available. - -## REPRESENTATIONS AND LIMITATIONS - -**Feedback.** Company represents that it will not give any Feedback that: - -1. Violates any copyright or trade secret claim or right of any third party; -1. It has reason to believe violates any patent claim or right of any third party; or -1. Is subject to an excluded license. - -**Authority.** Company represents it has all rights and authority necessary to sign this Agreement and grant the rights in it for itself and its affiliates. - -**Limitations.** All information, materials and input are provided “as-is” and Microsoft bears the risk of using them; Company gives no express warranties, guarantees or conditions as to its Input; and to the extent permitted under local law, Company excludes the implied warranties of merchantability, fitness for a particular purpose, title and non-infringement as to its Input. - -## LIMITATIONS ON AND EXCLUSIONS OF REMEDIES AND DAMAGES - -Except as described herein, the only remedy either of us has for claims relating to this Agreement is to terminate it. Neither of us can recover any damages, including direct, consequential, lost profits, special, punitive, indirect or incidental damages from the other. This limitation applies: - -1. To claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. -1. Even if one of us knew or should have known about the possibility of the damages. - -The limitations in this section does not apply to claims arising from or in connection with any infringement, misuse, or misappropriation by one of us of the other’s intellectual property rights. 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/hub-site/create-hub-site-with-powershell.md b/docs/features/hub-site/create-hub-site-with-powershell.md index f418d6ba9..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,13 +1,14 @@ --- title: Create SharePoint hub sites using PowerShell description: Example code for creating a SharePoint hub site by using PowerShell. -ms.date: 08/24/2022 +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. @@ -28,10 +29,10 @@ 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 + Connect-PnPOnline -Url https://contoso-admin.sharepoint.com -Interactive -ClientId ``` 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: diff --git a/docs/features/hub-site/hub-site-o365cli.md b/docs/features/hub-site/hub-site-o365cli.md index b8dd5d991..2ecea1787 100644 --- a/docs/features/hub-site/hub-site-o365cli.md +++ b/docs/features/hub-site/hub-site-o365cli.md @@ -1,7 +1,7 @@ --- 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/28/2022 +ms.date: 06/27/2024 ms.localizationpriority: high --- @@ -17,7 +17,7 @@ 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/) 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-office-365/) to connect to your SharePoint tenant. +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. 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 dc1d61ef8..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,7 +1,7 @@ --- 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. -ms.date: 11/07/2023 +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 ms.localizationpriority: high --- @@ -21,7 +21,10 @@ Does this sound familiar? You're running an application - for example, to scan f ## What is throttling? -SharePoint Online uses throttling to maintain optimal performance and reliability of the SharePoint Online service. Throttling limits the number of API calls or operations within a time window 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. + +> [!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? @@ -29,72 +32,138 @@ When usage limits are exceeded, SharePoint Online throttles any further requests 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. +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 than expected. +- 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. +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. -### User Throttling +### Resource units -Throttling limits the number of calls and operations collectively made by applications on behalf of a user to prevent overuse of resources. +Some limits are measured in terms of API costs. [Microsoft Graph APIs](/graph) have a predetermined resource unit cost per request: -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 view 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. +| 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` | -### Application Throttling +> [!NOTE] +> We reserve the right to change the API resource unit cost. -In addition to throttling by user account, limits are also applied to applications in a tenant. +### User Throttling -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. +Throttling limits the number of calls and operations collectively made by applications on behalf of a user to prevent the overuse of resources. -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. +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. -The table below defines the resource unit limits for an application in a tenant: +| 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 | -| License count | 0 – 1k | 1k – 5k | 5k - 15k | 15k - 50k | 50k+ | -| --------------- | --------- | --------- | --------- | --------- | --------- | -| App 1 minute | 1,200 | 2,400 | 3,600 | 4,800 | 6,000 | -| App daily | 1,200,000 | 2,400,000 | 3,600,000 | 4,800,000 | 6,000,000 | +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary -> [!NOTE] -> We reserve the right to change the resource unit limits. +### Tenant Throttling -In terms of API costs, [Microsoft Graph APIs](/graph) have a predetermined resource unit cost per request: +Some throttling limits are applied at the Tenant level to ensure the operations collectively made do not overuse resources. -| Resource units per request | Operations | -| -------------------------- | ------------------------------------------------------- | -| 1 |
  • Single item query, such as get item
  • Delta with a token | -| 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 | +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). -> [!NOTE] -> We reserve the right to change the API resource unit cost. +| 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 | -Delta with a token is the most efficient way to scan content in SharePoint, and we talk more in details 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. +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary -In [batching](/graph/json-batching), requests in a batch are evaluated individually by resource units. +### Application Throttling + +In addition to throttling by user account, limits are also applied to applications in a tenant. -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. And 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. +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. -Since application limits are in resource units, the actual request rate, such as requests per minute, depends on 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. +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. -Although each application has its own 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. +For multitenant applications: + +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. + +| 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 | + +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary + +### Other Limits + +| 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 | + +> [!NOTE] +> Displayed limits are default values. Microsoft may change these limits at any time. Your experience may vary ## How to handle throttling? 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) +- 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. -As stated earlier, [Microsoft Graph](/graph) is cloud born APIs that have the latest improvements and optimizations. In general, [Microsoft Graph](/graph) consumes less resource than CSOM and REST to achieve the same functionality. Hence, adopting [Microsoft Graph](/graph) can improve application's performance and reduce throttling. +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. -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. +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 @@ -102,11 +171,12 @@ When applications experience throttling, SharePoint Online returns a `Retry-Afte 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. -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 towards usage limits. Honoring the `Retry-After` HTTP header will ensure the shortest delay and reduce wasting quotas in throttled requests. +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. ### RateLimit headers - preview -In addition to the `Retry-After` header in the response of 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 throttle. +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. + - `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. @@ -118,61 +188,67 @@ The `RateLimit` headers are returned on a **best-efforts** basis, so application Below is the list of limits that we support the `RateLimit` headers for. The policies and values are subject to change: | 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. | +|----------------------------|---------------------------|---------------|------------------------------------------------------------------------------------------------------------------| +| 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.| Below are some examples to help you understand the `RateLimit` headers: - 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. -``` -HTTP/1.1 200 Ok -RateLimit-Limit: 1200 -RateLimit-Remaining: 120 -RateLimit-Reset: 5 -``` - -- 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`. -``` -HTTP/1.1 429 Too Many Requests -Retry-After: 31 -RateLimit-Limit: 1200 -RateLimit-Remaining: 0 -RateLimit-Reset: 31 -``` - -- 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. -``` -HTTP/1.1 429 Too Many Requests -Retry-After: 9 -``` + + ``` + HTTP/1.1 200 Ok + RateLimit-Limit: 1200 + RateLimit-Remaining: 120 + RateLimit-Reset: 5 + ``` + +- 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. + + ``` + HTTP/1.1 429 Too Many Requests + Retry-After: 31 + RateLimit-Limit: 1200 + RateLimit-Remaining: 0 + RateLimit-Reset: 31 + ``` + +- 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. + + ``` + HTTP/1.1 429 Too Many Requests + Retry-After: 9 + ``` + 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? +### How to decorate your HTTP traffic? Well-decorated traffic will be prioritized over traffic that isn't properly decorated. What is the definition of undecorated traffic? -- 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. +- 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? -- 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. It is 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. + ## Common throttling scenarios in SharePoint Online @@ -180,52 +256,70 @@ The most common causes of per-user throttling in SharePoint Online are client-si - **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, which attempts to reason over the entirety of data and apply changes to it. + 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 time period. + 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. + - 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 experience throttling. Using SharePoint and OneDrive as an intermediary service between Microsoft 365 and another repository is an example of an unsupported use case. + 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 resource of 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. + 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 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 OneDrive for Business content). +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 the service remains fast and reliable, queries using such permission are throttled at 25 requests per second. The search query will return with 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 similar app-only permission. Making more calls while receiving throttle responses will extend the time it takes for your app to become unthrottled. +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, which 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, which makes many simultaneous queries, check whether some of those requests can be removed without any significant impact to 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](http://sharepoint.com/) start page. People search in Microsoft Search has been optimized for better performance and more relevant results. -2. 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 completed. You may need to consider caching these results if you need them quickly, for example of a page load. -3. Try consolidating the requests into a single query. For example, instead 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`. -4. 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. +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'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/site-collection-app-catalog.md b/docs/general-development/site-collection-app-catalog.md index 221f82e55..a3f65dc78 100644 --- a/docs/general-development/site-collection-app-catalog.md +++ b/docs/general-development/site-collection-app-catalog.md @@ -1,7 +1,7 @@ --- title: Use the site collection app catalog description: Using site collection app catalogs, SharePoint tenant administrators can decentralize the management and scope the deployment of SharePoint add-ins and SharePoint Framework solutions to specific sites. -ms.date: 05/19/2023 +ms.date: 04/23/2025 ms.assetid: fdf7ecb1-9951-475b-b058-3285fba77b68 ms.localizationpriority: high --- @@ -14,29 +14,29 @@ Using site collection app catalogs, SharePoint tenant administrators can decentr ## Why site collection app catalogs -Previously, all add-ins and SharePoint Framework solutions had to be managed centrally in the tenant app catalog. While tenant administrators could delegate the access to other people in the organization, a deployed package was visible on all site collections. SharePoint offered no supported way of deploying add-ins and SharePoint Framework solutions only to specific sites. +Previously, all add-ins and SharePoint Framework solutions had to be managed centrally in the tenant app catalog. While tenant administrators could delegate access to other people in the organization, a deployed package was visible on all site collections. SharePoint offered no supported way of deploying add-ins and SharePoint Framework solutions only to specific sites. -With the introduction of site collection app catalogs, tenant administrators can enable app catalog on the specific sites. Once enabled, site collection administrators can deploy SharePoint add-ins and SharePoint Framework solutions that will be available only in that particular site collection. +With the introduction of site collection app catalogs, tenant administrators can enable the app catalog on specific sites. Once enabled, site collection administrators can deploy SharePoint add-ins and SharePoint Framework solutions that will be available only in that particular site collection. The following schema illustrates using site collection app catalogs: ![Diagram illustrating the concept of site collection app catalog](../images/site-collection-app-catalog-diagram.png) -In your Office 365 tenant you have a tenant app catalog. Solutions deployed to this app catalog, can be installed in any site collection in the tenant. Tenant administrators can choose to enable site collection app catalogs on specific site collections. Solutions deployed to the site collection app catalogs can only be installed in that particular site collection. +In your Office 365 tenant, you have a tenant app catalog. Solutions deployed to this app catalog can be installed in any site collection in the tenant. Tenant administrators can choose to enable site collection app catalogs on specific site collections. Solutions deployed to the site collection app catalogs can only be installed in that particular site collection. ## Supported capabilities ### Support for both SharePoint add-ins and SharePoint Framework packages -In site collection app catalogs, just as in tenant app catalog, you can deploy both SharePoint add-ins and SharePoint Framework solutions (.sppkg). +In site collection app catalogs, just as in tenant app catalogs, you can deploy both SharePoint add-ins and SharePoint Framework solutions (.sppkg). ### Including assets in solution packages -SharePoint Framework solution packages that contain assets, can be deployed to site collection app catalogs. Included assets will be deployed to a preconfigured document library in the same site collection as where the site collection app catalog is located. If the Office 365 Public CDN is configured, assets will be served from the CDN. Otherwise, assets will be served directly from the document library. +SharePoint Framework solution packages that contain assets can be deployed to site collection app catalogs. Included assets will be deployed to a preconfigured document library in the same site collection as where the site collection app catalog is located. If the Office 365 Public CDN is configured, assets will be served from the CDN. Otherwise, assets will be served directly from the document library. ### Tenant-scoped deployment -When deploying SharePoint Framework solutions that support tenant-wide deployment to a site collection app catalog, you will be prompted if you want to make this solution available to all sites in the organization. Despite the wording, if you check this box, the solution will be available immediately **only in the same site collection as where the app catalog is**. Other site collections in your organizations will not be able to use the solution. If you don't check this option, you will have to explicitly install the solution in your site, before you will be able to use it. +When deploying SharePoint Framework solutions that support tenant-wide deployment to a site collection app catalog, you will be prompted if you want to make this solution available to all sites in the organization. Despite the wording, if you check this box, the solution will be available immediately **only in the same site collection as where the app catalog is**. Other site collections in your organization will not be able to use the solution. If you don't check this option, you will have to explicitly install the solution on your site before you will be able to use it. ## Current limitations @@ -47,7 +47,7 @@ You can configure and manage site collection app catalogs using the SharePoint O > [!NOTE] > Before you can manage site collection app catalogs in your tenant, ensure that you have installed [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588) from November 2017 or newer. -Alternatively, you can use the [CLI for Microsoft 365](https://sharepoint.github.io/office365-cli?utm_source=msft_docs&utm_medium=page&utm_campaign=Use+the+site+collection+app+catalog) to manage your SharePoint site collection app catalogs. The CLI for Microsoft 365 is a cross-platform command line interface that can be used on any platform, including Windows, MacOS and Linux. Using [PnP PowerShell](/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets) to [create the app catalog](https://pnp.github.io/powershell/cmdlets/Add-PnPSiteCollectionAppCatalog.html) or [remove the app catalog](https://pnp.github.io/powershell/cmdlets/Remove-PnPSiteCollectionAppCatalog.html) is also an option when using Windows. +Alternatively, you can use the [CLI for Microsoft 365](https://sharepoint.github.io/office365-cli?utm_source=msft_docs&utm_medium=page&utm_campaign=Use+the+site+collection+app+catalog) to manage your SharePoint site collection app catalogs. The CLI for Microsoft 365 is a cross-platform command line interface that can be used on any platform, including Windows, macOS, and Linux. Using [PnP PowerShell](/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets) to [create the app catalog](https://pnp.github.io/powershell/cmdlets/Add-PnPSiteCollectionAppCatalog.html) or [remove the app catalog](https://pnp.github.io/powershell/cmdlets/Remove-PnPSiteCollectionAppCatalog.html) is also an option when using Windows. [!INCLUDE [pnp-powershell](../../includes/snippets/open-source/pnp-powershell.md)] @@ -56,7 +56,7 @@ Alternatively, you can use the [CLI for Microsoft 365](https://sharepoint.github ### Create a site collection app catalog > [!NOTE] -> Before running the following script, connect to your SharePoint Online tenant using the `Connect-SPOService` cmdlet when using the SharePoint Online PowerShell. Also ensure that you have a tenant app catalog created in your tenant (Multi-geo customers will need to create a tenant app catalog for each geo they wish to use a site collection app catalog). If you don't, the cmdlet will fail with the following error: +> Before running the following script, connect to your SharePoint Online tenant using the `Connect-SPOService` cmdlet when using the SharePoint Online PowerShell. Also, ensure that you have a tenant app catalog created in your tenant (Multi-geo customers will need to create a tenant app catalog for each geo they wish to use a site collection app catalog). If you don't, the cmdlet will fail with the following error: > > ```text > Cannot invoke method or retrieve property from null object. Object returned by the @@ -67,12 +67,12 @@ Alternatively, you can use the [CLI for Microsoft 365](https://sharepoint.github > " > ``` > -> Alternatively, if you are using the CLI for Microsoft 365, you must first connect to your Microsoft 365 tenant using the `m365 login` command. With PnP PowerShell you would use `Connect-PnPOnline -Url https://-admin.sharepoint.com -UseWebLogin` to set up the connection. +> Alternatively, if you are using the CLI for Microsoft 365, you must first connect to your Microsoft 365 tenant using the `m365 login` command. With PnP PowerShell you would use `Connect-PnPOnline -Url https://-admin.sharepoint.com -Interactive -ClientId ` (using [a registered Azure AD (Entra ID) application](https://pnp.github.io/powershell/articles/registerapplication.html)) to set up the connection. > [!CAUTION] -> Account used to create App Catalog Site Collection, must be Site Collection Administrators on both the tenant-level App Catalog and the target Site Collection +> The account used to create the App Catalog Site Collection must be a Site Collection Administrator on both the tenant-level App Catalog and the target Site Collection -To create a site collection app catalog, use the `Add-SPOSiteCollectionAppCatalog` cmdlet passing the site collection where the app catalog should be created as the `-Site` parameter. +To create a site collection app catalog, use the `Add-SPOSiteCollectionAppCatalog` cmdlet, passing the site collection where the app catalog should be created as the `-Site` parameter. ```powershell Add-SPOSiteCollectionAppCatalog -Site https://contoso.sharepoint.com/sites/marketing @@ -90,14 +90,14 @@ Alternatively, use the `spo site appcatalog add` command if you are using the CL m365 spo site appcatalog add --siteUrl https://contoso.sharepoint.com/sites/marketing ``` -After executing this script, the **Apps for SharePoint** library will be added to your site collection where you will be able to deploy SharePoint add-ins and SharePoint Framework solutions. +After executing this script, the **Apps for SharePoint** library will be added to your site collection, where you will be able to deploy SharePoint add-ins and SharePoint Framework solutions. ### Disable the site collection app catalog > [!NOTE] -> Before running the following script, connect to your SharePoint Online tenant using the `Connect-SPOService` cmdlet for the SharePoint Online PowerShell, `Connect-PnPOnline -Url https://-admin.sharepoint.com -UseWebLogin` for PnP PowerShell or `m365 login` command for the CLI for Microsoft 365 to connect to your Microsoft 365 tenant. +> Before running the following script, connect to your SharePoint Online tenant using the `Connect-SPOService` cmdlet for the SharePoint Online PowerShell, `Connect-PnPOnline -Url https://-admin.sharepoint.com -Interactive -ClientId ` for PnP PowerShell (using a [registered Azure AD (Entra ID) application](https://pnp.github.io/powershell/articles/registerapplication.html)), or m365 login` command for the CLI for Microsoft 365 to connect to your Microsoft 365 tenant. -To disable the site collection app catalog in your site collection, use the `Remove-SPOSiteCollectionAppCatalog` cmdlet passing the site collection where the app catalog should be disabled as the `-Site` parameter. Alternatively, if you have your site collection's ID, you can use the `Remove-SPOSiteCollectionAppCatalogById` cmdlet instead. +To disable the site collection app catalog in your site collection, use the `Remove-SPOSiteCollectionAppCatalog` cmdle,t passing the site collection where the app catalog should be disabled as the `-Site` parameter. Alternatively, if you have your site collection's ID, you can use the `Remove-SPOSiteCollectionAppCatalogById` cmdlet instead. > [!NOTE] > Despite the naming, the `Remove-SPOSiteCollectionAppCatalog` and `Remove-SPOSiteCollectionAppCatalogById` cmdlets don't remove the site collection app catalog from the site collection. Instead, they disable it so that it's not possible to deploy or use any solutions deployed in it. @@ -118,7 +118,7 @@ Alternatively, use the `spo site appcatalog remove` command if you are using the m365 spo site appcatalog remove --url https://contoso.sharepoint.com/sites/marketing ``` -After executing this script, the **Apps for SharePoint** library will be still visible in your site collection, but you will not be able to deploy or use any solutions deployed in it. +After executing this script, the **Apps for SharePoint** library will still be visible in your site collection, but you will not be able to deploy or use any solutions deployed in it. ![Screenshot illustrating how the app catalog will disallow adding new apps after it has been removed](../images/site-collection-app-catalog-disabled.png) @@ -130,7 +130,7 @@ To list all site collections in the tenant that have the site collection app cat ### Security -Before deploying solutions to site collection app catalogs, site collection administrators should verify that these solutions meet organizational policies. Although solutions installed in site collection app catalogs can only be used in these particular site collections, they can potentially access resources from other sites in the tenant so administrators should ensure that the solutions they are about to deploy work as intended. +Before deploying solutions to site collection app catalogs, site collection administrators should verify that these solutions meet organizational policies. Although solutions installed in site collection app catalogs can only be used in these particular site collections, they can potentially access resources from other sites in the tenant, so administrators should ensure that the solutions they are about to deploy work as intended. ## See also 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/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/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/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/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/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/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/schema/field-element-field.md b/docs/schema/field-element-field.md index f2b9631be..e3b466a1d 100644 --- a/docs/schema/field-element-field.md +++ b/docs/schema/field-element-field.md @@ -227,7 +227,7 @@ The following sections describe attributes, child elements, and parent elements. |**ShowInListSettings**|Optional **Boolean**. **TRUE** to display the column on the page for customizing list settings.| |**ShowInNewForm**|Optional **Boolean**. If **FALSE**, the field does not show up in a **Fields** enumeration when the display mode is set to **New**. Fields with this setting do not show up in the default New Item page for a given list. In particular, this is used to hide fields on the page for uploading documents to the document library.| |**ShowInVersionHistory**|Optional **Boolean**. **TRUE** to display the column on the page for viewing list item versions.| -|**ShowInViewForms**|Optional **Boolean**. **TRUE** to specify that the field is displayed in pages that are used to view list data.| +|**ShowInViewForms**|Optional **Boolean**. **TRUE** to specify that the field is displayed in pages that are used to view list data. This parameter does not apply to modern UI.| |**Sortable**|Optional **Boolean**. **TRUE** if values in the field can be sorted.| |**SourceID**|Optional **Text**. Contains the namespace that defines the field, such as `http://schemas.microsoft.com/sharepoint/v3` or the GUID of the list in which the custom field was created.| |**StaticName**|Optional **Text**. Contains an internal name of the field that might not be unique within a field collection. However, unlike the **Name** attribute, which might be amended to ensure its uniqueness, the value of the **StaticName** attribute is assigned to the field exactly as you have defined it. You can later use this value in code to get a reference to the field by calling the **TryGetFieldByStaticName** method.| diff --git a/docs/solution-guidance/applying-pnp-templates.md b/docs/solution-guidance/applying-pnp-templates.md index 7db81b247..522984e81 100644 --- a/docs/solution-guidance/applying-pnp-templates.md +++ b/docs/solution-guidance/applying-pnp-templates.md @@ -1,7 +1,7 @@ --- title: Applying PnP Templates to SharePoint Sites description: This article explains how to manually provision a look book PnP template using PnP PowerShell. -ms.date: 04/10/2024 +ms.date: 06/17/2024 ms.localizationpriority: high --- @@ -75,7 +75,6 @@ Here follows a brief guidance about the parameters: - **BenefitsSiteTitle**: is the title of the Communication Site provisioned by the Human Resources Hub template. - **BenefitsSiteUrl**: is the server-relative URL of the Communication Site provisioned by the Human Resources Hub template. It can be something like: _/sites/name-of-the-site_. - Here follows a brief guidance about the meaning of the prerequisites: - SharePoint Online Admin: you need to execute the provisioning using a user who is member of the SharePoint Online Administrators group. @@ -93,7 +92,7 @@ In order to execute the actual provisioning, you need to execute a PowerShell cm Download the `.PNP` template file that you want to provision, save it in a local folder, and run the following PowerShell command: ```powershell -Connect-PnPOnline https://-admin.sharepoint.com/ -Interactive +Connect-PnPOnline https://.sharepoint.com/sites/ -Interactive Invoke-PnPTenantTemplate -Path .\your-template-file.pnp -Parameters @{"SiteTitle"="";"SiteUrl"="/sites/"} ``` @@ -108,7 +107,7 @@ Remember to provide a value for all the parameters declared in the above table. Download the `.PNP` template file that you want to provision, save it in a local folder, and run the following PowerShell command: ```powershell -Connect-PnPOnline https://-admin.sharepoint.com/ +Connect-PnPOnline https://.sharepoint.com/sites/ -Interactive Invoke-PnPSiteTemplate -Path .\your-template-file.pnp -Parameters @{"SiteTitle"="";"SiteUrl"="/sites/"} ``` @@ -118,10 +117,10 @@ Remember to provide a value for all the parameters declared in the above table. #### Example script for applying Learning Pathways solution -This is how the PowerShell script would look like for applying the [Learning Pathways solution](/office365/customlearning/), which only has the `SiteUrl` parameter and the pnp file for the Learning Pathways is located in the *c:\temp* folder and you want to target to previously created site with URL of */sites/M365LP*. +This is how the PowerShell script would look for applying the [Learning Pathways solution](/office365/customlearning/), which only has the `SiteUrl` parameter and the pnp file for the Learning Pathways is located in the *c:\temp* folder and you want to target to a previously created site with URL of */sites/M365LP*. ```powershell -Connect-PnPOnline https://-admin.sharepoint.com/ +Connect-PnPOnline https://.sharepoint.com/sites/ Invoke-PnPSiteTemplate -Path c:\temp\M365LP.pnp -Parameters @{"SiteUrl"="/sites/M365LP"} ``` @@ -130,4 +129,4 @@ Invoke-PnPSiteTemplate -Path c:\temp\M365LP.pnp -Parameters @{"SiteUrl"="/sites/ Now that the look book template is provisioned on your tenant, feel free to browse to the site URL that you selected and play with the new site. -In there's any issue, don't hesitate to file an issue in the [PnP Provisioning Service repository on GitHub](https://github.com/SharePoint/sp-provisioning-service/issues). +If there's any issue, don't hesitate to file an issue in the [PnP Provisioning Service repository on GitHub](https://github.com/SharePoint/sp-provisioning-service/issues). diff --git a/docs/solution-guidance/media/apponly/sharepointapponly1new.png b/docs/solution-guidance/media/apponly/sharepointapponly1new.png new file mode 100644 index 000000000..dbe38ffbf Binary files /dev/null and b/docs/solution-guidance/media/apponly/sharepointapponly1new.png differ diff --git a/docs/solution-guidance/multigeo-managedmetadata.md b/docs/solution-guidance/multigeo-managedmetadata.md index 49d6b1c9c..b11e8980e 100644 --- a/docs/solution-guidance/multigeo-managedmetadata.md +++ b/docs/solution-guidance/multigeo-managedmetadata.md @@ -1,7 +1,7 @@ --- title: Manage metadata in a Multi-Geo tenant description: Managed metadata that you define for the default geo location of a Multi-Geo tenant is automatically replicated to the tenant's satellite locations, and is only available to the sites hosted in that geo location. -ms.date: 06/13/2022 +ms.date: 07/02/2025 ms.localizationpriority: medium --- @@ -23,13 +23,14 @@ The following are important points to know about managed metadata in Multi-Geo t - Create term groups, term sets, and terms in the default geo location. This ensures that they are consistently available across all the geo-locations in your tenant. - When term groups, term sets, and terms are replicated across geo-locations, they retain their ID. This allows you to reference term groups, term sets, and terms based on ID, regardless of the geo-location your code is running in. - For term sets and terms to be replicated across geo-locations, they need to be set as Available for Tagging. -- The incremental replication process runs hourly. The full replication job runs every three days. +- The incremental replication process runs hourly. The full replication job runs every seven (7) days. - When you programmatically create a term set in the default geo location, that term set is automatically replicated. You don't have to make any changes to the APIs. - In some cases, you might want a term group, term set, or terms to be available only in a satellite location, for example, a term that relates to a confidential project that applies to a specific geolocation. In that case, you can choose to create the relevant terms in the applicable geo-location. - If you want the term group to be available only in the default location, use the `Set-SPOTenantTaxonomyReplicationParameters` PowerShell cmdlet to explicitly specify which term groups from the default location are replicated. This cmdlet is part of the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588). > [!NOTE] > In a multi-geo scenario, there are protected or special term sets within the term store space that will not be replicated, nor will anything under them be replicated. Those groups are: + > - People > - Search Dictionaries > - System diff --git a/docs/solution-guidance/pnp-provisioning-tenant-templates.md b/docs/solution-guidance/pnp-provisioning-tenant-templates.md index 328f3914f..c6e192677 100644 --- a/docs/solution-guidance/pnp-provisioning-tenant-templates.md +++ b/docs/solution-guidance/pnp-provisioning-tenant-templates.md @@ -11,8 +11,8 @@ Think of Tenant Templates as an extension on top of PnP Provisioning or Site Tem [!INCLUDE [pnp-provisioning-engine](../../includes/snippets/open-source/pnp-provisioning-engine.md)] -> [!NOTE] -> A good resource for tenant templates is the [PnP Provisioning Templates Repository](https://github.com/sharepoint/sp-dev-provisioning-templates) which contains all the templates used in the lookbook service at https://lookbook.microsoft.com. You'll find a tenant folder, and in there several folders, each containing a template. In the subfolders you will find a source folder. In the source folder you'll find a template.xml file which is a tenant template. +> [!NOTE] +> A good resource for tenant templates is the [PnP Provisioning Templates Repository](https://github.com/sharepoint/sp-dev-provisioning-templates) which contains all the templates previously used in the lookbook service (no longer available). You'll find a tenant folder, and in there several folders, each containing a template. In the subfolders you will find a source folder. In the source folder you'll find a template.xml file which is a tenant template. ## The Sequence diff --git a/docs/solution-guidance/pnp-remote-provisioning.md b/docs/solution-guidance/pnp-remote-provisioning.md index ba9f0e577..75a808155 100644 --- a/docs/solution-guidance/pnp-remote-provisioning.md +++ b/docs/solution-guidance/pnp-remote-provisioning.md @@ -1,23 +1,23 @@ --- title: PnP remote provisioning description: Remote provisioning for your Office 365, SharePoint, and SharePoint Online site collections using features of the add-in model. -ms.date: 06/05/2020 +ms.date: 01/13/2025 ms.localizationpriority: high --- # PnP Remote Provisioning -The current recommendation when it comes to provisioning artifacts like sites, lists, content types, pages is to use something called "remote provisioning". In a nutshell, remote provisioning means that you utilize one of the available APIs (SharePoint REST, the SharePoint Client Side Object Model or the Microsoft Graph) to create those artifacts. Your code runs on your own machine or on a separate server. +The current recommendation for provisioning artifacts like sites, lists, content types, and pages is to use "remote provisioning." In a nutshell, remote provisioning means utilizing one of the available APIs (SharePoint REST, the SharePoint Client Side Object Model, or the Microsoft Graph) to create those artifacts. Your code runs on your own machine or on a separate server. [!INCLUDE [pnp-provisioning-engine](../../includes/snippets/open-source/pnp-provisioning-engine.md)] -In order for you to create a repeatable process, with known parameters, the [SharePoint Developer Community](../community/community.md) created an engine, called the PnP Provisioning Engine, which allows you to easily create templates and apply those templates to sites or your tenant. The PnP Provisioning Engine can be called from C# code or by using PnP PowerShell. +To create a repeatable process with known parameters, the [SharePoint Developer Community](../community/community.md) created an engine called the PnP Provisioning Engine. This engine allows you to easily create templates and apply them to sites or your tenant. The PnP Provisioning Engine can be called from C# code or by using PnP PowerShell. See the following resources for more information: ## PnP Remote Provisioning vs Site Designs and Site Scripts -The general recommendation is that if you can provision your artifacts with Site Scripts then you should go for Site Scripts. Keep in mind though that the PnP Provisioning Engine extends beyond the scope of just site collection artifacts and moves into the territory of provisioning Tenant scoped artifacts. +The general recommendation is that if you can provision your artifacts with Site Scripts. The PnP Provisioning Engine extends beyond the scope of site collection artifacts and moves into the territory of provisioning tenant-scoped artifacts. ## PnP remote provisioning resources @@ -26,12 +26,11 @@ The general recommendation is that if you can provision your artifacts with Site |[Introducing the PnP provisioning engine](introducing-the-pnp-provisioning-engine.md)| Introduces the PnP provisioning engine, which was released in April 2015 within the OfficeDev PnP project, and which is updated on a monthly basis in alignment with the release schedule of the Office Dev PnP Core Library.| |[Configuring the PnP provisioning engine](configuring-the-pnp-provisioning-engine.md)|Learn how to configure the engine by using a JSON configuration file. |[The PnP Office Open XML File Format](the-pnp-office-open-xml-file-format.md)|Learn about the .PnP file format, which is an Office Open XML file, and how it is built up. -|[PnP provisioning framework](pnp-provisioning-framework.md)| Get a high-level overview of remote provisioning features available for your Office 365 and SharePoint Online site collections as well as an understanding about why creating sandboxed and full-trust solutions is no longer recommended.| +|[PnP provisioning framework](pnp-provisioning-framework.md)| Get a high-level overview of remote provisioning features available for your Office 365 and SharePoint Online site collections as well as an understanding of why creating sandboxed and full-trust solutions is no longer recommended.| |[PnP provisioning engine and the Core library](pnp-provisioning-engine-and-the-core-library.md)| Take a high-level look at the remote provisioning process, including a closer look at the OfficeDevPnP.Core library.| |[PnP provisioning schema](pnp-provisioning-schema.md)| How to use the XML schema to serialize and save your provisioning templates.| |[Provisioning console application sample](provisioning-console-application-sample.md)| Learn the fundamentals of using the PnP provisioning engine to create and persist, and then apply provisioning templates to new SharePoint site collections.| |[OfficeDevPnP.Core ](https://github.com/SharePoint/PnP-Sites-Core/tree/master/Core)|The Office 365 Developer PnP Core Component is an extension that encapsulates commonly used remote CSOM/REST operations as reusable extension methods to support CSOM provisioning objects.| -|[Inside the PnP provisioning schema (video)](https://channel9.msdn.com/blogs/OfficeDevPnP/Deep-dive-to-PnP-provisioning-engine-schema)|A Microsoft Channel 9 audio/video introduction to the PnP provisioning schema delivered by Paolo Pialorsi.| ## See also diff --git a/docs/solution-guidance/security-apponly-azureacs.md b/docs/solution-guidance/security-apponly-azureacs.md index f4d33a578..176a1901c 100644 --- a/docs/solution-guidance/security-apponly-azureacs.md +++ b/docs/solution-guidance/security-apponly-azureacs.md @@ -21,12 +21,12 @@ For new tenants, apps using an ACS app-only access token is disabled by default. > [!NOTE] > Site collection admin is not able to register add-in with Azure ACS in AppRegNew.aspx by default unless explicitly allowed by the SharePoint tenant admin. For more information, see [Set-SPOTenant](/powershell/module/sharepoint-online/set-spotenant#-siteownermanagelegacyserviceprincipalenabled). -Navigate to a site in your tenant (e.g. https://contoso.sharepoint.com) and then call the appregnew.aspx page (e.g. https://contoso.sharepoint.com/_layouts/15/appregnew.aspx). In this page click on the Generate button to generate a client id and client secret and fill the remaining information like shown in the screen-shot below. +Navigate to a site in your tenant (e.g. https://contoso.sharepoint.com) and then call the appregnew.aspx page (e.g. https://contoso.sharepoint.com/_layouts/15/appregnew.aspx). In this page fill the remaining information like shown in the screen-shot below. -![Create a new Client ID & secret](media/apponly/sharepointapponly1.png) +![Create a new Client ID & secret](media/apponly/sharepointapponly1new.png) > [!IMPORTANT] -> Store the retrieved information (client id and client secret) since you'll need this in the next step! +> After pressing `Create` you'll be presented with a client id and client secret, store the retrieved information (client id and client secret) since you'll need this in the next step! Next step is granting permissions to the newly created principal. Since we're granting tenant scoped permissions this granting can only be done via the appinv.aspx page on the tenant administration site. You can reach this site via `https://contoso-admin.sharepoint.com/_layouts/15/appinv.aspx`. Once the page is loaded add your client id and look up the created principal: diff --git a/docs/sp-add-ins-modernize/from-csom-to-pnp-libraries.md b/docs/sp-add-ins-modernize/from-csom-to-pnp-libraries.md index b2d1c3b58..daa3218c7 100644 --- a/docs/sp-add-ins-modernize/from-csom-to-pnp-libraries.md +++ b/docs/sp-add-ins-modernize/from-csom-to-pnp-libraries.md @@ -155,7 +155,7 @@ The above code relies on interactive and web based login to access a target Shar The code sampleretrieves *Id* and *Title* of a library with title "Documents" and it retrieves the top 10 items in the library, in order to show *Id* and *Title* of those items. Syntax is really close to what you are used to using in CSOM. In fact, you get a *context* object, which is of type *Microsoft.SharePoint.Client.ClientContext* from CSOM, and you use it. However, for example you use the *ExecuteQueryRetryAsync* method, which is actually a .NET extension method provided by PnP Framework, or you use the *GetListByTitle* method, which is yet another extension method provided by PnP Framework. Moreover, in PnP Framework there are plenty of asynchronous methods that allow you to write modern asynchronous code. -In the PnP Framework library there are thousands of extensions methods for the CSOM types to improve code quality, readability, and efficiency. Furhtermore, in the PnP Framework there is also the implementation of the [PnP Provisioning Engine](https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/introducing-the-pnp-provisioning-engine), which is the engine used by many business and by Microsoft itself to automate the provisioning of sites and artifacts. For example, the PnP Provisioning Engine is behind the scenes of the [Microsoft Look Book site](http://lookbook.microsoft.com/), as well as behind the scenes of the provisioning of SPO demo content in Microsoft 365 developers’ tenant. +In the PnP Framework library there are thousands of extensions methods for the CSOM types to improve code quality, readability, and efficiency. Furhtermore, in the PnP Framework there is also the implementation of the [PnP Provisioning Engine](https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/introducing-the-pnp-provisioning-engine), which is the engine used by many business and by Microsoft itself to automate the provisioning of sites and artifacts. Last but not least, the PnP Framework is in the back-end of most of the cmdlets provided by the [PnP PowerShell](https://pnp.github.io/powershell/index.html) module, and provides the basic infrastructure for the [PnP Page Transformation](https://pnp.github.io/pnpcore/using-the-sdk/transformation-getting-started.html) engine of the PnP Modernization Framework. diff --git a/docs/sp-add-ins-modernize/publishing-modern-sharepoint-apps-on-appsource.md b/docs/sp-add-ins-modernize/publishing-modern-sharepoint-apps-on-appsource.md index d5a6bbbf9..d1ece85ee 100644 --- a/docs/sp-add-ins-modernize/publishing-modern-sharepoint-apps-on-appsource.md +++ b/docs/sp-add-ins-modernize/publishing-modern-sharepoint-apps-on-appsource.md @@ -1,54 +1,54 @@ --- title: Publishing modern SharePoint applications on Microsoft AppSource description: Publishing modern SharePoint applications on Microsoft AppSource -ms.date: 08/28/2023 +ms.date: 06/08/2024 ms.localizationpriority: high ms.service: sharepoint --- # Publishing modern SharePoint applications on Microsoft AppSource -In this article you will learn how to publish on the Microsoft 365 Store (via [Microsoft AppSource](https://appsource.microsoft.com/)) a modern solution built with SharePoint Framework. Your SharePoint Framework solution can target SharePoint Online only, or also Microsoft Teams. In the latter case, the application will show up in Microsoft Teams gallery through the SharePoint Online tenant App Catalog. +In this article, you will learn how to publish on the Microsoft 365 Store (via [Microsoft AppSource](https://appsource.microsoft.com/)) a modern solution built with SharePoint Framework. Your SharePoint Framework solution can target SharePoint Online only, or also Microsoft Teams. In the latter case, the application will show up in the Microsoft Teams gallery through the SharePoint Online tenant App Catalog. -If you prefer, you can watch the following video, instead of reading the whole article, which you can still consider as a much more detailed reference. +If you prefer, you can watch the following video, instead of reading the whole article, which you can still consider a much more detailed reference. -[![IMAGE_ALT](https://img.youtube.com/vi/_z-q787tGrQ/0.jpg)](https://youtu.be/_z-q787tGrQ) +> [!VIDEO https://youtu.be/_z-q787tGrQ] ## How to publish an application on the marketplace -First of all, you need to make sure that you are a member of the Microsoft Partner Network (MPN). If you are not a registerd member, you can enroll through the following link: [https://aka.ms/joinmarketplace](https://aka.ms/joinmarketplace). In order to being able to sell your products on the marketplace, you will also need to provide a payout profile, a tax profile, and to compile the billing profile. The process will require a review and approval phase on the Microsoft side. +First of all, you need to make sure that you are a member of the Microsoft Partner Network (MPN). If you are not a registered member, you can enroll through the following link: [https://aka.ms/joinmarketplace](https://aka.ms/joinmarketplace). To be able to sell your products on the marketplace, you will also need to provide a payout profile, and a tax profile, and to compile the billing profile. The process will require a review and approval phase on the Microsoft side. ![The initial step of the Partner enrollment program. You need to provide your email address and follow the registration steps.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-01.png) -Once you are a registered partner, you have to complete the onboarding process for the *"Office Store"* program. Click on the gear icon in the upper right corner of the *"Partner Center"* web site and select *"Account Settings"*. Choose *"Program"* in the menu on the right side of the page and then *"Other Programs"* to see the available programs to enroll. Select the program with name *"Office Store"* and start the enrollment process. +Once you are a registered partner, you have to complete the onboarding process for the *"Office Store"* program. Click on the gear icon in the upper right corner of the *"Partner Center"* website and select *"Account Settings"*. Choose *"Program"* in the menu on the right side of the page and then *"Other Programs"* to see the available programs to enroll. Select the program with the name *"Office Store"* and start the enrollment process. ![The *"Registered programs"* section of the Microsoft *"Partner Center"* with the *"Office Store"* program subscribed and active.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-02.png) -Once yoy will be enrolled in the *"Office Store"* programm (it can take up to 48 hours) you should be able to find the *"Office Store"* program in your Partner Center dashboard, under [*"Account settings"* -> *"Programs"* -> *"Registered programs"*](https://partner.microsoft.com/en-us/dashboard/account/v3/settings/programs). +Once you are enrolled in the *"Office Store"* program (it can take up to 48 hours) you should be able to find the *"Office Store"* program in your Partner Center dashboard, under [*"Account settings"* -> *"Programs"* -> *"Registered programs"*](https://partner.microsoft.com/dashboard/account/v3/settings/programs). -![The *"Registered programs"* section of the Microsoft *"Partner Center"* with the *"Office Store"* program subscribed and active.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-03.png) +![Microsoft Partner Center - Account Settings](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-03.png) -You can now move to the [*"Marketplace"*](https://partner.microsoft.com/en-us/dashboard/marketplace-offers/overview) section of the *"Partner Center"*, which you can find under the *"Home"* page of the *"Partner Center"* web site, and from there you should choose to target the *"Office store"* and create a *"New offer"* of type *"SharePoint solution"*. +You can now move to the [*"Marketplace"*](https://partner.microsoft.com/dashboard/marketplace-offers/overview) section of the *"Partner Center"*, which you can find under the *"Home"* page of the *"Partner Center"* web site, and from there you should choose to target the *"Office store"* and create a *"New offer"* of type *"SharePoint solution"*. ![The *"Office Store"* marketplace. There is a *"+ New offer"* button with a list of types of offers that includes "Office add-in", "SharePoint solution", and "Teams app".](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-04.png) -Provide a name for your application, check that the name is unique and available, associate the product with a publisher and save it. For the sake of making an example, imagine that you are going to publish a solution with name *"Orders App"*, like illustrated in the following screenshot. +Provide a name for your application, check that the name is unique and available, associate the product with a publisher, and save it. For the sake of making an example, imagine that you are going to publish a solution with the name *"Orders App"*, like illustrated in the following screenshot. ![The panel to configure the SharePoint sulution name.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/Publishing-modern-SharePoint-apps-on-AppSource-Partner-Center-05.png) -Now, you are ready to go through the registration steps for your SharePoint solution. Specifically, you have to provide information about the *"Product setup"*. The information include a flag to specify if your product includes in-app purchases or associated services that require an additional purchase. You can also configure a connection to a CRM (Customer Relationship Management) system to send customer leads to. +Now, you are ready to go through the registration steps for your SharePoint solution. Specifically, you have to provide information about the *"Product setup"*. The information includes a flag to specify if your product includes in-app purchases or associated services that require an additional purchase. You can also configure a connection to a CRM (Customer Relationship Management) system to send customer leads to. ![The product configuration step about *"Product setup"*. You can configure in-app purchases and CRM connection.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-06.png) -Then, you can upload the actual packages of your solution, through a dedicate page called *"Packages"*. +Then, you can upload the actual packages of your solution, through a dedicated page called *"Packages"*. ![The product configuration step about *"Packages"*. You can use it to upload the packages of your product.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-07.png) -The next step is the one to define the *"Properties"* of the solution. This includes information about the product category, the target industries, the lagal information like the license contract, a link to the EULA (End User License Agreement), and the documentation link. +The next step is the one to define the *"Properties"* of the solution. This includes information about the product category, the target industries, the legal information like the license contract, a link to the EULA (End User License Agreement), and the documentation link. ![The product configuration step about *"Properties"* that includes product category, industries, legal information, documentation link.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-08.png) -You can now define the *"Marketplace listings"* for your solution. In this section you can define the supported languages. +You can now define the *"Marketplace listings"* for your solution. In this section, you can define the supported languages. ![The product configuration step about *"Marketplace listings"* that allows to define the supported languages.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-09.png) @@ -56,19 +56,19 @@ The next step is the *"Availability"* one, where you can configure the target ma ![The product configuration step about *"Availability"*, where you can define the target markets and the release date.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-10.png) -In case your solution relies on Azure Access Control Service (ACS), you can configure the Client IDs of those applications, including a *"Friendly name"*, an *"App domain"*, an *"App redirect URL"*, and you can eventually generate a *"Client Secret"* through the *"Client IDs"* section. Clearly, for a modern SharePoint Online solutions, you shouldn't rely on Azure ACS but on Azure Active Directory registered applications. +In case your solution relies on Azure Access Control Service (ACS), you can configure the Client IDs of those applications, including a *"Friendly name"*, an *"App domain"*, an *"App redirect URL"*, and you can eventually generate a *"Client Secret"* through the *"Client IDs"* section. Clearly, for modern SharePoint Online solutions, you shouldn't rely on Azure ACS but on Azure Active Directory registered applications. ![The product configuration step about *"Client IDs"*, where you can configure Azure AD applications required by the solution.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-11.png) -It is now time to provide *"Additional Certification Info"* useful to test your solution. Through this step you can provide information useful for testing, screenshot, additional PDF documentation. This information is not shown to customers but used for testing purposes only. +It is now time to provide *"Additional Certification Info"* useful to test your solution. Through this step, you can provide information useful for testing, screenshots, and additional PDF documentation. This information is not shown to customers but is used for testing purposes only. ![The product configuration step about *"Additional Certification Info"*, where you can provide additional technical information to test your solution.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-12.png) -You can now go through a *"Publisher Attestation"*, which is voluntary, that allows you to complete a self-assessment of your app's security, data handling, and compliance practices. +You can now go through a *"Publisher Attestation"*, which is voluntary, and allows you to complete a self-assessment of your app's security, data handling, and compliance practices. ![The product configuration step about *"App Compliance"*, where you can start a voluntary self-assessment of your application.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-13.png) -The last and optional step *"Manage product names"* allows you to reserve additional names for your solution, in case you want to use different names based on the target language, or to change your product's name in the future. +The last and optional step *"Manage product names"* allows you to reserve additional names for your solution, in case you want to use different names based on the target language or to change your product's name in the future. ![The product configuration step about *"Manage product names"*, through which you can reserve additional names for your solution.](../images/add-in-transform/publishing-modern-sharepoint-apps-on-appsource/publishing-modern-sharepoint-apps-on-appsource-partner-center-14.png) @@ -82,29 +82,29 @@ Once you will publish your solution, it will go through a certification process ## Solution Certification -Before submitting the solution through the certification process, it is highly suggested that you validate your application against the validation checklist, so that the app will pass the approval process. You can find the list of validation checks in the document [Prepare your SharePoint Framework application for publishing to the Marketplace](../spfx/publish-to-marketplace-checklist.md). +Before submitting the solution through the certification process, it is highly suggested that you validate your application against the validation checklist so that the app will pass the approval process. You can find the list of validation checks in the document [Prepare your SharePoint Framework application for publishing to the Marketplace](../spfx/publish-to-marketplace-checklist.md). In the checklist, just for the sake of making an example, you will find checks like: -- Use SharePoint Framework v1.11 or newer +- Use the SharePoint Framework v1.11 or newer - Test application in both root and non-root sites - Test application in the required browsers -- The application must only manipulate the DOM element provided through the domElement property -- Don't use names of other Microsoft's products in your solution's name +- The application must only manipulate the DOM element provided through the `domElement` property +- Don't use the names of other Microsoft products in your solution's name - Supporting end users to inject scripts is not allowed - Don't include malicious code - etc. -Your application will go through a certification process, and it is better and time saving for you to validate all the checks before submitting your application. You should also make sure you read, review, and comply with the [Microsoft 365 policies for SharePoint Framework solutions](https://learn.microsoft.com/en-us/legal/marketplace/certification-policies#1170-sharepoint-framework-solutions). +Your application will go through a certification process, and it is better and time-saving for you to validate all the checks before submitting your application. You should also make sure you read, review, and comply with the [Microsoft 365 policies for SharePoint Framework solutions](/legal/marketplace/certification-policies#1170-sharepoint-framework-solutions). Once you've gone through the offer registration process and your solution is certified and validated, your offering will become ready and available on the marketplace on the availability date that you configured. ## Recommended content -You can find additional information about this topic reading the following documents: +You can find additional information about this topic by reading the following documents: * [Prepare your SharePoint Framework application for publishing to the Marketplace](../spfx/publish-to-marketplace-checklist.md) -* [Microsoft 365 policies for SharePoint Framework solutions](https://learn.microsoft.com/en-us/legal/marketplace/certification-policies#1170-sharepoint-framework-solutions) +* [Microsoft 365 policies for SharePoint Framework solutions](/legal/marketplace/certification-policies#1170-sharepoint-framework-solutions) * [Join the Microsoft Marketplace](https://aka.ms/joinmarketplace) -* [Microsoft Business Applications Independent Software Vendor (ISV) Connect Program onboarding guide](https://learn.microsoft.com/en-us/azure/marketplace/business-applications-isv-program) -* [Store step-by-step submission guide](https://learn.microsoft.com/en-us/azure/marketplace/add-in-submission-guide) +* [Microsoft Business Applications Independent Software Vendor (ISV) Connect Program onboarding guide](/azure/marketplace/business-applications-isv-program) +* [Store step-by-step submission guide](/azure/marketplace/add-in-submission-guide) diff --git a/docs/sp-add-ins/add-first-run-logic-to-the-provider-hosted-add-in.md b/docs/sp-add-ins/add-first-run-logic-to-the-provider-hosted-add-in.md index f8b0f8e84..bcda4dce3 100644 --- a/docs/sp-add-ins/add-first-run-logic-to-the-provider-hosted-add-in.md +++ b/docs/sp-add-ins/add-first-run-logic-to-the-provider-hosted-add-in.md @@ -1,6 +1,6 @@ --- title: Add first-run logic to the provider-hosted add-in -description: Include "first run" code in a provider-hosted SharePoint Add-in by creating the basic class for deploying components, adding the basic startup logic, and programmatically deploying a SharePoint list. +description: Include "first run" code in a provider-hosted SharePoint Add-in by creating the basic class for deploying components, adding the basic startup logic, and programmatically deploying a SharePoint list. ms.date: 09/26/2023 ms.localizationpriority: medium --- @@ -8,7 +8,8 @@ ms.localizationpriority: medium [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the eighth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). +This is the eighth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). +[Next steps](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps) > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeFirstRunLogic.sln file. @@ -18,20 +19,17 @@ In this article, you add code to the start page of the Chain Store SharePoint Ad ## Create the basic class for deploying SharePoint components > [!NOTE] -> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: -> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. -> 2. Ensure that all three projects are set to **Start** in the **Action** column. +> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: +> +> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. +> 1. Ensure that all three projects are set to **Start** in the **Action** column. 1. In the **ChainStoreWeb** project in **Solution Explorer**, right-click the **Utilities** folder, and then select **Add** > **Existing Item**. - -2. In **File Explorer**, go to the solution folder, the **ChainStoreWeb** folder, and then open the **Utilities** folder. - -3. Select SharePointComponentDeployer.cs, and then select **Add**. - -4. Open the file SharePointComponentDeployer.cs. It has a static class and two static methods that get and set the add-in's version in the **Tenants** table of the corporate database. We won't discuss these methods because this series of articles is not intended to teach ASP.NET or SQL Server/Azure programming. +1. In **File Explorer**, go to the solution folder, the **ChainStoreWeb** folder, and then open the **Utilities** folder. +1. Select SharePointComponentDeployer.cs, and then select **Add**. +1. Open the file SharePointComponentDeployer.cs. It has a static class and two static methods that get and set the add-in's version in the **Tenants** table of the corporate database. We won't discuss these methods because this series of articles is not intended to teach ASP.NET or SQL Server/Azure programming. +1. Add the following **using** statements to the top of the file. -5. Add the following **using** statements to the top of the file. - ```csharp using System.Web; using System.Linq; @@ -39,7 +37,7 @@ In this article, you add code to the start page of the Chain Store SharePoint Ad using Microsoft.SharePoint.Client; ``` -6. At the top of the `SharePointComponentDeployer` class, add the following two static fields. Both of these are initialized in the **Page_Load** method of the add-in's start page (you add that code in a later step). +1. At the top of the `SharePointComponentDeployer` class, add the following two static fields. Both of these are initialized in the **Page_Load** method of the add-in's start page (you add that code in a later step). ```csharp internal static SharePointContext sPContext; @@ -47,15 +45,14 @@ In this article, you add code to the start page of the Chain Store SharePoint Ad ``` Note the following about this code: - - - The first field holds the `SharePointContext` object that is needed to make CRUD operations on SharePoint. - + + - The first field holds the `SharePointContext` object that is needed to make CRUD operations on SharePoint. - The second field holds the version number of the add-in that is installed on the host web. This value is initially different from the default value (**0000.0000.0000.0000**) that is recorded in the corporate **Tenants** table when the installation handler registers the tenant. For example, the first version of the add-in will be **1.0.0.0**. -7. Create the following static property to hold the version of the add-in that is currently recorded in the corporate **Tenants** table. It uses the two methods that were already in the file to get and set this value. - +1. Create the following static property to hold the version of the add-in that is currently recorded in the corporate **Tenants** table. It uses the two methods that were already in the file to get and set this value. + ```csharp - internal static Version RemoteTenantVersion + internal static Version RemoteTenantVersion { get { @@ -68,17 +65,17 @@ In this article, you add code to the start page of the Chain Store SharePoint Ad } ``` -8. Now create the following `IsDeployed` property. +1. Now create the following `IsDeployed` property. ```csharp - public static bool IsDeployed + public static bool IsDeployed { get { if (RemoteTenantVersion < localVersion) - return false; + return false; else - return true; + return true; } } ``` @@ -86,13 +83,12 @@ In this article, you add code to the start page of the Chain Store SharePoint Ad Note the following about this code: - The **Page_Load** method of the add-in's start page uses the value of this property to determine whether the add-in is running for the first time. A **false** value signals that the add-in has not run before on the current host web, so its components need to be deployed. - - The criterion is whether the version number registered in the **Tenants** table is lower than the version actually installed. The first time the add-in runs, it is lower. Code that you write in a later step sets the version in the **Tenants** table to the same version as is actually installed, so when the add-in runs again, `IsDeployed` returns **true** and the deployment logic does not execute again. - -9. Add the following method to the `SharePointComponentDeployer` class. Note that the last thing the method does is update the registered tenant version in the corporate database (**0000.0000.0000.0000**) to match the actual version of the add-in on the host web (**1.0.0.0**). You will complete this method in a later step. - + +1. Add the following method to the `SharePointComponentDeployer` class. Note that the last thing the method does is update the registered tenant version in the corporate database (**0000.0000.0000.0000**) to match the actual version of the add-in on the host web (**1.0.0.0**). You will complete this method in a later step. + ```csharp - internal static void DeployChainStoreComponentsToHostWeb(HttpRequest request) + internal static void DeployChainStoreComponentsToHostWeb(HttpRequest request) { // TODO4: Deployment code goes here. @@ -101,17 +97,17 @@ In this article, you add code to the start page of the Chain Store SharePoint Ad ``` > [!NOTE] -> You may wonder now why the add-in uses version numbers and a "less than" test to determine the answer to a simple yes/no question: "Is the add-in running for the first time?" We could just as well have a simple string field in the **Tenants** table that is set to *not-yet-run* in the installation handler, and then changed to *already-run-once* by the first-run logic after the SharePoint components are deployed. +> You may wonder now why the add-in uses version numbers and a "less than" test to determine the answer to a simple yes/no question: "Is the add-in running for the first time?" We could just as well have a simple string field in the **Tenants** table that is set to *not-yet-run* in the installation handler, and then changed to *already-run-once* by the first-run logic after the SharePoint components are deployed. > -> For the Chain Store add-in, a simple test would work. However, it is generally a good practice to use version numbers because a production add-in is likely to be updated-in-place in the future; that is, updated after it is already installed. When that time comes, your add-in logic needs to be sensitive to more than the two possibilities *not-yet-run* and *already-run-once*. +> For the Chain Store add-in, a simple test would work. However, it is generally a good practice to use version numbers because a production add-in is likely to be updated-in-place in the future; that is, updated after it is already installed. When that time comes, your add-in logic needs to be sensitive to more than the two possibilities *not-yet-run* and *already-run-once*. > > Suppose, for example, that you want to add an additional list to the host web in the upgrade from version 1.0.0.0 to 2.0.0.0. You could do this in an update event handler, or in first-run-after-update logic. Either way, your deployment logic needs to deploy new components, but it also needs to avoid trying to redeploy components that were deployed in a previous version of the add-in. A version number of 1.0.0.0 signals that the components of version 1.0.0.0 have been deployed, but that the first-run-after-update logic has not yet run. ## Add the basic startup logic -The SharePoint host web needs to tell the remote web application what version of the add-in it has installed. We use a query parameter to do this. +The SharePoint host web needs to tell the remote web application what version of the add-in it has installed. We use a query parameter to do this. -1. Open the AppManifest.xml file in the **ChainStore** project. In the designer, you see the placeholder *{StandardTokens}* as the value of the **Query string** box. Add the string `"&SPAddInVersion=1.0.0.0"` to the end. +1. Open the AppManifest.xml file in the **ChainStore** project. In the designer, you see the placeholder *{StandardTokens}* as the value of the **Query string** box. Add the string `"&SPAddInVersion=1.0.0.0"` to the end. The manifest designer should look similar to the following. *Notice that the version number you pass in the query string has to match the value in the __Version__ box of the designer.* If you ever update the add-in, one of your tasks is to raise these two values and keep them the same. @@ -119,7 +115,7 @@ The SharePoint host web needs to tell the remote web application what version of ![The General tab of the manifest designer. The Version box has the value one zero zero zero. The Query string box says "{StandardTokens}&SPAddInVersion=1.0.0.0"](../images/db71c411-10c5-43d8-bb5e-3388d2f6f7bc.PNG) -2. Open the CorporateDataViewer.aspx.cs file and add the following code to the **Page_Load** method, just under the line that initializes the `spContext` object. +1. Open the CorporateDataViewer.aspx.cs file and add the following code to the **Page_Load** method, just under the line that initializes the `spContext` object. ```csharp SharePointComponentDeployer.sPContext = spContext; @@ -133,22 +129,21 @@ The SharePoint host web needs to tell the remote web application what version of Note the following about this code: - - It begins by setting the two static fields in the static `SharePointComponentDeployer` class. It passes the **SharePointContext** object because the code in the `SharePointComponentDeployer` calls into SharePoint, and it uses the query parameter that you added to set the `localVersion` property. - + - It begins by setting the two static fields in the static `SharePointComponentDeployer` class. It passes the **SharePointContext** object because the code in the `SharePointComponentDeployer` calls into SharePoint, and it uses the query parameter that you added to set the `localVersion` property. - It does nothing if `IsDeployed` is true; that is, if the first-run logic has already run. Otherwise, it calls the deployment method and passes the ASP.NET **Request** object. ## Programmatically deploy a SharePoint list 1. In the SharePointComponentDeployer.cs file, replace the `TODO4` with the following line (you create this method in the next step). - + ```csharp - CreateLocalEmployeesList(); + CreateLocalEmployeesList(); ``` -2. Add the following method to the `SharePointComponentDeployer` class. +1. Add the following method to the `SharePointComponentDeployer` class. ```csharp - private static void CreateLocalEmployeesList() + private static void CreateLocalEmployeesList() { using (var clientContext = sPContext.CreateUserClientContextForSPHost()) { @@ -160,11 +155,11 @@ The SharePoint host web needs to tell the remote web application what version of if (matchingLists.Count() == 0) { - // TODO5: Create the list + // TODO5: Create the list - // TODO6: Rename the Title field on the list + // TODO6: Rename the Title field on the list - // TODO7: Add "Added to Corporate DB" field to the list + // TODO7: Add "Added to Corporate DB" field to the list clientContext.ExecuteQuery(); } @@ -175,103 +170,96 @@ The SharePoint host web needs to tell the remote web application what version of Note the following about this code: - It has two calls of **ExecuteQuery**. The first is needed to determine if the list already exists. The second does the work of creating the list. - - The **ClientContext.LoadQuery** method is similar to the **ClientContext.Load** method except that instead of bringing an entity such as a list down to the client, it brings down the enumerable results of a query. -3. Replace `TODO5` with the following code. +1. Replace `TODO5` with the following code. ```csharp - ListCreationInformation listInfo = new ListCreationInformation(); - listInfo.Title = "Local Employees"; - listInfo.TemplateType = (int)ListTemplateType.GenericList; - listInfo.Url = "Lists/Local Employees"; - List localEmployeesList = clientContext.Web.Lists.Add(listInfo); + ListCreationInformation listInfo = new ListCreationInformation(); + listInfo.Title = "Local Employees"; + listInfo.TemplateType = (int)ListTemplateType.GenericList; + listInfo.Url = "Lists/Local Employees"; + List localEmployeesList = clientContext.Web.Lists.Add(listInfo); ``` Note the following about this code: - The **ListCreationInformation** class is similar to the **ListItemCreationInformation** class that you saw in an earlier article in this series. It is a lightweight class more suitable for sending information from the web application to SharePoint than the full **List** class. - - There are many types of list templates, such as the Tasks type for a "to do" list and the Events type for a calendar. The **Local Employees** list is based on the simplest: the Generic type. - - The **ListCreationInformation.Url** property holds the URL of the list *relative* to the host web. By specifying `"Lists/LocalEmployees"`, the code is setting the full URL of the list to `https://{SharePointDomain}/hongkong/_layouts/15/start.aspx#/Lists/Local%20Employees`. -4. Replace `TODO6` with the following code, which changes the public name of the "Title" field (column) from "Title" to "Name." This is what you did on the **List Settings** page when you created the list manually. - +1. Replace `TODO6` with the following code, which changes the public name of the "Title" field (column) from "Title" to "Name." This is what you did on the **List Settings** page when you created the list manually. + ```csharp - Field field = localEmployeesList.Fields.GetByInternalNameOrTitle("Title"); - field.Title = "Name"; - field.Update(); + Field field = localEmployeesList.Fields.GetByInternalNameOrTitle("Title"); + field.Title = "Name"; + field.Update(); ``` -5. You also manually created a field named **Added to Corporate DB**. To do that programmatically, add the following code in place of `TODO7`. +1. You also manually created a field named **Added to Corporate DB**. To do that programmatically, add the following code in place of `TODO7`. ```csharp - localEmployeesList.Fields.AddFieldAsXml("" - + "FALSE", - true, - AddFieldOptions.DefaultValue); + localEmployeesList.Fields.AddFieldAsXml("" + + "FALSE", + true, + AddFieldOptions.DefaultValue); ``` Note the following about this code: - The key properties of the field are specified with an XML blob. This is a legacy of SharePoint's architecture, where websites, lists, fields, content types, and most other kinds of SharePoint components are defined as XML. In this case, we specify the display name, data type, and default value of the field. - - - The second parameter determines whether the field is visible in the default view of the list. We set it to **true**. - + - The second parameter determines whether the field is visible in the default view of the list. We set it to **true**. - The third parameter determines what content types the field is added to. Passing **DefaultValue** means that it is only added to the list's default content type. +1. Recall that the **Added to Corporate DB** is **No** (that is, false) by default, but the custom ribbon button in the add-in sets it to **Yes** after it adds the employee to the corporate database. This system works best only if users cannot manually change the value of the field. To ensure that they don't, make the field invisible in the forms for creating and editing items on the **Local Employees** list. We do this by adding two more attributes to the first parameter, as shown in the following code. -6. Recall that the **Added to Corporate DB** is **No** (that is, false) by default, but the custom ribbon button in the add-in sets it to **Yes** after it adds the employee to the corporate database. This system works best only if users cannot manually change the value of the field. To ensure that they don't, make the field invisible in the forms for creating and editing items on the **Local Employees** list. We do this by adding two more attributes to the first parameter, as shown in the following code. - ```csharp - localEmployeesList.Fields.AddFieldAsXml("" - + "FALSE", - true, - AddFieldOptions.DefaultValue); + localEmployeesList.Fields.AddFieldAsXml("" + + "FALSE", + true, + AddFieldOptions.DefaultValue); ``` - - -7. The entire `CreateLocalEmployeesList` should now look like the following. + +1. The entire `CreateLocalEmployeesList` should now look like the following. ```csharp - private static void CreateLocalEmployeesList() - { - using (var clientContext = sPContext.CreateUserClientContextForSPHost()) - { - var query = from list in clientContext.Web.Lists - where list.Title == "Local Employees" - select list; - IEnumerable matchingLists = clientContext.LoadQuery(query); - clientContext.ExecuteQuery(); - - if (matchingLists.Count() == 0) - { - ListCreationInformation listInfo = new ListCreationInformation(); - listInfo.Title = "Local Employees"; - listInfo.TemplateType = (int)ListTemplateType.GenericList; - listInfo.Url = "LocalEmployees"; - List localEmployeesList = clientContext.Web.Lists.Add(listInfo); - - Field field = localEmployeesList.Fields.GetByInternalNameOrTitle("Title"); - field.Title = "Name"; - field.Update(); - - localEmployeesList.Fields.AddFieldAsXml("" - + "FALSE", - true, - AddFieldOptions.DefaultValue); - clientContext.ExecuteQuery(); - } - } - } + private static void CreateLocalEmployeesList() + { + using (var clientContext = sPContext.CreateUserClientContextForSPHost()) + { + var query = from list in clientContext.Web.Lists + where list.Title == "Local Employees" + select list; + IEnumerable matchingLists = clientContext.LoadQuery(query); + clientContext.ExecuteQuery(); + + if (matchingLists.Count() == 0) + { + ListCreationInformation listInfo = new ListCreationInformation(); + listInfo.Title = "Local Employees"; + listInfo.TemplateType = (int)ListTemplateType.GenericList; + listInfo.Url = "LocalEmployees"; + List localEmployeesList = clientContext.Web.Lists.Add(listInfo); + + Field field = localEmployeesList.Fields.GetByInternalNameOrTitle("Title"); + field.Title = "Name"; + field.Update(); + + localEmployeesList.Fields.AddFieldAsXml("" + + "FALSE", + true, + AddFieldOptions.DefaultValue); + clientContext.ExecuteQuery(); + } + } + } ``` ## Temporarily remove the custom button from the project @@ -285,49 +273,36 @@ For technical reasons that we'll discuss in the next article, the custom button Because the add-in now adds a list to the host web, not just items to an existing list, we need to escalate the permissions that the add-in requests from Write to Manage: 1. In **Solution Explorer**, open the AppManifest.xml file in the **ChainStore** project. - -2. On the **Permissions** tab, leave the **Scope** value at Web, but in the **Permission** field, select **Manage** from the drop-down. - -3. Save the file. +1. On the **Permissions** tab, leave the **Scope** value at Web, but in the **Permission** field, select **Manage** from the drop-down. +1. Save the file. ## Run the add-in and test the first-run logic -1. Open the **Site Contents** page of the Hong Kong SAR store's website, and then remove the **Local Employees** list. - -2. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. - -3. When the add-in's start page opens, select the **Back to Site** link on the chrome control at the top. +1. Open the **Site Contents** page of the Hong Kong SAR store's website, and then remove the **Local Employees** list. +1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. When the add-in's start page opens, select the **Back to Site** link on the chrome control at the top. +1. Go to the **Site Contents** page. The **Local Employees** list is present because your first-run logic added it. -4. Go to the **Site Contents** page. The **Local Employees** list is present because your first-run logic added it. - > [!NOTE] > If the list is not there or you have other indications that the first-run code is not executing, it may be that the **Tenants** table is not being reverted to an empty state when you select F5. The most common cause of this is that the **ChainCorporateDB** project is no longer set as a startup project in Visual Studio. See the [note near the top of this article](#create-the-basic-class-for-deploying-sharepoint-components) for how to fix this. Also be sure that you've configured the database to be rebuilt as described in [Configure Visual Studio to rebuild the corporate database with each debugging session](give-your-provider-hosted-add-in-the-sharepoint-look-and-feel.md#Rebuild). -5. Open the list and add an item. Note that on the new item form, the **Added to Corporate DB** field is no longer present, so it cannot be manually set. This is true of the edit item form as well. - +1. Open the list and add an item. Note that on the new item form, the **Added to Corporate DB** field is no longer present, so it cannot be manually set. This is true of the edit item form as well. + *Figure 2. New item form for the Local Employees list* ![The new item form for the Local Employees list. The "Added to Corporate DB" field is no longer on the form, only the name field and buttons for OK and Cancel.](../images/3fdc6752-4184-4928-9423-0bc7c0206c62.PNG) -6. Use the browser's back button to go back to the add-in's start page. - -7. Select the gear icon on the chrome control at the top, and then select **Account settings**. +1. Use the browser's back button to go back to the add-in's start page. +1. Select the gear icon on the chrome control at the top, and then select **Account settings**. +1. On the **Account settings** page, select the **Show Add-in Version** button. The version shows as **1.0.0.0** because the first-run logic changed it. -8. On the **Account settings** page, select the **Show Add-in Version** button. The version shows as **1.0.0.0** because the first-run logic changed it. - *Figure 3. Account settings page* ![The Account settings page with the version number of 1.0.0.0.](../images/4c6d82a7-7c40-4190-b7e3-1337275e1e60.PNG) -9. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. - -10. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. +1. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. +1. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. ## Next steps - In the next article, you'll see how to get the custom button for the **Local Employee** ribbon back into the add-in now that the list is being deployed programmatically: [Programmatically deploy a custom button in the provider-hosted add-in](programmatically-deploy-a-custom-button-in-the-provider-hosted-add-in.md). - - - - diff --git a/docs/sp-add-ins/add-ins-and-azure-acs-retirements-faq.md b/docs/sp-add-ins/add-ins-and-azure-acs-retirements-faq.md index ac939fb69..376b97027 100644 --- a/docs/sp-add-ins/add-ins-and-azure-acs-retirements-faq.md +++ b/docs/sp-add-ins/add-ins-and-azure-acs-retirements-faq.md @@ -1,7 +1,7 @@ --- title: SharePoint Add-Ins and Azure ACS retirement FAQ description: Answers frequently asked questions related to the retirements of SharePoint Add-In and Azure ACS in Microsoft 365. -ms.date: 01/02/2024 +ms.date: 04/15/2025 ms.localizationpriority: high ms.service: sharepoint --- @@ -34,10 +34,18 @@ If your SharePoint Hosted Add-In is storing data in its app web, then that's som > [!Important] > It's important you retrieve the data **before** you uninstall the SharePoint Add-In, because the app web is deleted when you uninstall the Add-In. In case you've accidentally deleted the Add-In, you can restore it from the recycle bin, which will also restore the Add-In's app web. +## Can SharePoint Online users still acquire my Add-In from the public marketplace after July 1st? + +Users will still be able to browse your Add-In in the public marketplace (https://appsource.microsoft.com/), but when using the "Get it now" button the SharePoint Online user will see a message stating that Add-Ins are retired with a button that redirects the user to the Add-In vendor's site. Installing an Add-In via the public marketplace will not be possible anymore as of July 1st 2024. + ## Can I still use my Add-In on SharePoint on-premises? SharePoint Add-Ins in SharePoint on-premises are not retired and will continue to work after April 2026 when deployed using a SharePoint on-premises app catalog. But acquiring them from the SharePoint Store/public marketplace will not be possible after April 2026. +## Can I, as Add-In vendor, still update my Add-In? + +Yes, as Add-In vendor you can still submit updated versions of your Add-In via Partner Center as you might need to patch an issue. + ## My Add-In is used for both SharePoint Online and SharePoint on-premises; what do you advise? SharePoint Online is continuously being updated and getting new and updated features, whereas SharePoint on-premises follows a much slower release cadence. This means that on-premises SharePoint doesn't support the latest SharePoint Framework version, or the latest features. If you want to continue to maintain a single codebase, you'll need to use an SPFx version that's also supported for your target SharePoint on-premises environment, which will limit the options for your SharePoint Online solution. An alternative approach is to build and maintain two versions of your SPFx application, one for SharePoint Online and one for SharePoint on-premises, and use shared code where possible to maximize code reuse. @@ -67,6 +75,10 @@ When you're using the classic "Site Contents" page (`_layouts/15/viewlsts.aspx`) No, both CSOM (client-side object model) and JSOM (JavaScript object model) will continue working after Add-Ins and Azure ACS have been fully retired. However, for new applications, and updates to existing applications, we recommend using the Microsoft Graph and SharePoint REST APIs for client-side code. For server-side code the recommendation is to use Microsoft Graph as a first choice. If the functionality you need is not yet available in the Microsoft Graph, then SharePoint REST or SharePoint CSOM can be used. +## When I use appregnew.aspx the created ACS principals show up in Entra + +As of December 2024 we've streamlined the app creation flow and as a result ACS principals created using appregnew.aspx now show are created as "regular" Entra app principal versus previously service principals with `legacyServicePrincipal` property set to `Legacy`. These app principals are detected by the [Microsoft 365 Assessment tool](https://aka.ms/microsoft365assessmenttool), however you need version 1.10.0 to ensure the principal validity is correctly reported. Note, if you want to renew the secret of these principals ensure you're using the right approach as described in [Replace an expiring client secret in a SharePoint Add-in](replace-an-expiring-client-secret-in-a-sharepoint-add-in.md). + ## Do I need to delete Azure ACS principals that are not needed anymore? Azure ACS principals will automatically expire (default lifetime is 2 years) so no action is needed; you can just let the principals expire. If you want to delete the principals after remediation, then follow this guidance: @@ -77,3 +89,7 @@ Azure ACS principals will automatically expire (default lifetime is 2 years) so For principals that have Site, Web or List permissions **and** Tenant permissions, you'll need to follow both procedures described above. A good practice is for admins to turn off Azure ACS app-only access for the entire tenant, having first ensured there is no remaining business relevant Azure ACS usage, as mentioned in the [Azure ACS retirement announcement](https://aka.ms/retirement/acs/support). Doing this will automatically prevent any remaining un-expired principals from working. + +## Can I rely on unpublished offers in Partner Center for managing a multi-tenant Client ID for customers? + +No, offers setup in Partner Center must be published on Microsoft stores before using the client IDs in production. diff --git a/docs/sp-add-ins/add-sharepoint-write-operations-to-the-provider-hosted-add-in.md b/docs/sp-add-ins/add-sharepoint-write-operations-to-the-provider-hosted-add-in.md index f0015d509..66d8feec5 100644 --- a/docs/sp-add-ins/add-sharepoint-write-operations-to-the-provider-hosted-add-in.md +++ b/docs/sp-add-ins/add-sharepoint-write-operations-to-the-provider-hosted-add-in.md @@ -8,7 +8,7 @@ ms.localizationpriority: medium [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the fifth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). +This is the fifth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeSharePointWriteOps.sln file. @@ -22,8 +22,8 @@ Our add-in has a custom ribbon button that adds an employee from the Hong Kong S > [!NOTE] > The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: > -> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. -> 2. Ensure that all three projects are set to **Start** in the **Action** column. +> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. +> 1. Ensure that all three projects are set to **Start** in the **Action** column. 1. In **Solution Explorer**, open the EmployeeAdder.aspx.cs file. 1. Add the following line to the **Page_Load** method between the call of `AddLocalEmployeeToCorpDB` and the call of `Response.Redirect`. In the next step, you create the **SetLocalEmployeeSyncStatus** method. @@ -36,7 +36,7 @@ Our add-in has a custom ribbon button that adds an employee from the Hong Kong S 1. Add the following new method to the `EmployeeAdder` class. ```csharp - private void SetLocalEmployeeSyncStatus() + private void SetLocalEmployeeSyncStatus() { using (var clientContext = spContext.CreateUserClientContextForSPHost()) { @@ -49,11 +49,11 @@ Our add-in has a custom ribbon button that adds an employee from the Hong Kong S } ``` - Note the following about this code: - - - The internal name for the **Added to Corporate DB** field is odd-looking. Internal field names cannot contain spaces, so when a user creates a field with spaces in its display name, SharePoint substitutes the string "_x0020_" for each space when it sets the internal name. This turns "Added to Employee DB" into "Added_x0020_to_x0020_Corporate_x0020_DB". Internal names cannot be more than 32 characters, so the name is truncated to just "Added_x0020_to_x0020_Corporate_x". - - Although the **Added to Corporate DB** column is called a **Yes/No** field in the SharePoint UI, it is really a boolean, so its value is set to **true**, not **Yes**. - - The **Update** method of the **ListItem** class must be called to commit the changes to SharePoint's content database. It is a general, but not quite universal, rule that when you change a property value of an object that is stored in the SharePoint databases, you must call the object's **Update** method. + > NOTE: + > + > - The internal name for the **Added to Corporate DB** field is odd-looking. Internal field names cannot contain spaces, so when a user creates a field with spaces in its display name, SharePoint substitutes the string "_x0020_" for each space when it sets the internal name. This turns "Added to Employee DB" into "Added_x0020_to_x0020_Corporate_x0020_DB". Internal names cannot be more than 32 characters, so the name is truncated to just "Added_x0020_to_x0020_Corporate_x". + > - Although the **Added to Corporate DB** column is called a **Yes/No** field in the SharePoint UI, it is really a boolean, so its value is set to **true**, not **Yes**. + > - The **Update** method of the **ListItem** class must be called to commit the changes to SharePoint's content database. It is a general, but not quite universal, rule that when you change a property value of an object that is stored in the SharePoint databases, you must call the object's **Update** method. ## Request permission to write to the host web list @@ -65,7 +65,7 @@ Because the add-in is now writing to the list as well as reading it, we need to ## Run the add-in and test the button -1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. 1. On the permission form, select **Local Employees** from the list, and then select **Trust it**. 1. When the add-in's start page opens, click **Back to Site** on the chrome control at the top. 1. From the website's home page, go to **Site Contents** > **Local Employees**. The list view page opens. @@ -75,8 +75,8 @@ Because the add-in is now writing to the list as well as reading it, we need to 1. Select the **Add to Corporate DB** button. (You must select an item first.) 1. The page seems to reload because the **Page_Load** method of the EmployeeAdder page redirects back to it. The value of the **Added to Corporate DB** field for the employee changes to **Yes**. - > [!NOTE] - > What prevents a user from manually changing the value **Added to Corporate DB** in a way that makes the list and the corporate database inconsistent? Nothing does at the moment. You'll get the solution to this problem in a later article of this series. + > [!NOTE] + > What prevents a user from manually changing the value **Added to Corporate DB** in a way that makes the list and the corporate database inconsistent? Nothing does at the moment. You'll get the solution to this problem in a later article of this series. 1.To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. 1.Right-click the project in **Solution Explorer** and select **Retract**. @@ -142,44 +142,46 @@ Now you add a function to the add-in that creates an item in the **Expected Ship ``` Note the following about this code: - - A **ListItem** object is not created with a constructor. This is for performance reasons. A **ListItem** object has many properties (with default values). If a constructor is used, the entire object would be included in the XML message that the **ExecuteQuery** method sends to the server. + - A **ListItem** object is not created with a constructor. This is for performance reasons. A **ListItem** object has many properties (with default values). If a constructor is used, the entire object would be included in the XML message that the **ExecuteQuery** method sends to the server. - The **ListItemCreationInformation** object is a lightweight object that only contains the minimal non-default values that the server needs to create a **ListItem** object. It may appear that there is a line that creates a **ListItem** object, but recall that this line only adds some XML markup to a message that is sent to the server. The **ListItem** object is created there on the server. - There is no need to bring the **ListItem** object back down to the client, so there is no call to the **ClientContext.Load** method. - The code does not need to explicitly set the **Arrived** or **Added to Inventory** fields because they have default values of **No**, which is what we want. ## Check for deleted components -Anyone with list owner privileges for a SharePoint list can delete the list. And if the list is deployed to the host web by an add-in, the website owner of the host web can delete it. That may happen if the owner decides to do without the functionality provided by the list. (It can be restored from the SharePoint Recycle Bin if the owner changes his mind.) +Anyone with list owner privileges for a SharePoint list can delete the list. And if the list is deployed to the host web by an add-in, the website owner of the host web can delete it. That may happen if the owner decides to do without the functionality provided by the list. (It can be restored from the SharePoint Recycle Bin if the owner changes his mind.) The **CreateExpectedShipment** method depends on the existence of the **Expected Shipments** list. Suppose a website owner decided to delete the list. Later, when an order is added with the add-in's **Order Form**, the **CreateExpectedShipment** method is called and throws an exception whose message says that there's no **Expected Shipments** list on the SharePoint website. You might want the method to check the `expectedShipmentsList` for nullity before it does anything with it. When you are working with CSOM, you can *not* make this check with a simple structure like this: -`if (expectedShipmentsList != null) { ... }` +``` +if (expectedShipmentsList != null) { ... } +``` -Instead, you need to use a special CSOM class called **ConditionalScope**. The reasons for this are connected to CSOM's batching system, which was mentioned in the previous article in this series (see [Client-side runtime and batching](get-a-quick-overview-of-the-sharepoint-object-model.md#CSOMBatching)). **ConditionalScope** and the batching system are advanced topics that are outside the scope of this getting started series, but you should see MSDN's documentation about them after you have completed this series of tutorials. +Instead, you need to use a special CSOM class called **ConditionalScope**. The reasons for this are connected to CSOM's batching system, which was mentioned in the previous article in this series (see [Client-side runtime and batching](get-a-quick-overview-of-the-sharepoint-object-model.md#client-side-runtime-and-batching)). **ConditionalScope** and the batching system are advanced topics that are outside the scope of this getting started series, but you should see MSDN's documentation about them after you have completed this series of tutorials. An alternative way to check for the existence of a list is as follows: instead of using the **GetByTitle** method to get a reference to the list, you can check to see if a list with the specified name is in the website's "list of lists" with code like the following. ```csharp -var query = from list in clientContext.Web.Lists - where list.Title == "Expected Shipments" - select list; -IEnumerable matchingLists = clientContext.LoadQuery(query); -clientContext.ExecuteQuery(); -if (matchingLists.Count() != 0) -{ - List expectedShipmentsList = matchingLists.Single(); - // Do something with the list. +var query = from list in clientContext.Web.Lists + where list.Title == "Expected Shipments" + select list; +IEnumerable matchingLists = clientContext.LoadQuery(query); +clientContext.ExecuteQuery(); +if (matchingLists.Count() != 0) +{ + List expectedShipmentsList = matchingLists.Single(); + // Do something with the list. } -clientContext.ExecuteQuery(); +clientContext.ExecuteQuery(); ``` -The preceding code has the advantage of allowing you to avoid the complications of the **ConditionalScope** class, and we use exactly this code elsewhere in this series of articles. But there is a disadvantage too: this code requires an extra call of **ExecuteQuery** solely to get the value you want to check in the **if** statement. +The preceding code has the advantage of allowing you to avoid the complications of the **ConditionalScope** class, and we use exactly this code elsewhere in this series of articles. But there is a disadvantage too: this code requires an extra call of **ExecuteQuery** solely to get the value you want to check in the **if** statement. If we use this technique in the **CreateExpectedShipment** method to check for the existence of the list, that method will have two calls of **ExecuteQuery**, each of which makes an HTTP request from the remote web server to SharePoint. These requests are the most time-consuming part of any CSOM method, so it is generally a good practice to minimize them. -We will leave the **CreateExpectedShipment** method as is, but in a production add-in, you need to think about how your code is going to work if a component that it references is deleted. Programmatically restoring the list from the Recycle Bin is one option, but that would annoy users who intentionally decided to delete the list. +We will leave the **CreateExpectedShipment** method as is, but in a production add-in, you need to think about how your code is going to work if a component that it references is deleted. Programmatically restoring the list from the Recycle Bin is one option, but that would annoy users who intentionally decided to delete the list. You should also consider that doing nothing at all to prevent the exception might be the best choice. An exception from SharePoint would alert users that the deletion of the list has broken part of the add-in, which is something the person who deleted it might not have realized. A user can then decide whether to restore the list from the Recycle Bin or do without the part of the add-in functionality that no longer works. @@ -194,12 +196,12 @@ Recall that when an add-in requests Read or Write permission with the scope of L ## Run the add-in and test the item creation -1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. 1. When the add-in's start page opens, select the **Order Form** link at the bottom of the page. 1. Enter some values in the form, and then select **Place Order**. 1. Use the browser's back button to go back to the start page, and then select **Back to Site** on the chrome control at the top. 1. From the home page of the Hong Kong SAR store, go to **Site Contents** and open the **Expected Shipments** list. There is now an item on the list corresponding to the order. The following screenshot is an example. - + *Figure 2. Expected Shipments list with a single item* ![The Expected Shipments list with a single item. The Product and Supplier fields have names. The Quantity field has a number. The two Yes/No fields are both set to "No."](../images/e4285084-d31e-4e79-a469-ddebbc7dfb18.PNG) @@ -208,6 +210,5 @@ Recall that when an add-in requests Read or Write permission with the scope of L 1. Right-click the project in **Solution Explorer** and select **Retract**. ## Next steps - In the next article, you'll learn how to surface the remote Order Form as a web part on a SharePoint page: [Include an add-in part in the provider-hosted add-in](include-an-add-in-part-in-the-provider-hosted-add-in.md). diff --git a/docs/sp-add-ins/get-a-quick-overview-of-the-sharepoint-object-model.md b/docs/sp-add-ins/get-a-quick-overview-of-the-sharepoint-object-model.md index a90a0a96b..0252330bc 100644 --- a/docs/sp-add-ins/get-a-quick-overview-of-the-sharepoint-object-model.md +++ b/docs/sp-add-ins/get-a-quick-overview-of-the-sharepoint-object-model.md @@ -1,67 +1,61 @@ --- title: Get a quick overview of the SharePoint object model -description: Get introduced to the content hierarchy, and client-side runtime and batching. +description: Get introduced to the content hierarchy, and client-side runtime and batching. ms.date: 09/26/2023 ms.localizationpriority: high ms.service: sharepoint --- - - # Get a quick overview of the SharePoint object model [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the fourth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). - +This is the fourth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). + > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeSharePointWriteOps.sln file. -In this article you'll take a brief break from coding to get a quick overview of the SharePoint Client-side Object Model (CSOM). This model is large and well-documented in MSDN with reference topics, "how-to's", and code samples. In this article, we can only provide the tip of the tip of the tip of the iceberg. But even a very short introduction will make much of the code you see in this series a lot less mysterious. +In this article you'll take a brief break from coding to get a quick overview of the SharePoint Client-side Object Model (CSOM). This model is large and well-documented in MSDN with reference topics, "how-to's", and code samples. In this article, we can only provide the tip of the tip of the tip of the iceberg. But even a very short introduction will make much of the code you see in this series a lot less mysterious. ## Content hierarchy The following table shows the hierarchy of content in SharePoint and the CSOM classes that represent them. Each of these entities has children of the type just under it. - -|**Entity**|**Class**|**Remarks**| -|:-----|:-----|:-----| -|SharePoint on-premises farm or SharePoint Online subscription (also called a tenant)||There is only limited programmatic access to this level in CSOM. There is no Farm or Subscription or Tenant class, for example. (SharePoint's server-side object model, which cannot be used in add-ins, enables programmatic access to these entities.)| -|site collection|**Site**|A collection of websites that are grouped together for mainly administrative reasons and to house SharePoint components, such as branded master pages or custom security groups, that can be applied to all the child websites. All websites belong to some site collection.| -|website|**Web**|A set of pages and SharePoint components. Can have subwebsites.| -|list|**List**|Document libraries and other kinds of file libraries are also at this level. A document library is a special kind of list in which each row includes an attached document, and the other columns are data about the document, such as its author, when it was last edited, and who has it checked out. | -|list item|**ListItem**|A row in a list—that is, a list item—with particular values in the fields of the row. Also has a type. See next row. | -|list item|**Content Type**|The type of a list item. These are represented by the **ContentType** class. Each is basically a set of columns and metadata. The simplest is the built-in **Item** content type. All other content types are derived from **Item**. SharePoint includes many built-in content types, such as Event and Announcement. | -|column|**Field**|A **Field** object includes not only information about the underlying data type, but also information about how the data is formatted and rendered on forms, such as the forms for creating, displaying, and editing specific list items.| +| **Entity** | **Class** | **Remarks** | +| :----------------------------------------------------------------------------------- | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| SharePoint on-premises farm or SharePoint Online subscription (also called a tenant) | | There is only limited programmatic access to this level in CSOM. There is no Farm or Subscription or Tenant class, for example. (SharePoint's server-side object model, which cannot be used in add-ins, enables programmatic access to these entities.) | +| site collection | **Site** | A collection of websites that are grouped together for mainly administrative reasons and to house SharePoint components, such as branded master pages or custom security groups, that can be applied to all the child websites. All websites belong to some site collection. | +| website | **Web** | A set of pages and SharePoint components. Can have subwebsites. | +| list | **List** | Document libraries and other kinds of file libraries are also at this level. A document library is a special kind of list in which each row includes an attached document, and the other columns are data about the document, such as its author, when it was last edited, and who has it checked out. | +| list item | **ListItem** | A row in a list—that is, a list item—with particular values in the fields of the row. Also has a type. See next row. | +| list item | **Content Type** | The type of a list item. These are represented by the **ContentType** class. Each is basically a set of columns and metadata. The simplest is the built-in **Item** content type. All other content types are derived from **Item**. SharePoint includes many built-in content types, such as Event and Announcement. | +| column | **Field** | A **Field** object includes not only information about the underlying data type, but also information about how the data is formatted and rendered on forms, such as the forms for creating, displaying, and editing specific list items. | -You can programmatically create custom lists, content types, column types, and list items. +You can programmatically create custom lists, content types, column types, and list items. In addition to content, the CSOM gives you access to users, groups, roles and permissions, taxonomy, search, and more. - ## Client-side runtime and batching -CSOM uses a batching system. Chunks of managed code are converted into XML and sent to the server in a single HTTP request. For every command, a corresponding server object model call is made, and the server returns a response to the client in JavaScript Object Notation (JSON) format. +CSOM uses a batching system. Chunks of managed code are converted into XML and sent to the server in a single HTTP request. For every command, a corresponding server object model call is made, and the server returns a response to the client in JavaScript Object Notation (JSON) format. -SharePoint code on a client begins by retrieving a client context object that represents the current request context, including the identity of the SharePoint website (and its parent site collection), and through this context you can obtain access to CSOM objects. The following is the basic structure that you will see again and again. +SharePoint code on a client begins by retrieving a client context object that represents the current request context, including the identity of the SharePoint website (and its parent site collection), and through this context you can obtain access to CSOM objects. The following is the basic structure that you will see again and again. ```csharp - using (var clientContext = spContext.CreateUserClientContextForSPHost()) - { - // CRUD operation or query code goes here. +using (var clientContext = spContext.CreateUserClientContextForSPHost()) +{ + // CRUD operation or query code goes here. - clientContext.ExecuteQuery(); - } + clientContext.ExecuteQuery(); +} ``` Note the following about this code: - The `spContext` object is of the type **SharePointContext** and is defined in the SharePointContext.cs (or .vb) file that is generated by the Office Developer Tools for Visual Studio. This file can be modified, but it is not often that you need to do so. For most SharePoint Add-in projects, this file and the TokenHelper.cs (or .vb) file, which is also generated by the tools, effectively function as extensions of CSOM itself. - - The `clientContext` object is the CSOM type **ClientContext**. - - The **ExecuteQuery** method bundles up the CRUD operation code in an XML message that it sends to the SharePoint server. There it is translated into equivalent server-side object model code and executed. -There was an example of this pattern in the previous article of this series, in the `GetLocalEmployeeName` method shown here. +There was an example of this pattern in the previous article of this series, in the `GetLocalEmployeeName` method shown here. ```csharp private string GetLocalEmployeeName() @@ -82,14 +76,8 @@ private string GetLocalEmployeeName() Note the following about this method: - The first two lines in the **using** block appear to get references to the list and the list item object. But actually when these lines execute in the SharePoint client-side runtime, they are simply translated into an XML format. The **ExecuteQuery** method sends that XML to the server. +- The **Load** method adds something extra to the message: it tells the server to send the specified object down to the client. The **ExecuteQuery** method receives this object (as JSON) and uses it to initialize the client-side `localEmployee` variable. Subsequent client-side code then references that **ListItem** object and its members. As you can see, the next line references the value of the item's `"Title"` field. This line would have thrown an exception if the **Load** method had not been called because the object doesn't really exist on the client-side until it is loaded. -- The **Load** method adds something extra to the message: it tells the server to send the specified object down to the client. The **ExecuteQuery** method receives this object (as JSON) and uses it to initialize the client-side `localEmployee` variable. Subsequent client-side code then references that **ListItem** object and its members. As you can see, the next line references the value of the item's `"Title"` field. This line would have thrown an exception if the **Load** method had not been called because the object doesn't really exist on the client-side until it is loaded. - ## Next steps - In the next article, we get back to coding and learn how to [add SharePoint write operations to the provider-hosted add-in](add-sharepoint-write-operations-to-the-provider-hosted-add-in.md). - - - - diff --git a/docs/sp-add-ins/get-started-creating-provider-hosted-sharepoint-add-ins.md b/docs/sp-add-ins/get-started-creating-provider-hosted-sharepoint-add-ins.md index aaf911501..3184719aa 100644 --- a/docs/sp-add-ins/get-started-creating-provider-hosted-sharepoint-add-ins.md +++ b/docs/sp-add-ins/get-started-creating-provider-hosted-sharepoint-add-ins.md @@ -1,12 +1,10 @@ --- title: Get started creating provider-hosted SharePoint Add-ins description: Set up a development environment and create your first provider-hosted SharePoint Add-in. -ms.date: 09/26/2023 +ms.date: 02/10/2025 ms.localizationpriority: high ms.service: sharepoint --- - - # Get started creating provider-hosted SharePoint Add-ins [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] @@ -15,7 +13,7 @@ Provider-hosted add-ins are one of the two major types of SharePoint Add-ins. Fo Here's a summary of provider-hosted add-ins: -- They include a web application, service, or database that is hosted externally from the SharePoint farm or SharePoint Online subscription. They may also include SharePoint components. You can host the external components on any web-hosting stack, including the LAMP (Linux, Apache, MySQL, and PHP) stack. +- They include a web application, service, or database hosted externally from the SharePoint farm or SharePoint Online subscription. They may also include SharePoint components. You can host the external components on any web-hosting stack, including the LAMP (Linux, Apache, MySQL, and PHP) stack. - The custom business logic in the add-in has to run on either the external components or in JavaScript on custom SharePoint pages. In this article, you'll complete the following steps: @@ -24,8 +22,6 @@ In this article, you'll complete the following steps: - Create the add-in project - Code your add-in - - ## Set up your dev environment There are many ways to set up a development environment for SharePoint Add-ins. This section explains the simplest way. For alternatives, such as setting up an "all on-premises" environment, see [Tools](tools-and-environments-for-developing-sharepoint-add-ins.md). @@ -33,13 +29,10 @@ There are many ways to set up a development environment for SharePoint Add-ins. ### Get the tools - If you don't already have **Visual Studio** 2013 or later installed, install it by using the instructions at [Install Visual Studio](/visualstudio/install/install-visual-studio). We recommend using the [latest version from the Microsoft Download Center](https://www.visualstudio.com/downloads/download-visual-studio-vs). - - Visual Studio includes the **Microsoft Office Developer Tools for Visual Studio**. Sometimes a version of the tools is released between updates of Visual Studio. To be sure that you have the latest version of the tools, run the [installer for Office Developer Tools for Visual Studio 2013](https://aka.ms/OfficeDevToolsForVS2013), or the [installer for Office Developer Tools for Visual Studio 2015](https://aka.ms/OfficeDevToolsForVS2015). Reference [earlier versions of Visual Studio](https://msdn.microsoft.com/library/da049020-cfda-40d7-8ff4-7492772b620f.aspx) or other [Visual Studio documentation](/visualstudio/). - - ### Sign up for an Office 365 developer subscription > [!NOTE] @@ -49,8 +42,7 @@ Reference [earlier versions of Visual Studio](https://msdn.microsoft.com/library To get an Office 365 plan: -- [Sign up for an Office 365 developer subscription through the Office 365 Developer Program](https://developer.microsoft.com/office/dev-program). - +- [Sign up for an Office 365 developer subscription through the Office 365 Developer Program](https://developer.microsoft.com/office/dev-program).\ - See the [Office 365 Developer Program documentation](/office/developer-program/office-365-developer-program) for step-by-step instructions about how to join the Office 365 Developer Program and sign up and configure your subscription. ### Open your developer site @@ -64,164 +56,158 @@ Select the **Build Add-ins** link in the upper-left corner of the page to open y ![Screenshot that shows the developer site homepage.](../images/SP15_DeveloperSiteHome_border.png) - - ## Create the add-in project 1. Start Visual Studio by using the **Run as administrator** option. - -2. In Visual Studio, select **File** > **New** > **New Project**. - -3. In the **New Project** dialog box, expand the **Visual C#** node, expand the **Office/SharePoint** node, and then select **Add-ins** > **SharePoint Add-in**. - -4. Name the project **SampleAddIn**, and then select **OK**. - -5. In the **Specify the SharePoint Add-in Settings** dialog box, do the following: +1. In Visual Studio, select **File** > **New** > **New Project**. +1. In the **New Project** dialog box, expand the **Visual C#** node, expand the **Office/SharePoint** node, and then select **Add-ins** > **SharePoint Add-in**. +1. Name the project **SampleAddIn**, and then select **OK**. +1. In the **Specify the SharePoint Add-in Settings** dialog box, do the following: - Provide the full URL of the SharePoint site that you want to use to debug your add-in. This is the URL of the developer site. Use HTTPS, not HTTP in the URL. At some point during this procedure, or shortly after it completes, you will be prompted to sign in to this site. The timing of the prompt varies. Use the administrator credentials (in the \*.onmicrosoft.com domain) that you created when you signed up for your developer site; for example MyName@contoso.onmicrosoft.com. - - Under **How do you want to host your SharePoint Add-in**, select **Provider-hosted**. - - Select **Next**. -6. On the **Specify the target SharePoint version** page, select **SharePoint Online**, and then select **Next**. - -7. Under **Which type of web application project do you want to create?**, select **ASP.NET Web Forms Application**, and then select **Next**. +1. On the **Specify the target SharePoint version** page, select **SharePoint Online**, and then select **Next**. +1. Under **Which type of web application project do you want to create?**, select **ASP.NET Web Forms Application**, and then select **Next**. +1. Under **How do you want your add-in to authenticate?**, select **Use Windows Azure Access Control Service**. +1. In the wizard, select **Finish**. + +Much of the configuration is done when the solution opens. Two projects are created in the Visual Studio solution: one for the SharePoint Add-in and the other for the ASP.NET web application. -8. Under **How do you want your add-in to authenticate?**, select **Use Windows Azure Access Control Service**. +## Register and apply ACS app -9. In the wizard, select **Finish**. - - Much of the configuration is done when the solution opens. Two projects are created in the Visual Studio solution: one for the SharePoint Add-in and the other for the ASP.NET web application. +1. Register app, see [To register by using AppRegNew.aspx](register-sharepoint-add-ins.md#to-register-by-using-appregnewaspx) +1. Open the addin project, right-click the **AppManifest.xml** file, and select **View Code** to see the file. +1. Update the `ClientId` field to the one generated in step 1. +1. Open the **web.config** file, replace the `ClientId` and `ClientSecret` fields with the one generated from step 1. - ## Code your add-in 1. Open the AppManifest.xml file. On the **Permissions** tab, specify the **Site Collection** scope and the **Read** permission level. - -2. Delete any markup inside the `` tag of the Pages/Default.aspx file of your web application, and then add the following HTML and ASP.NET controls inside the ``. This sample uses the [UpdatePanel](https://msdn2.microsoft.com/library/bb359258) control to enable partial page rendering. +1. Delete any markup inside the `` tag of the **Pages/Default.aspx** file of your web application, and then add the following HTML and ASP.NET controls inside the ``. This sample uses the [UpdatePanel](https://msdn2.microsoft.com/library/bb359258) control to enable partial page rendering. ```HTML -
    -
    - - - - - - - -
    - -

    SharePoint Site

    - - -

    Current User:

    - - -

    Site Users

    - - - -
    -
    -
    - -

    Site Lists

    - - - -
    -
    -
    -
    -
    -
    -
    -
    +
    +
    + + + + + + + +
    + +

    SharePoint Site

    + + +

    Current User:

    + + +

    Site Users

    + + + +
    +
    +
    + +

    Site Lists

    + + + +
    +
    +
    +
    +
    +
    +
    +
    ``` -3. Add the following declarations to the Default.aspx.cs file of your web application. +1. Add the following declarations to the **Default.aspx.cs** file of your web application. ```csharp - using Microsoft.SharePoint.Client; - using Microsoft.IdentityModel.S2S.Tokens; - using System.Net; - using System.IO; - using System.Xml; + using Microsoft.SharePoint.Client; + using Microsoft.IdentityModel.S2S.Tokens; + using System.Net; + using System.IO; + using System.Xml; ``` -4. In the Default.aspx.cs file of your web application, add these variables inside the [Page](https://msdn2.microsoft.com/library/dfbt9et1) class. +1. In the **Default.aspx.cs** file of your web application, add these variables inside the [Page](https://msdn2.microsoft.com/library/dfbt9et1) class. ```csharp - SharePointContextToken contextToken; - string accessToken; - Uri sharepointUrl; - string siteName; - string currentUser; - List listOfUsers = new List(); - List listOfLists = new List(); + SharePointContextToken contextToken; + string accessToken; + Uri sharepointUrl; + string siteName; + string currentUser; + List listOfUsers = new List(); + List listOfLists = new List(); ``` -5. Add the `RetrieveWithCSOM` method inside the [Page](https://msdn2.microsoft.com/library/dfbt9et1) class. This method uses the SharePoint CSOM to retrieve information about your site and display it on the page. +1. Add the `RetrieveWithCSOM` method inside the [Page](https://msdn2.microsoft.com/library/dfbt9et1) class. This method uses the SharePoint CSOM to retrieve information about your site and display it on the page. ```csharp - // This method retrieves information about the host web by using the CSOM. - private void RetrieveWithCSOM(string accessToken) - { - - if (IsPostBack) - { - sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]); - } - - ClientContext clientContext = - TokenHelper.GetClientContextWithAccessToken( - sharepointUrl.ToString(), accessToken); - - // Load the properties for the web object. - Web web = clientContext.Web; - clientContext.Load(web); - clientContext.ExecuteQuery(); - - // Get the site name. - siteName = web.Title; - - // Get the current user. - clientContext.Load(web.CurrentUser); - clientContext.ExecuteQuery(); - currentUser = clientContext.Web.CurrentUser.LoginName; - - // Load the lists from the Web object. - ListCollection lists = web.Lists; - clientContext.Load(lists); - clientContext.ExecuteQuery(); - - // Load the current users from the Web object. - UserCollection users = web.SiteUsers; - clientContext.Load(users); - clientContext.ExecuteQuery(); - - foreach (User siteUser in users) - { - listOfUsers.Add(siteUser.LoginName); - } - - foreach (List list in lists) - { - listOfLists.Add(list.Title); - } - } + // This method retrieves information about the host web by using the CSOM. + private void RetrieveWithCSOM(string accessToken) + { + + if (IsPostBack) + { + sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]); + } + + ClientContext clientContext = + TokenHelper.GetClientContextWithAccessToken( + sharepointUrl.ToString(), accessToken); + + // Load the properties for the web object. + Web web = clientContext.Web; + clientContext.Load(web); + clientContext.ExecuteQuery(); + + // Get the site name. + siteName = web.Title; + + // Get the current user. + clientContext.Load(web.CurrentUser); + clientContext.ExecuteQuery(); + currentUser = clientContext.Web.CurrentUser.LoginName; + + // Load the lists from the Web object. + ListCollection lists = web.Lists; + clientContext.Load(lists); + clientContext.ExecuteQuery(); + + // Load the current users from the Web object. + UserCollection users = web.SiteUsers; + clientContext.Load(users); + clientContext.ExecuteQuery(); + + foreach (User siteUser in users) + { + listOfUsers.Add(siteUser.LoginName); + } + + foreach (List list in lists) + { + listOfLists.Add(list.Title); + } + } ``` -6. Add the `CSOM_Click` method inside the [Page](https://msdn2.microsoft.com/library/dfbt9et1) class. This method triggers the event that occurs when the user clicks the **Populate Data** link. +1. Add the `CSOM_Click` method inside the [Page](https://msdn2.microsoft.com/library/dfbt9et1) class. This method triggers the event that occurs when the user clicks the **Populate Data** link. ```csharp - protected void CSOM_Click(object sender, EventArgs e) + protected void CSOM_Click(object sender, EventArgs e) { string commandAccessToken = ((LinkButton)sender).CommandArgument; RetrieveWithCSOM(commandAccessToken); @@ -234,14 +220,14 @@ Select the **Build Add-ins** link in the upper-left corner of the page to open y } ``` -7. Replace the existing `Page_Load` method with this one. The `Page_Load` method uses methods in the TokenHelper.cs file to retrieve the context from the `Request` object and get an access token from Microsoft Azure Access Control Service (ACS). +1. Replace the existing `Page_Load` method with this one. The `Page_Load` method uses methods in the TokenHelper.cs file to retrieve the context from the `Request` object and get an access token from Microsoft Azure Access Control Service (ACS). ```csharp - // The Page_load method fetches the context token and the access token. + // The Page_load method fetches the context token and the access token. // The access token is used by all of the data retrieval methods. protected void Page_Load(object sender, EventArgs e) { - string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request); + string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request); if (contextTokenString != null) { @@ -265,159 +251,151 @@ Select the **Build Add-ins** link in the upper-left corner of the page to open y } ``` -8. The Default.aspx.cs file should look like this when you're finished. +1. The **Default.aspx.cs** file should look like this when you're finished. ```csharp - using System; - using System.Collections.Generic; - using System.Linq; - using System.Web; - using System.Web.UI; - using System.Web.UI.WebControls; - - using Microsoft.SharePoint.Client; - using Microsoft.IdentityModel.S2S.Tokens; - using System.Net; - using System.IO; - using System.Xml; - - namespace SampleAddInWeb - { - public partial class Default : System.Web.UI.Page - { - SharePointContextToken contextToken; - string accessToken; - Uri sharepointUrl; - string siteName; - string currentUser; - List listOfUsers = new List(); - List listOfLists = new List(); - - protected void Page_PreInit(object sender, EventArgs e) - { - Uri redirectUrl; - switch (SharePointContextProvider.CheckRedirectionStatus(Context, out redirectUrl)) - { - case RedirectionStatus.Ok: - return; - case RedirectionStatus.ShouldRedirect: - Response.Redirect(redirectUrl.AbsoluteUri, endResponse: true); - break; - case RedirectionStatus.CanNotRedirect: - Response.Write("An error occurred while processing your request."); - Response.End(); - break; - } - } - - protected void CSOM_Click(object sender, EventArgs e) - { - string commandAccessToken = ((LinkButton)sender).CommandArgument; - RetrieveWithCSOM(commandAccessToken); - WebTitleLabel.Text = siteName; - CurrentUserLabel.Text = currentUser; - UserList.DataSource = listOfUsers; - UserList.DataBind(); - ListList.DataSource = listOfLists; - ListList.DataBind(); - } - - // This method retrieves information about the host web by using the CSOM. - private void RetrieveWithCSOM(string accessToken) - { - - if (IsPostBack) - { - sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]); - } - - ClientContext clientContext = - TokenHelper.GetClientContextWithAccessToken( - sharepointUrl.ToString(), accessToken); - - // Load the properties for the web object. - Web web = clientContext.Web; - clientContext.Load(web); - clientContext.ExecuteQuery(); - - // Get the site name. - siteName = web.Title; - - // Get the current user. - clientContext.Load(web.CurrentUser); - clientContext.ExecuteQuery(); - currentUser = clientContext.Web.CurrentUser.LoginName; - - // Load the lists from the Web object. - ListCollection lists = web.Lists; - clientContext.Load(lists); - clientContext.ExecuteQuery(); - - // Load the current users from the Web object. - UserCollection users = web.SiteUsers; - clientContext.Load(users); - clientContext.ExecuteQuery(); - - foreach (User siteUser in users) - { - listOfUsers.Add(siteUser.LoginName); - } - - foreach (List list in lists) - { - listOfLists.Add(list.Title); - } - } - - protected void Page_Load(object sender, EventArgs e) - { - string contextTokenString = - TokenHelper.GetContextTokenFromRequest(Request); - - if (contextTokenString != null) - { - contextToken = - TokenHelper.ReadAndValidateContextToken(contextTokenString, Request.Url.Authority); - - sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]); - accessToken = - TokenHelper.GetAccessToken(contextToken, sharepointUrl.Authority) - .AccessToken; - CSOM.CommandArgument = accessToken; - } - else if (!IsPostBack) - { - Response.Write("Could not find a context token."); - return; - } - } - } - } - + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + + using Microsoft.SharePoint.Client; + using Microsoft.IdentityModel.S2S.Tokens; + using System.Net; + using System.IO; + using System.Xml; + + namespace SampleAddInWeb + { + public partial class Default : System.Web.UI.Page + { + SharePointContextToken contextToken; + string accessToken; + Uri sharepointUrl; + string siteName; + string currentUser; + List listOfUsers = new List(); + List listOfLists = new List(); + + protected void Page_PreInit(object sender, EventArgs e) + { + Uri redirectUrl; + switch (SharePointContextProvider.CheckRedirectionStatus(Context, out redirectUrl)) + { + case RedirectionStatus.Ok: + return; + case RedirectionStatus.ShouldRedirect: + Response.Redirect(redirectUrl.AbsoluteUri, endResponse: true); + break; + case RedirectionStatus.CanNotRedirect: + Response.Write("An error occurred while processing your request."); + Response.End(); + break; + } + } + + protected void CSOM_Click(object sender, EventArgs e) + { + string commandAccessToken = ((LinkButton)sender).CommandArgument; + RetrieveWithCSOM(commandAccessToken); + WebTitleLabel.Text = siteName; + CurrentUserLabel.Text = currentUser; + UserList.DataSource = listOfUsers; + UserList.DataBind(); + ListList.DataSource = listOfLists; + ListList.DataBind(); + } + + // This method retrieves information about the host web by using the CSOM. + private void RetrieveWithCSOM(string accessToken) + { + + if (IsPostBack) + { + sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]); + } + + ClientContext clientContext = + TokenHelper.GetClientContextWithAccessToken( + sharepointUrl.ToString(), accessToken); + + // Load the properties for the web object. + Web web = clientContext.Web; + clientContext.Load(web); + clientContext.ExecuteQuery(); + + // Get the site name. + siteName = web.Title; + + // Get the current user. + clientContext.Load(web.CurrentUser); + clientContext.ExecuteQuery(); + currentUser = clientContext.Web.CurrentUser.LoginName; + + // Load the lists from the Web object. + ListCollection lists = web.Lists; + clientContext.Load(lists); + clientContext.ExecuteQuery(); + + // Load the current users from the Web object. + UserCollection users = web.SiteUsers; + clientContext.Load(users); + clientContext.ExecuteQuery(); + + foreach (User siteUser in users) + { + listOfUsers.Add(siteUser.LoginName); + } + + foreach (List list in lists) + { + listOfLists.Add(list.Title); + } + } + + protected void Page_Load(object sender, EventArgs e) + { + string contextTokenString = + TokenHelper.GetContextTokenFromRequest(Request); + + if (contextTokenString != null) + { + contextToken = + TokenHelper.ReadAndValidateContextToken(contextTokenString, Request.Url.Authority); + + sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]); + accessToken = + TokenHelper.GetAccessToken(contextToken, sharepointUrl.Authority) + .AccessToken; + CSOM.CommandArgument = accessToken; + } + else if (!IsPostBack) + { + Response.Write("Could not find a context token."); + return; + } + } + } + } ``` -9. Use the F5 key to deploy and run your add-in. If you see a **Security Alert** window that asks you to trust the self-signed Localhost certificate, select **Yes**. - -10. Select **Trust It** on the consent page to grant permissions to the add-in. Visual Studio will install the web application to IIS Express and then install the add-in to your test SharePoint site and launch it. You'll see a page that has the table shown in the following screen shot. To see summary information about your SharePoint site, select **Populate Data**. +1. Use the F5 key to deploy and run your add-in. If you see a **Security Alert** window that asks you to trust the self-signed Localhost certificate, select **Yes**. +1. Select **Trust It** on the consent page to grant permissions to the add-in. Visual Studio will install the web application to IIS Express and then install the add-in to your test SharePoint site and launch it. You'll see a page that has the table shown in the following screenshot. To see summary information about your SharePoint site, select **Populate Data**. - ![Basic self-hosted app launch page](../images/SP15_basicself-hostedapp.gif) - + ![Basic self-hosted app launch page](../images/SP15_basicself-hostedapp.gif) - ## Next steps To create your add-ins, walk through the following steps in this order: 1. [Give your provider-hosted add-in the SharePoint look-and-feel](give-your-provider-hosted-add-in-the-sharepoint-look-and-feel.md) -2. [Include a custom button in the provider-hosted add-in](include-a-custom-button-in-the-provider-hosted-add-in.md) -3. [Get a quick overview of the SharePoint object model](get-a-quick-overview-of-the-sharepoint-object-model.md) -4. [Add SharePoint write operations to the provider-hosted add-in](add-sharepoint-write-operations-to-the-provider-hosted-add-in.md) -5. [Include an add-in part in the provider-hosted add-in](include-an-add-in-part-in-the-provider-hosted-add-in.md) -6. [Handle add-in events in the provider-hosted add-in](handle-add-in-events-in-the-provider-hosted-add-in.md) -7. [Add first-run logic to the provider-hosted add-in](add-first-run-logic-to-the-provider-hosted-add-in.md) -8. [Programmatically deploy a custom button in the provider-hosted add-in](programmatically-deploy-a-custom-button-in-the-provider-hosted-add-in.md) -9. [Handle list item events in the provider-hosted add-in](handle-list-item-events-in-the-provider-hosted-add-in.md) - - - - +1. [Include a custom button in the provider-hosted add-in](include-a-custom-button-in-the-provider-hosted-add-in.md) +1. [Get a quick overview of the SharePoint object model](get-a-quick-overview-of-the-sharepoint-object-model.md) +1. [Add SharePoint write operations to the provider-hosted add-in](add-sharepoint-write-operations-to-the-provider-hosted-add-in.md) +1. [Include an add-in part in the provider-hosted add-in](include-an-add-in-part-in-the-provider-hosted-add-in.md) +1. [Handle add-in events in the provider-hosted add-in](handle-add-in-events-in-the-provider-hosted-add-in.md) +1. [Add first-run logic to the provider-hosted add-in](add-first-run-logic-to-the-provider-hosted-add-in.md) +1. [Programmatically deploy a custom button in the provider-hosted add-in](programmatically-deploy-a-custom-button-in-the-provider-hosted-add-in.md) +1. [Handle list item events in the provider-hosted add-in](handle-list-item-events-in-the-provider-hosted-add-in.md) diff --git a/docs/sp-add-ins/get-to-know-the-sharepoint-rest-service.md b/docs/sp-add-ins/get-to-know-the-sharepoint-rest-service.md index 12a4561c4..a311b58f4 100644 --- a/docs/sp-add-ins/get-to-know-the-sharepoint-rest-service.md +++ b/docs/sp-add-ins/get-to-know-the-sharepoint-rest-service.md @@ -122,7 +122,7 @@ The following table contains typical REST endpoint URL examples to get you start ```json { "__metadata": { - "type": "SP.Data.listname.ListItem" + "type": "SP.Data.listnameListItem" }, "Title": "MyItem" } @@ -130,6 +130,17 @@ The following table contains typical REST endpoint URL examples to get you start In the above JSON, replace listname with the name of your SharePoint list by omitting the spaces. +For example, if your SharePoint list name is "My Awesome List" the resulting json should be: + +```json +{ + "__metadata": { + "type": "SP.Data.MyAwesomeListListItem" + }, + "Title": "MyItem" +} +``` + ## Batch job support The SharePoint Online (and on-premises SharePoint 2016 or later) 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](make-batch-requests-with-the-rest-apis.md). diff --git a/docs/sp-add-ins/handle-add-in-events-in-the-provider-hosted-add-in.md b/docs/sp-add-ins/handle-add-in-events-in-the-provider-hosted-add-in.md index 8b7687cf8..6a6df0c3a 100644 --- a/docs/sp-add-ins/handle-add-in-events-in-the-provider-hosted-add-in.md +++ b/docs/sp-add-ins/handle-add-in-events-in-the-provider-hosted-add-in.md @@ -5,12 +5,11 @@ ms.date: 09/26/2023 ms.localizationpriority: medium ms.service: sharepoint --- - # Handle add-in events in the provider-hosted add-in [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the seventh in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). +This is the seventh in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeAdd-inEventHandlers.sln file. @@ -27,64 +26,60 @@ We want our Chain Store add-in to create and deploy the **Local Employees** and Deciding which is best for a given add-in is an advanced topic. In this article, we can only mention a few points of comparison: - A custom installation handler has to complete in 30 seconds. There is no limit to how long first-run logic can take. - -- If anything goes wrong during an add-in installation, SharePoint rolls back everything it has done as part of the installation. A custom installation handler runs *after* SharePoint has done everything it's going to do to install the add-in, so a custom handler can participate in this system. +- If anything goes wrong during an add-in installation, SharePoint rolls back everything it has done as part of the installation. A custom installation handler runs *after* SharePoint has done everything it's going to do to install the add-in, so a custom handler can participate in this system. For example, if your custom logic throws an exception, you can tell SharePoint to roll back the entire add-in installation. If something goes wrong in custom first-run logic, however, the add-in remains installed and presumably won't work properly. -- SharePoint doesn't give up if it has to roll back an add-in installation. It immediately tries the installation again. It makes up to four attempts (the 30-second time limit applies on each attempt). Each time it retries, the custom installation handler runs again *from the beginning*. If the handler managed to install, say, a list, before the rollback, it tries to install the same list again on the retry. +- SharePoint doesn't give up if it has to roll back an add-in installation. It immediately tries the installation again. It makes up to four attempts (the 30-second time limit applies on each attempt). Each time it retries, the custom installation handler runs again *from the beginning*. If the handler managed to install, say, a list, before the rollback, it tries to install the same list again on the retry. To prevent this from happening, code in an installation handler has to be written so that it won't take any action (such as deploy a component) unless it first checks to see if that action has already been done. This makes the logic of an installation handler more complex than first-run logic because first-run logic won't retry (unless you specifically code it to do so). Also, checking to see if a component has already been deployed usually requires a time-consuming call over the Internet from the remote handler to SharePoint. A second call is also needed to actually deploy the component (if it has not already been deployed). -For the Chain Store add-in, we combine these strategies. In this article, you create an installation handler that registers the host web as a tenant in the corporate database and then sets a signal that specifies whether the add-in has been run yet on the host web. +For the Chain Store add-in, we combine these strategies. In this article, you create an installation handler that registers the host web as a tenant in the corporate database and then sets a signal that specifies whether the add-in has been run yet on the host web. In a later article in this series, you'll put first-run logic in the **Page_Load** method of the add-ins start page. This logic deploys the two custom lists and does some other things, too. - ## Configure the solution for event receiver debugging -Debugging of event receivers requires the use of the Azure Service Bus. Follow the instructions at [Debug and troubleshoot a remote event receiver in a SharePoint Add-in](debug-and-troubleshoot-a-remote-event-receiver-in-a-sharepoint-add-in.md). Because you are using a SharePoint Online website as your test site, ensure that you carry out the instructions for a remote test site. The remainder of this series assumes you have configured debugging successfully. +Debugging of event receivers requires the use of the Azure Service Bus. Follow the instructions at [Debug and troubleshoot a remote event receiver in a SharePoint Add-in](debug-and-troubleshoot-a-remote-event-receiver-in-a-sharepoint-add-in.md). Because you are using a SharePoint Online website as your test site, ensure that you carry out the instructions for a remote test site. The remainder of this series assumes you have configured debugging successfully. ## Create the installation handler > [!NOTE] -> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: -> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. -> 2. Ensure that all three projects are set to **Start** in the **Action** column. +> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: +> +> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. +> 1. Ensure that all three projects are set to **Start** in the **Action** column. 1. In **Solution Explorer**, select the **ChainStore** project so that its properties appear in the **Properties** pane of Visual Studio. +1. Set the value of **Handle Add-in Installed** to **True** (it may still be called **Handle App Installed**). This does two things: -2. Set the value of **Handle Add-in Installed** to **True** (it may still be called **Handle App Installed**). This does two things: - - A folder called **Services** is created in the **ChainStoreWeb** project (not the **ChainStore** project), and two files are added to it: an AppEventReceiver.svc file and its code-behind AppEventReceiver.svc.cs file (the file names begin with the string "App" because add-ins used to be called "apps"; *don't rename these files* because the Office Developer Tools for Visual Studio assumes that the files will keep these names). + - The handler URL is registered in the add-in manifest. This part of the manifest is not visible in the manifest designer. To see it, right-click the AppManifest.xml file and select **View Code**. A new child of the **Properties** element looks like the following. - - The handler URL is registered in the add-in manifest. This part of the manifest is not visible in the manifest designer. To see it, right-click the AppManifest.xml file and select **View Code**. A new child of the **Properties** element looks like the following. - ```XML ~remoteAppUrl/Services/AppEventReceiver.svc - ``` - + ``` + This markup tells SharePoint to call the **ProcessEvent** method of this service when it has finished doing all of its own work related to installing the add-in. The custom handler is the last thing that runs as part of the installation. The string `~remoteAppUrl` is a placeholder that the Office Developer Tools for Visual Studio replaces with the service host URL. When you are debugging, it is an Azure Service Bus URL. When you create the package for deployment to production, it is the production URL. -3. Open the AppEventReceiver.svc.cs file. - -4. You see that the Office Developer Tools for Visual Studio has created a sample implementation of the **ProcessEvent** method. All implementations of this method begin by initializing an **SPRemoteEventResult** object, and they all end by returning that object to SharePoint. Among other things, this object tells SharePoint whether or not it should roll back the event because the custom handling logic has failed. +1. Open the AppEventReceiver.svc.cs file. +1. You see that the Office Developer Tools for Visual Studio has created a sample implementation of the **ProcessEvent** method. All implementations of this method begin by initializing an **SPRemoteEventResult** object, and they all end by returning that object to SharePoint. Among other things, this object tells SharePoint whether or not it should roll back the event because the custom handling logic has failed. The tools may also have included a **using** block in this method that creates a **ClientContext** object. The custom handler in the Chain Store add-in isn't going to call back into SharePoint, so delete this block. The method should now look like the following. - + ```csharp - public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) - { - SPRemoteEventResult result = new SPRemoteEventResult(); + public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) + { + SPRemoteEventResult result = new SPRemoteEventResult(); - return result; - } + return result; + } ``` -5. The event receiver could be called by any of three possible add-in events, so add the following **switch** structure to the **ProcessEvent** method in between the lines that create and return the `result` object (the event names have the string "App" in them because add-ins used to be called "apps"). - +1. The event receiver could be called by any of three possible add-in events, so add the following **switch** structure to the **ProcessEvent** method in between the lines that create and return the `result` object (the event names have the string "App" in them because add-ins used to be called "apps"). + ```csharp - switch (properties.EventType) + switch (properties.EventType) { case SPRemoteEventType.AppInstalled: @@ -96,61 +91,60 @@ Debugging of event receivers requires the use of the Azure Service Bus. Follow t break; case SPRemoteEventType.AppUninstalling: - // TODO3: Custom uninstallation logic goes here. + // TODO3: Custom uninstallation logic goes here. break; } ``` -6. Our installation logic is going to call an SQL stored procedure to register the Hong Kong SAR store as a tenant in the remote web application. It is very important that, if this process fails, the handler signals SharePoint to roll back the installation of the add-in, so add the following **try/catch** blocks in place of `TODO2`. +1. Our installation logic is going to call an SQL stored procedure to register the Hong Kong SAR store as a tenant in the remote web application. It is very important that, if this process fails, the handler signals SharePoint to roll back the installation of the add-in, so add the following **try/catch** blocks in place of `TODO2`. ```csharp - try + try { CreateTenant(tenantName); - } + } catch (Exception e) { - // Tell SharePoint to cancel and roll back the event. + // Tell SharePoint to cancel and roll back the event. result.ErrorMessage = e.Message; result.Status = SPRemoteEventServiceStatus.CancelWithError; } ``` - Note the following about this code: + > NOTE: + > - You create the `tenantName` object and `CreateTenant` method in a later step. + > - The **Status** property of the **SPRemoteEventResult** object can have three possible values: **Continue** (the default), **CancelNoError**, and **CancelWithError**. Either of the latter two tell SharePoint to roll back the event. - - You create the `tenantName` object and `CreateTenant` method in a later step. - - The **Status** property of the **SPRemoteEventResult** object can have three possible values: **Continue** (the default), **CancelNoError**, and **CancelWithError**. Either of the latter two tell SharePoint to roll back the event. +1. The host web URL, which is the sample's tenant discriminator, is part of the information that SharePoint passes to the receiver in the **SPRemoteEventProperties** parameter. Add the following line to the **ProcessEvent** method on the line that is just under the initialization of the **SPRemoteEventResult** object. -7. The host web URL, which is the sample's tenant discriminator, is part of the information that SharePoint passes to the receiver in the **SPRemoteEventProperties** parameter. Add the following line to the **ProcessEvent** method on the line that is just under the initialization of the **SPRemoteEventResult** object. - ```csharp - string tenantName = properties.AppEventProperties.HostWebFullUrl.ToString(); + string tenantName = properties.AppEventProperties.HostWebFullUrl.ToString(); ``` -8. Now our code has to deal with a little quirk of the **AppEventProperties.HostWebFullUrl** property. In most other contexts, SharePoint includes a closing `"/"` character at the end of the host web URL, so the logic of our sample code assumes that this character is present. But SharePoint adds this character at the end of the **HostWebFullUrl** value if, and only if, the host web is the root web of a site collection. Because our Hong Kong SAR website is a subweb in the site collection, we need to add this character to ensure that the same tenant name string is used throughout the sample. +1. Now our code has to deal with a little quirk of the **AppEventProperties.HostWebFullUrl** property. In most other contexts, SharePoint includes a closing `"/"` character at the end of the host web URL, so the logic of our sample code assumes that this character is present. But SharePoint adds this character at the end of the **HostWebFullUrl** value if, and only if, the host web is the root web of a site collection. Because our Hong Kong SAR website is a subweb in the site collection, we need to add this character to ensure that the same tenant name string is used throughout the sample. Add the following code under the initialization of the `tenantName` object. - + ```csharp - if (!tenantName.EndsWith("/")) + if (!tenantName.EndsWith("/")) { tenantName += "/"; } ``` -9. Add the following **using** statements to the top of the file. - +1. Add the following **using** statements to the top of the file. + ```csharp - using System.Data.SqlClient; - using System.Data; - using ChainStoreWeb.Utilities; + using System.Data.SqlClient; + using System.Data; + using ChainStoreWeb.Utilities; ``` -10. Add the following method to the `AppEventReceiver` class. We don't discuss this in detail because the purpose of this series of articles is to teach SharePoint Add-in programming, not SQL Server/Azure programming. +1. Add the following method to the `AppEventReceiver` class. We don't discuss this in detail because the purpose of this series of articles is to teach SharePoint Add-in programming, not SQL Server/Azure programming. ```csharp - private void CreateTenant(string tenantName) + private void CreateTenant(string tenantName) { // Do not catch exceptions. Allow them to bubble up and trigger roll back // of installation. @@ -169,22 +163,21 @@ Debugging of event receivers requires the use of the Azure Service Bus. Follow t ``` This method creates a row in a database table called **Tenants**. In addition to the **Name** column, the table also has a **Version** column with a default value set to 0000.0000.0000.0000. In a later article in this series, you will create first-run logic that looks at this value to determine whether the add-in has already been installed on the host web. If the version is 0000.0000.0000.0000, your code deploys the **Local Employees** and **Expected Shipments** lists, and then raises the version number. - + ## Create the uninstallation handler -It is usually a good practice to handle the uninstalling event whenever you are handling the installed event. The basic idea is that the uninstalling handler deletes or recycles things that the installed handler deployed. There are, however, many exceptions, so you really need to understand the use cases of your add-in. For example, a list that is deployed with an add-in and populated with the add-in might still have value even after the add-in itself is uninstalled, in which case you wouldn't want to uninstall the list in the uninstalling event handler. +It is usually a good practice to handle the uninstalling event whenever you are handling the installed event. The basic idea is that the uninstalling handler deletes or recycles things that the installed handler deployed. There are, however, many exceptions, so you really need to understand the use cases of your add-in. For example, a list that is deployed with an add-in and populated with the add-in might still have value even after the add-in itself is uninstalled, in which case you wouldn't want to uninstall the list in the uninstalling event handler. The uninstallation event does not run, as you might expect, when a user removes the add-in from the **Site Contents** page. Doing so only moves the add-in to the website's Recycle Bin. A user could restore it, but restoring does not rerun the installed event handler, so you'd want anything that was deployed with the installed event handler to still exist if the add-in is restored. SharePoint components can be moved from the Recycle Bin to the second-stage Recycle Bin. It is only when an add-in is deleted from the second-stage that the uninstalling event happens; when a user does that, the add-in is unrestorable anyway, so we want the Hong Kong SAR store's tenancy to be removed from the corporate database at that point. -1. Set the value of **Handle Add-in Uninstalling** to **True** (it may still be called **Handle App Uninstalling**). This registers the handler in the AppManifest.xml file just as you earlier registered the installation handler. If you look at the file, you see that they have exactly the same URL. The Office Developer Tools for Visual Studio assumes that you are using the same \*.svc file. We are doing that in this sample, and it is a standard practice. - -2. Add the following code in place of `TODO3` in the AppEventReceiver.svc.cs file. +1. Set the value of **Handle Add-in Uninstalling** to **True** (it may still be called **Handle App Uninstalling**). This registers the handler in the AppManifest.xml file just as you earlier registered the installation handler. If you look at the file, you see that they have exactly the same URL. The Office Developer Tools for Visual Studio assumes that you are using the same \*.svc file. We are doing that in this sample, and it is a standard practice. +1. Add the following code in place of `TODO3` in the AppEventReceiver.svc.cs file. ```csharp - try + try { DeleteTenant(tenantName); - } + } catch (Exception e) { // Tell SharePoint to cancel and roll back the event. @@ -193,15 +186,14 @@ The uninstallation event does not run, as you might expect, when a user removes } ``` - Note the following about this code: + > NOTE: + > - The `DeleteTenant` method is added in the next step. + > - Rolling back the uninstallation of the add-in leaves it in the second-stage Recycle Bin, from which it could still be restored. - - The `DeleteTenant` method is added in the next step. - - Rolling back the uninstallation of the add-in leaves it in the second-stage Recycle Bin, from which it could still be restored. +1. Add the following method to the `AppEventReceiver` class. -3. Add the following method to the `AppEventReceiver` class. - ```csharp - private void DeleteTenant(string tenantName) + private void DeleteTenant(string tenantName) { // Do not catch exceptions. Allow them to bubble up and trigger roll back // of un-installation (removal from 2nd level Recycle Bin). @@ -214,7 +206,7 @@ The uninstallation event does not run, as you might expect, when a user removes cmd.CommandType = CommandType.StoredProcedure; SqlParameter name = cmd.Parameters.Add("@Name", SqlDbType.NVarChar); name.Value = tenantName; - cmd.ExecuteNonQuery(); + cmd.ExecuteNonQuery(); }//dispose conn and cmd } ``` @@ -224,25 +216,17 @@ The uninstallation event does not run, as you might expect, when a user removes ## Run the add-in and test the installation handler -1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site, runs the installation event handler, and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. - -2. When the add-in's start page opens, select the gear icon on the chrome control at the top, and then select **Account settings**. +1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site, runs the installation event handler, and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. When the add-in's start page opens, select the gear icon on the chrome control at the top, and then select **Account settings**. +1. On the **Accounts settings** page, select the **Show Add-in Version** button. The version shows as 0000.0000.0000.0000. -3. On the **Accounts settings** page, select the **Show Add-in Version** button. The version shows as 0000.0000.0000.0000. - *Figure 1. Account settings page* ![The Account settings page with the heading "Account settings", a button named "Show Add-in Version", and under this, a line of text reading "Registered version: zero zero zero zero dot zero zero zero zero dot zero zero zero zero dot zero zero zero zero".](../images/2a905b7d-89c7-456a-8456-21a9b7e9efc5.PNG) -4. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time that you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. - -5. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. +1. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time that you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. +1. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. ## Next steps - In the next article of the series, you will add first-run logic to the add-in that programmatically deploys the **Local Employees** list and the custom ribbon button: [Add first-run logic to the provider-hosted add-in](add-first-run-logic-to-the-provider-hosted-add-in.md). - - - - diff --git a/docs/sp-add-ins/handle-list-item-events-in-the-provider-hosted-add-in.md b/docs/sp-add-ins/handle-list-item-events-in-the-provider-hosted-add-in.md index c800b673f..aa09faad8 100644 --- a/docs/sp-add-ins/handle-list-item-events-in-the-provider-hosted-add-in.md +++ b/docs/sp-add-ins/handle-list-item-events-in-the-provider-hosted-add-in.md @@ -10,605 +10,566 @@ ms.service: sharepoint [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the tenth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). +This is the tenth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeRER.sln file. -You saw in an earlier article in this series that when an order is placed, it is added to the **Orders** table in the corporate database, and an item for it is automatically added to the **Expected Shipments** list. When it arrives at the local store, a user sets the **Arrived** column to **Yes**. Changing a field value for an item creates an item updated event for which you can add a custom handler. +You saw in an earlier article in this series that when an order is placed, it is added to the **Orders** table in the corporate database, and an item for it is automatically added to the **Expected Shipments** list. When it arrives at the local store, a user sets the **Arrived** column to **Yes**. Changing a field value for an item creates an item updated event for which you can add a custom handler. In this article, you create a handler for this list item event and then programmatically deploy it in the first-run logic of the SharePoint Add-in. Your handler adds the item into the **Inventory** table in the corporate database. It then sets the **Added to Inventory** column of the **Expected Shipments** list to **Yes**. You also learn how to prevent this second item updated event from setting off an infinite series of item updated events. ## Programmatically deploy the Expected Shipments list > [!NOTE] -> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: -> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. -> 2. Ensure that all three projects are set to **Start** in the **Action** column. +> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: +> +> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. +> 1. Ensure that all three projects are set to **Start** in the **Action** column. -1. In **Solution Explorer**, open the Utilities\SharePointComponentDeployer.cs file in the **ChainStoreWeb** project. Add the following method to the `SharePointComponentDeployer` class. +1. In **Solution Explorer**, open the Utilities\SharePointComponentDeployer.cs file in the **ChainStoreWeb** project. Add the following method to the `SharePointComponentDeployer` class. - ```csharp - private static void CreateExpectedShipmentsList() - { - using (var clientContext = sPContext.CreateUserClientContextForSPHost()) - { - var query = from list in clientContext.Web.Lists - where list.Title == "Expected Shipments" - select list; - IEnumerable matchingLists = clientContext.LoadQuery(query); - clientContext.ExecuteQuery(); - - if (matchingLists.Count() == 0) - { - ListCreationInformation listInfo = new ListCreationInformation(); - listInfo.Title = "Expected Shipments"; - listInfo.TemplateType = (int)ListTemplateType.GenericList; - listInfo.Url = "Lists/ExpectedShipments"; - List expectedShipmentsList = clientContext.Web.Lists.Add(listInfo); - - Field field = expectedShipmentsList.Fields.GetByInternalNameOrTitle("Title"); - field.Title = "Product"; - field.Update(); - - expectedShipmentsList.Fields.AddFieldAsXml("", - true, - AddFieldOptions.DefaultValue); - expectedShipmentsList.Fields.AddFieldAsXml("" - + "1", - true, - AddFieldOptions.DefaultValue); - expectedShipmentsList.Fields.AddFieldAsXml("" - + "FALSE", - true, - AddFieldOptions.DefaultValue); - expectedShipmentsList.Fields.AddFieldAsXml("" - + "FALSE", - true, - AddFieldOptions.DefaultValue); - - clientContext.ExecuteQuery(); - } - } - } - ``` + ```csharp + private static void CreateExpectedShipmentsList() + { + using (var clientContext = sPContext.CreateUserClientContextForSPHost()) + { + var query = from list in clientContext.Web.Lists + where list.Title == "Expected Shipments" + select list; + IEnumerable matchingLists = clientContext.LoadQuery(query); + clientContext.ExecuteQuery(); + + if (matchingLists.Count() == 0) + { + ListCreationInformation listInfo = new ListCreationInformation(); + listInfo.Title = "Expected Shipments"; + listInfo.TemplateType = (int)ListTemplateType.GenericList; + listInfo.Url = "Lists/ExpectedShipments"; + List expectedShipmentsList = clientContext.Web.Lists.Add(listInfo); + + Field field = expectedShipmentsList.Fields.GetByInternalNameOrTitle("Title"); + field.Title = "Product"; + field.Update(); + + expectedShipmentsList.Fields.AddFieldAsXml("", + true, + AddFieldOptions.DefaultValue); + expectedShipmentsList.Fields.AddFieldAsXml("" + + "1", + true, + AddFieldOptions.DefaultValue); + expectedShipmentsList.Fields.AddFieldAsXml("" + + "FALSE", + true, + AddFieldOptions.DefaultValue); + expectedShipmentsList.Fields.AddFieldAsXml("" + + "FALSE", + true, + AddFieldOptions.DefaultValue); + + clientContext.ExecuteQuery(); + } + } + } + ``` This code doesn't introduce any functionality that you haven't already seen in a previous article of this series, but note the following: - + - It sets the **Required** attribute of the **Quantity** field to **TRUE** so the field must always have a value. It then sets the default value to 1. - - The **Arrived** and **Added to Inventory** fields are hidden on the New Item form. - - Ideally, the **Added to Inventory** field would also be hidden on the Edit Item form because it should only be changed to **Yes** when the item updated event handler has first added the item to the corporate **Inventory** table. For technical reasons that we'll explain in a later step, a field has to be visible in the Edit Item form if we want to programmatically write to it in an item updated event handler. +1. In the **DeployChainStoreComponentsToHostWeb** method, add the following line, just above the line `RemoteTenantVersion = localTenantVersion`. -2. In the **DeployChainStoreComponentsToHostWeb** method, add the following line, just above the line `RemoteTenantVersion = localTenantVersion`. - ```csharp - CreateExpectedShipmentsList(); + CreateExpectedShipmentsList(); ``` ## Create the list item event receiver > [!NOTE] -> If you have been working through this series of articles, you have already configured your development environment for debugging remote event receivers. If you have not done that, see [Configure the solution for event receiver debugging](handle-add-in-events-in-the-provider-hosted-add-in.md#RERDebug) before you go any further in this topic. +> If you have been working through this series of articles, you have already configured your development environment for debugging remote event receivers. If you have not done that, see [Configure the solution for event receiver debugging](handle-add-in-events-in-the-provider-hosted-add-in.md#configure-the-solution-for-event-receiver-debugging) before you go any further in this topic. The Office Developer Tools for Visual Studio includes a **Remote Event Receiver** item that can be added to a SharePoint Add-in solution. However, at the time this article was written, this project item assumes that the list (with which the receiver will be registered) is on the add-in web, and consequently the tools create an add-in web and some SharePoint artifacts in it. But the receiver for the Chain Store add-in is going to be registered (in a later step) with the **Expected Shipments** list on the host web, so the add-in does not need an add-in web. (For a reminder of the distinction between add-in webs and host webs, see [SharePoint Add-ins](sharepoint-add-ins.md).) - + > [!NOTE] > List and list item event receivers are called remote event receivers (RER) because their code is remote from SharePoint, either in the cloud or in an on-premises server outside the SharePoint farm. However, the events that trigger them are in SharePoint. 1. In **Solution Explorer**, right-click the **Services** folder in the **ChainStoreWeb** project, and select **Add** > **WCF Service**. +1. When prompted, name the service **RemoteEventReceiver1**, and then select **OK**. +1. The tools create an interface file, an \*.svc file, and a code-behind file. We don't need the interface file IRemoteEventReceiver1.cs, so delete it. (The tools may have opened it automatically; if so, close and delete it.) -2. When prompted, name the service **RemoteEventReceiver1**, and then select **OK**. - -3. The tools create an interface file, an \*.svc file, and a code-behind file. We don't need the interface file IRemoteEventReceiver1.cs, so delete it. (The tools may have opened it automatically; if so, close and delete it.) - > [!NOTE] > When you created the add-in event receivers for the installed and uninstalling events in an earlier article in this series, the Office Developer Tools for Visual Studio added their URLs to the app manifest file. List and list item event receivers are not registered in the app manifest. Instead, they are registered (in a provider-hosted add-in) programmatically. You'll do that in a later step. -4. Open the code-behind file RemoteEventReceiver1.svc.cs. Replace its entire contents with the following code. +1. Open the code-behind file RemoteEventReceiver1.svc.cs. Replace its entire contents with the following code. ```csharp - using System; - using System.Collections.Generic; - using Microsoft.SharePoint.Client; - using Microsoft.SharePoint.Client.EventReceivers; - using System.Data.SqlClient; - using System.Data; - using ChainStoreWeb.Utilities; - - namespace ChainStoreWeb.Services - { - public class RemoteEventReceiver1 : IRemoteEventService - { - /// - /// Handles events that occur before an action occurs, - /// such as when a user is adding or deleting a list item. - /// - /// Holds information about the remote event. - /// Holds information returned from the remote event. - public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) - { - throw new NotImplementedException(); - } - - /// - /// Handles events that occur after an action occurs, - /// such as after a user adds an item to a list or deletes an item from a list. - /// - /// Holds information about the remote event. - public void ProcessOneWayEvent(SPRemoteEventProperties properties) - { - - } - } - } + using System; + using System.Collections.Generic; + using Microsoft.SharePoint.Client; + using Microsoft.SharePoint.Client.EventReceivers; + using System.Data.SqlClient; + using System.Data; + using ChainStoreWeb.Utilities; + + namespace ChainStoreWeb.Services + { + public class RemoteEventReceiver1 : IRemoteEventService + { + /// + /// Handles events that occur before an action occurs, + /// such as when a user is adding or deleting a list item. + /// + /// Holds information about the remote event. + /// Holds information returned from the remote event. + public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties) + { + throw new NotImplementedException(); + } + + /// + /// Handles events that occur after an action occurs, + /// such as after a user adds an item to a list or deletes an item from a list. + /// + /// Holds information about the remote event. + public void ProcessOneWayEvent(SPRemoteEventProperties properties) + { + } + } + } ``` Note the following about this code: - + - The interface `IRemoteEventService` is defined in the **Microsoft.SharePoint.Client.EventReceivers** namespace. - - There won't be any "before" events handled in the Chain Store add-in, but the **ProcessEvent** method is required by the `IRemoteEventService` interface. -5. Add the following code to the **ProcessOneWayEvent** method. Note that the **ItemUpdated** event is the only one that this sample will handle, so we could have used a simple **if** structure instead of a **switch**. But event receivers typically handle multiple events, so we want you to see the pattern you'll most commonly be using in your event handlers as a SharePoint add-in developer. - +1. Add the following code to the **ProcessOneWayEvent** method. Note that the **ItemUpdated** event is the only one that this sample will handle, so we could have used a simple **if** structure instead of a **switch**. But event receivers typically handle multiple events, so we want you to see the pattern you'll most commonly be using in your event handlers as a SharePoint add-in developer. + ```csharp - switch (properties.EventType) - { - case SPRemoteEventType.ItemUpdated: + switch (properties.EventType) + { + case SPRemoteEventType.ItemUpdated: - // TODO12: Handle the item updated event. + // TODO12: Handle the item updated event. - break; - } + break; + } ``` -6. Replace `TODO12` with the following code. Again, here, we are using a **switch** structure when a simple **if** structure would do because we want you to see the common pattern in SharePoint event receivers. - +1. Replace `TODO12` with the following code. Again, here, we are using a **switch** structure when a simple **if** structure would do because we want you to see the common pattern in SharePoint event receivers. + ```csharp - switch (properties.ItemEventProperties.ListTitle) - { - case "Expected Shipments": + switch (properties.ItemEventProperties.ListTitle) + { + case "Expected Shipments": - // TODO13: Handle the arrival of a shipment. + // TODO13: Handle the arrival of a shipment. - break; - } + break; + } ``` -7. The code that responds to the arrival of a shipment should do two things: - +1. The code that responds to the arrival of a shipment should do two things: + - Add the item that has arrived at the store into the corporate inventory. - - Set the **Added to Inventory** field on the **Expected Shipments** list to **Yes**. But this should only happen if the item was successfully added to the inventory. - + Add the following code in place of `TODO13`. The two methods, `TryUpdateInventory` and `RecordInventoryUpdateLocally` are created in later steps. ```csharp - bool updateComplete = TryUpdateInventory(properties); - if (updateComplete) - { - RecordInventoryUpdateLocally(properties); - } + bool updateComplete = TryUpdateInventory(properties); + if (updateComplete) + { + RecordInventoryUpdateLocally(properties); + } ``` - -8. The **ProcessOneWayEvent** method should now look like the following: +1. The **ProcessOneWayEvent** method should now look like the following: ```csharp - public void ProcessOneWayEvent(SPRemoteEventProperties properties) - { - switch (properties.EventType) - { - case SPRemoteEventType.ItemUpdated: - - switch (properties.ItemEventProperties.ListTitle) - { - case "Expected Shipments": - bool updateComplete = UpdateInventory(properties); - if (updateComplete) - { - RecordInventoryUpdateLocally(properties); - } - break; - } - break; - } - } + public void ProcessOneWayEvent(SPRemoteEventProperties properties) + { + switch (properties.EventType) + { + case SPRemoteEventType.ItemUpdated: + + switch (properties.ItemEventProperties.ListTitle) + { + case "Expected Shipments": + bool updateComplete = UpdateInventory(properties); + if (updateComplete) + { + RecordInventoryUpdateLocally(properties); + } + break; + } + break; + } + } ``` -9. Add the following method to the `RemoteEventReceiver1` class. - +1. Add the following method to the `RemoteEventReceiver1` class. + ```csharp - private bool TryUpdateInventory(SPRemoteEventProperties properties) - { - bool successFlag = false; + private bool TryUpdateInventory(SPRemoteEventProperties properties) + { + bool successFlag = false; - // TODO14: Test whether the list item is changing because the product has arrived - // or for some other reason. If the former, add it to the inventory and set the success flag - // to true. + // TODO14: Test whether the list item is changing because the product has arrived + // or for some other reason. If the former, add it to the inventory and set the success flag + // to true. - return successFlag; - } + return successFlag; + } ``` -10. There are five columns on the **Expected Shipments** list, but we don't want the handler to react to most kinds of updates to an item. For example, if a user corrects the spelling of a supplier's name, the item updated event is triggered, but our handler should do nothing. The handler should only act when the **Arrived** field has just been set to **Yes**. - - There's another condition that needs to be tested. Suppose **Arrived** is set to **Yes** and the product in the item is added to inventory (and **Added to Inventory** is set to **Yes**). But later a user mistakenly changes the **Arrived** field of a shipment back to **No** and then fixes his mistake by setting it again to **Yes**. Both the mistake and the fix trigger the item updated event. The handler won't react to the mistake because it only acts when **Arrived** is **Yes**, but it would react to the fix that sets **Arrived** back to **Yes**, so the same product and quantity would get added into the inventory a second time. For this reason, the handler should only act when the **Added to Inventory** value is **No**. - +1. There are five columns on the **Expected Shipments** list, but we don't want the handler to react to most kinds of updates to an item. For example, if a user corrects the spelling of a supplier's name, the item updated event is triggered, but our handler should do nothing. The handler should only act when the **Arrived** field has just been set to **Yes**. + + There's another condition that needs to be tested. Suppose **Arrived** is set to **Yes** and the product in the item is added to inventory (and **Added to Inventory** is set to **Yes**). But later a user mistakenly changes the **Arrived** field of a shipment back to **No** and then fixes his mistake by setting it again to **Yes**. Both the mistake and the fix trigger the item updated event. The handler won't react to the mistake because it only acts when **Arrived** is **Yes**, but it would react to the fix that sets **Arrived** back to **Yes**, so the same product and quantity would get added into the inventory a second time. For this reason, the handler should only act when the **Added to Inventory** value is **No**. + Therefore, the handler needs to know what the values of these fields are just after the user updates the item. The **SPRemoteEventProperties** object has an **ItemEventProperties** property. And, in turn, it has an indexed **AfterProperties** property that holds the values of the fields in the updated item. The following code uses these properties to test whether the handler should react. Put this in place of `TODO14`. - ```csharp - var arrived = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Arrived"]); - var addedToInventory = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Added_x0020_to_x0020_Inventory"]); + ```csharp + var arrived = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Arrived"]); + var addedToInventory = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Added_x0020_to_x0020_Inventory"]); - if (arrived && !addedToInventory) - { + if (arrived && !addedToInventory) + { - // TODO15: Add the item to inventory + // TODO15: Add the item to inventory - successFlag = true; - } - ``` + successFlag = true; + } + ``` -11. Replace `TODO15` with the following code. +1. Replace `TODO15` with the following code. - ```csharp - using (SqlConnection conn = SQLAzureUtilities.GetActiveSqlConnection()) - using (SqlCommand cmd = conn.CreateCommand()) - { - conn.Open(); - cmd.CommandText = "UpdateInventory"; - cmd.CommandType = CommandType.StoredProcedure; - SqlParameter tenant = cmd.Parameters.Add("@Tenant", SqlDbType.NVarChar); - tenant.Value = properties.ItemEventProperties.WebUrl + "/"; - SqlParameter product = cmd.Parameters.Add("@ItemName", SqlDbType.NVarChar, 50); - product.Value = properties.ItemEventProperties.AfterProperties["Title"]; // not "Product" - SqlParameter quantity = cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt); - quantity.Value = Convert.ToUInt16(properties.ItemEventProperties.AfterProperties["Quantity"]); - cmd.ExecuteNonQuery(); - } - ``` + ```csharp + using (SqlConnection conn = SQLAzureUtilities.GetActiveSqlConnection()) + using (SqlCommand cmd = conn.CreateCommand()) + { + conn.Open(); + cmd.CommandText = "UpdateInventory"; + cmd.CommandType = CommandType.StoredProcedure; + SqlParameter tenant = cmd.Parameters.Add("@Tenant", SqlDbType.NVarChar); + tenant.Value = properties.ItemEventProperties.WebUrl + "/"; + SqlParameter product = cmd.Parameters.Add("@ItemName", SqlDbType.NVarChar, 50); + product.Value = properties.ItemEventProperties.AfterProperties["Title"]; // not "Product" + SqlParameter quantity = cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt); + quantity.Value = Convert.ToUInt16(properties.ItemEventProperties.AfterProperties["Quantity"]); + cmd.ExecuteNonQuery(); + } + ``` This is mainly SQL and ASP.NET programming, so we don't discuss it in detail, but note: - - - We use the **ItemEventProperties.WebUrl** property to get the tenant name, which is the host web URL. + - We use the **ItemEventProperties.WebUrl** property to get the tenant name, which is the host web URL. - We use the **AfterProperties** again to get the values of the product name and quantity. - - We refer to the product name field as "Title", even though the display name was changed to "Product" (in the **CreateExpectedShipmentsList** method) because fields are always referred to by their internal names. - -12. We are not finished with the **TryUpdateInventory** method yet, but at this point it should look like the following. - - ```csharp - private bool TryUpdateInventory(SPRemoteEventProperties properties) - { - bool successFlag = false; - - var arrived = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Arrived"]); - var addedToInventory = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Added_x0020_to_x0020_Inventory"]); - - if (arrived && !addedToInventory) - { - using (SqlConnection conn = SQLAzureUtilities.GetActiveSqlConnection()) - using (SqlCommand cmd = conn.CreateCommand()) - { - conn.Open(); - cmd.CommandText = "UpdateInventory"; - cmd.CommandType = CommandType.StoredProcedure; - SqlParameter tenant = cmd.Parameters.Add("@Tenant", SqlDbType.NVarChar); - tenant.Value = properties.ItemEventProperties.WebUrl + "/"; - SqlParameter product = cmd.Parameters.Add("@ItemName", SqlDbType.NVarChar, 50); - product.Value = properties.ItemEventProperties.AfterProperties["Title"]; // not "Product" - SqlParameter quantity = cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt); - quantity.Value = Convert.ToUInt16(properties.ItemEventProperties.AfterProperties["Quantity"]); - cmd.ExecuteNonQuery(); - } - successFlag = true; - } - return successFlag; - } - ``` +1. We are not finished with the **TryUpdateInventory** method yet, but at this point it should look like the following. + + ```csharp + private bool TryUpdateInventory(SPRemoteEventProperties properties) + { + bool successFlag = false; + + var arrived = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Arrived"]); + var addedToInventory = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Added_x0020_to_x0020_Inventory"]); + + if (arrived && !addedToInventory) + { + using (SqlConnection conn = SQLAzureUtilities.GetActiveSqlConnection()) + using (SqlCommand cmd = conn.CreateCommand()) + { + conn.Open(); + cmd.CommandText = "UpdateInventory"; + cmd.CommandType = CommandType.StoredProcedure; + SqlParameter tenant = cmd.Parameters.Add("@Tenant", SqlDbType.NVarChar); + tenant.Value = properties.ItemEventProperties.WebUrl + "/"; + SqlParameter product = cmd.Parameters.Add("@ItemName", SqlDbType.NVarChar, 50); + product.Value = properties.ItemEventProperties.AfterProperties["Title"]; // not "Product" + SqlParameter quantity = cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt); + quantity.Value = Convert.ToUInt16(properties.ItemEventProperties.AfterProperties["Quantity"]); + cmd.ExecuteNonQuery(); + } + successFlag = true; + } + return successFlag; + } + ``` + +1. When the **TryUpdateInventory** method returns **true**, our handler calls a method (not yet written) that updates the same item in the **Expected Shipments** list by setting the **Added to Inventory** field to **Yes**. This is itself an item update event, so the handler is called again. (The fact that the **Added to Inventory** field is now **Yes** prevents the handler from adding the same shipment to inventory a second time, but the handler is still called.) + + SharePoint behaves a little differently when the item updated event is triggered by a programmatic update: *it only includes in the __AfterProperties__ the fields that changed in the update.* So the **Arrived** field won't be present because only the **Added to Inventory** field changed. -13. When the **TryUpdateInventory** method returns **true**, our handler calls a method (not yet written) that updates the same item in the **Expected Shipments** list by setting the **Added to Inventory** field to **Yes**. This is itself an item update event, so the handler is called again. (The fact that the **Added to Inventory** field is now **Yes** prevents the handler from adding the same shipment to inventory a second time, but the handler is still called.) - - SharePoint behaves a little differently when the item updated event is triggered by a programmatic update: *it only includes in the __AfterProperties__ the fields that changed in the update.* So the **Arrived** field won't be present because only the **Added to Inventory** field changed. - The line... - + `var arrived = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Arrived"]);` - - ...throws a **KeyNotFoundException**. - + + ...throws a **KeyNotFoundException**. + There is more than one way to resolve this problem. In this sample we are going to catch the exception and use the **catch** block to ensure that the `successFlag` is set to **false**. Doing this ensures that the item isn't updated a third time. - + Put everything in the method that is between the first line `bool successFlag = false;` and the last line `return successFlag;` in a **try** block. - -14. Add the following **catch** block just under the **try** block. - - ```csharp - catch (KeyNotFoundException) - { - successFlag = false; - } - ``` + +1. Add the following **catch** block just under the **try** block. + + ```csharp + catch (KeyNotFoundException) + { + successFlag = false; + } + ``` > [!NOTE] > The **KeyNotFoundException** is also the reason why we have to leave the **Added to Inventory** field visible on the Edit Item form. SharePoint does not include fields that are hidden on the Edit Item form in **AfterProperties**. -15. The entire method should now look like the following. +1. The entire method should now look like the following. - ```csharp - private bool TryUpdateInventory(SPRemoteEventProperties properties) - { - bool successFlag = false; - - try - { - var arrived = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Arrived"]); - var addedToInventory = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Added_x0020_to_x0020_Inventory"]); - - if (arrived && !addedToInventory) - { - using (SqlConnection conn = SQLAzureUtilities.GetActiveSqlConnection()) - using (SqlCommand cmd = conn.CreateCommand()) - { - conn.Open(); - cmd.CommandText = "UpdateInventory"; - cmd.CommandType = CommandType.StoredProcedure; - SqlParameter tenant = cmd.Parameters.Add("@Tenant", SqlDbType.NVarChar); - tenant.Value = properties.ItemEventProperties.WebUrl + "/"; - SqlParameter product = cmd.Parameters.Add("@ItemName", SqlDbType.NVarChar, 50); - product.Value = properties.ItemEventProperties.AfterProperties["Title"]; // not "Product" - SqlParameter quantity = cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt); - quantity.Value = Convert.ToUInt16(properties.ItemEventProperties.AfterProperties["Quantity"]); - cmd.ExecuteNonQuery(); - } - successFlag = true; - } - } - catch (KeyNotFoundException) - { - successFlag = false; - } - return successFlag; - } - ``` + ```csharp + private bool TryUpdateInventory(SPRemoteEventProperties properties) + { + bool successFlag = false; + + try + { + var arrived = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Arrived"]); + var addedToInventory = Convert.ToBoolean(properties.ItemEventProperties.AfterProperties["Added_x0020_to_x0020_Inventory"]); + + if (arrived && !addedToInventory) + { + using (SqlConnection conn = SQLAzureUtilities.GetActiveSqlConnection()) + using (SqlCommand cmd = conn.CreateCommand()) + { + conn.Open(); + cmd.CommandText = "UpdateInventory"; + cmd.CommandType = CommandType.StoredProcedure; + SqlParameter tenant = cmd.Parameters.Add("@Tenant", SqlDbType.NVarChar); + tenant.Value = properties.ItemEventProperties.WebUrl + "/"; + SqlParameter product = cmd.Parameters.Add("@ItemName", SqlDbType.NVarChar, 50); + product.Value = properties.ItemEventProperties.AfterProperties["Title"]; // not "Product" + SqlParameter quantity = cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt); + quantity.Value = Convert.ToUInt16(properties.ItemEventProperties.AfterProperties["Quantity"]); + cmd.ExecuteNonQuery(); + } + successFlag = true; + } + } + catch (KeyNotFoundException) + { + successFlag = false; + } + return successFlag; + } + ``` -16. Add the following method to the `RemoteEventReceiver1` class. +1. Add the following method to the `RemoteEventReceiver1` class. ```csharp - private void RecordInventoryUpdateLocally(SPRemoteEventProperties properties) - { - using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties)) - { - List expectedShipmentslist = clientContext.Web.Lists.GetByTitle(properties.ItemEventProperties.ListTitle); - ListItem arrivedItem = expectedShipmentslist.GetItemById(properties.ItemEventProperties.ListItemId); - arrivedItem["Added_x0020_to_x0020_Inventory"] = true; - arrivedItem.Update(); - clientContext.ExecuteQuery(); - } - } + private void RecordInventoryUpdateLocally(SPRemoteEventProperties properties) + { + using (ClientContext clientContext = TokenHelper.CreateRemoteEventReceiverClientContext(properties)) + { + List expectedShipmentslist = clientContext.Web.Lists.GetByTitle(properties.ItemEventProperties.ListTitle); + ListItem arrivedItem = expectedShipmentslist.GetItemById(properties.ItemEventProperties.ListItemId); + arrivedItem["Added_x0020_to_x0020_Inventory"] = true; + arrivedItem.Update(); + clientContext.ExecuteQuery(); + } + } ``` By now this pattern of code is familiar from earlier articles in this series. But note one difference: - - - The code gets the **ClientContext** object by calling **TokenHelper.CreateRemoteEventReceiverClientContext** method instead of the **SharePointContext.CreateUserClientContextForSPHost** method as we used in code that called into SharePoint from pages, such as the EmployeeAdder page. - + + - The code gets the **ClientContext** object by calling **TokenHelper.CreateRemoteEventReceiverClientContext** method instead of the **SharePointContext.CreateUserClientContextForSPHost** method as we used in code that called into SharePoint from pages, such as the EmployeeAdder page. - The primary reason for having different methods to get a **ClientContext** object is that SharePoint passes the information needed to create such objects differently to event receivers from how it passes it to pages. For event receivers, it passes an **SPRemoteEventProperties** object, but for pages it passes a special field, called a context token, in the body of the request that launches the add-in page. -17. Save and close the receiver code file. - +1. Save and close the receiver code file. + ## Register the receiver The final task is to tell SharePoint that we have a custom receiver that we want SharePoint to call whenever an item on the **Expected Shipments** list is updated. 1. Open the SharePointContentDeployer.cs file and add the following line to the **DeployChainStoreComponentsToHostWeb** method, just under the line that creates the **Expected Shipments** list (we'll add this method in the next step). Note that we are passing to the method the **HttpRequest** object that the add-in's start page passed to the **DeployChainStoreComponentsToHostWeb** method. - + ```csharp - RegisterExpectedShipmentsEventHandler(request); + RegisterExpectedShipmentsEventHandler(request); ``` -2. Add the following method to the `SharePointComponentDeployer` class. - +1. Add the following method to the `SharePointComponentDeployer` class. + ```csharp - private static void RegisterExpectedShipmentsEventHandler(HttpRequest request) - { - using (var clientContext = sPContext.CreateUserClientContextForSPHost()) - { - var query = from list in clientContext.Web.Lists - where list.Title == "Expected Shipments" - select list; - IEnumerable matchingLists = clientContext.LoadQuery(query); - clientContext.ExecuteQuery(); - - List expectedShipmentsList = matchingLists.Single(); - - // TODO16: Add the event receiver to the list's collection of event receivers. - - clientContext.ExecuteQuery(); - } - } + private static void RegisterExpectedShipmentsEventHandler(HttpRequest request) + { + using (var clientContext = sPContext.CreateUserClientContextForSPHost()) + { + var query = from list in clientContext.Web.Lists + where list.Title == "Expected Shipments" + select list; + IEnumerable matchingLists = clientContext.LoadQuery(query); + clientContext.ExecuteQuery(); + + List expectedShipmentsList = matchingLists.Single(); + + // TODO16: Add the event receiver to the list's collection of event receivers. + + clientContext.ExecuteQuery(); + } + } ``` -3. Replace `TODO16` with the following lines. Note that there is a lightweight **CreationInformation** class for event receivers just as there is for lists and list items. - - ```csharp - EventReceiverDefinitionCreationInformation receiver = new EventReceiverDefinitionCreationInformation(); - receiver.ReceiverName = "ExpectedShipmentsItemUpdated"; - receiver.EventType = EventReceiverType.ItemUpdated; +1. Replace `TODO16` with the following lines. Note that there is a lightweight **CreationInformation** class for event receivers just as there is for lists and list items. - // TODO17: Set the URL of the receiver. + ```csharp + EventReceiverDefinitionCreationInformation receiver = new EventReceiverDefinitionCreationInformation(); + receiver.ReceiverName = "ExpectedShipmentsItemUpdated"; + receiver.EventType = EventReceiverType.ItemUpdated; - expectedShipmentsList.EventReceivers.Add(receiver); + // TODO17: Set the URL of the receiver. + expectedShipmentsList.EventReceivers.Add(receiver); ``` -4. Now you need to tell SharePoint the URL of the event receiver. In production, it's going to be at the same domain as the remote pages, with the path of /Services/RemoteEventReceiver1.svc. Because the handler is being registered in first-run logic from the add-in's start page, the domain is in the host header of the **HttpRequest** object for the request that called the page. Our code has passed that object from the page to the **DeployChainStoreComponentsToHostWeb** method, which itself passed it to the **RegisterExpectedShipmentsEventHandler** method. So we can set the receiver's URL with the following code. - +1. Now you need to tell SharePoint the URL of the event receiver. In production, it's going to be at the same domain as the remote pages, with the path of /Services/RemoteEventReceiver1.svc. Because the handler is being registered in first-run logic from the add-in's start page, the domain is in the host header of the **HttpRequest** object for the request that called the page. Our code has passed that object from the page to the **DeployChainStoreComponentsToHostWeb** method, which itself passed it to the **RegisterExpectedShipmentsEventHandler** method. So we can set the receiver's URL with the following code. + `receiver.ReceiverUrl = "https://" + request.Headers["Host"] + "/Services/RemoteEventReceiver1.svc";` - - Unfortunately, this won't work when you are debugging the add-in from Visual Studio. When you are debugging, the receiver is hosted in the Azure Service Bus, not in the localhost URL where the remote pages are hosted. We need to set distinct URLs for the receiver depending on whether we are debugging or not, so replace `TODO17` with the following structure that uses C# compiler directives. Note that in debug mode the receiver's URL is read from a web.config setting (you will create this setting in a later step). - ```csharp - #if DEBUG - receiver.ReceiverUrl = WebConfigurationManager.AppSettings["RERdebuggingServiceBusUrl"].ToString(); - #else - receiver.ReceiverUrl = "https://" + request.Headers["Host"] + "/Services/RemoteEventReceiver1.svc"; - #endif + Unfortunately, this won't work when you are debugging the add-in from Visual Studio. When you are debugging, the receiver is hosted in the Azure Service Bus, not in the localhost URL where the remote pages are hosted. We need to set distinct URLs for the receiver depending on whether we are debugging or not, so replace `TODO17` with the following structure that uses C# compiler directives. Note that in debug mode the receiver's URL is read from a web.config setting (you will create this setting in a later step). + ```csharp + #if DEBUG + receiver.ReceiverUrl = WebConfigurationManager.AppSettings["RERdebuggingServiceBusUrl"].ToString(); + #else + receiver.ReceiverUrl = "https://" + request.Headers["Host"] + "/Services/RemoteEventReceiver1.svc"; + #endif ``` +1. The entire **RegisterExpectedShipmentsEventHandler** method should now look like the following. -5. The entire **RegisterExpectedShipmentsEventHandler** method should now look like the following. - ```csharp - private static void RegisterExpectedShipmentsEventHandler(HttpRequest request) - { - using (var clientContext = sPContext.CreateUserClientContextForSPHost()) - { - var query = from list in clientContext.Web.Lists - where list.Title == "Expected Shipments" - select list; - IEnumerable matchingLists = clientContext.LoadQuery(query); - clientContext.ExecuteQuery(); - - List expectedShipmentsList = matchingLists.Single(); - - EventReceiverDefinitionCreationInformation receiver = new EventReceiverDefinitionCreationInformation(); - receiver.ReceiverName = "ExpectedShipmentsItemUpdated"; - receiver.EventType = EventReceiverType.ItemUpdated; - - #if DEBUG - receiver.ReceiverUrl = WebConfigurationManager.AppSettings["RERdebuggingServiceBusUrl"].ToString(); - #else - receiver.ReceiverUrl = "https://" + request.Headers["Host"] + "/Services/RemoteEventReceiver1.svc"; - #endif - expectedShipmentsList.EventReceivers.Add(receiver); - clientContext.ExecuteQuery(); - } - } + private static void RegisterExpectedShipmentsEventHandler(HttpRequest request) + { + using (var clientContext = sPContext.CreateUserClientContextForSPHost()) + { + var query = from list in clientContext.Web.Lists + where list.Title == "Expected Shipments" + select list; + IEnumerable matchingLists = clientContext.LoadQuery(query); + clientContext.ExecuteQuery(); + + List expectedShipmentsList = matchingLists.Single(); + + EventReceiverDefinitionCreationInformation receiver = new EventReceiverDefinitionCreationInformation(); + receiver.ReceiverName = "ExpectedShipmentsItemUpdated"; + receiver.EventType = EventReceiverType.ItemUpdated; + + #if DEBUG + receiver.ReceiverUrl = WebConfigurationManager.AppSettings["RERdebuggingServiceBusUrl"].ToString(); + #else + receiver.ReceiverUrl = "https://" + request.Headers["Host"] + "/Services/RemoteEventReceiver1.svc"; + #endif + + expectedShipmentsList.EventReceivers.Add(receiver); + clientContext.ExecuteQuery(); + } + } ``` -6. Add the following **using** statement to the top of the file. - +1. Add the following **using** statement to the top of the file. + ```csharp - using System.Web.Configuration; + using System.Web.Configuration; ``` -7. To ensure that `DEBUG` is true if and only if the add-in is being debugged, carry out the following subprocedure: - +1. To ensure that `DEBUG` is true if and only if the add-in is being debugged, carry out the following subprocedure: + 1. In **Solution Explorer**, right-click the **ChainStoreWeb** project and select **Properties**. - - 2. Open the **Build** tab of the **Properties**, and then select **Debug** from the **Configuration** drop-down at the top. - - 3. Ensure that the **Define DEBUG constant** check box is selected (it usually is by default). The following screen shot shows the proper setting. + 1. Open the **Build** tab of the **Properties**, and then select **Debug** from the **Configuration** drop-down at the top. + 1. Ensure that the **Define DEBUG constant** check box is selected (it usually is by default). The following screen shot shows the proper setting. *Figure 1. Build sub-tab of the Properties tab in Visual Studio* ![The Build sub-tab of the Properties tab in Visual Studio. The Configuration drop-down is set to Debug. The check box for "Define DEBUG constant" is selected.](../images/4f81174f-d875-4a9e-bff4-adea0f176f00.PNG) - 4. Change the **Configuration** drop-down to **Release**, and then ensure that the **Define DEBUG constant** check box is *not* selected (it usually is not by default). The following screenshot shows the proper setting. - + 1. Change the **Configuration** drop-down to **Release**, and then ensure that the **Define DEBUG constant** check box is *not* selected (it usually is not by default). The following screenshot shows the proper setting. + *Figure 2. Build sub-tab of the Properties tab with check box cleared* ![The Build sub-tab of the Properties tab. The Configuration drop down says Release. The check box for "Define DEBUG constant" is not checked.](../images/7fd942de-a324-4f70-a750-f5304c993832.PNG) - 5. If you made any changes, save and then close the **Properties** tab. - - -8. Open the web.config file, and add the following markup as a child of the **appSettings** element (we get the value of the setting in the next section). - + 1. If you made any changes, save and then close the **Properties** tab. + +1. Open the web.config file, and add the following markup as a child of the **appSettings** element (we get the value of the setting in the next section). + ```XML - + ``` ## Get the receiver URL for debugging -The add-in event and list item event receivers are Windows Communication Service (WCF) services, and every WCF service knows its own endpoint and stores it in multiple places, including the **System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri** object. +The add-in event and list item event receivers are Windows Communication Service (WCF) services, and every WCF service knows its own endpoint and stores it in multiple places, including the **System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri** object. When you are debugging, the add-in receiver is hosted at an Azure Service Bus endpoint that is almost the same as the endpoint for the list item receiver. The difference is that the URL of the add-in endpoint ends with "AppEventReceiver.svc", but the list item receiver's URL ends with "RemoteEventReceiver1.svc." So we can get the URL of the endpoint in the add-in receiver, make a small change to the end of it, and then use it as the value of our web.config **RERdebuggingServiceBusUrl** setting. 1. Open the AppEventReceiver.svc.cs file in the **Services** folder of the **ChainStoreWeb** project. +1. Add the following as the very first line in the **ProcessEvent** method. -2. Add the following as the very first line in the **ProcessEvent** method. - ```csharp - string debugEndpoint = System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri.ToString(); + string debugEndpoint = System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri.ToString(); ``` -3. Add a breakpoint to the very next line of the method. - -4. Select F5 to debug the add-in. Because web.config is open and Office Developer Tools for Visual Studio changes a setting in it every time you select F5, you are prompted to reload it. Select **Yes**. - -5. When the breakpoint is hit, hover the cursor over the `debugEndpoint` variable. When the Visual Studio Data Tip appears, select the down arrow, and then select **Text Visualizer**. - - *Figure 3. Visual Studio text visualizer with an Azure Service Bus URL* +1. Add a breakpoint to the very next line of the method. +1. Select F5 to debug the add-in. Because web.config is open and Office Developer Tools for Visual Studio changes a setting in it every time you select F5, you are prompted to reload it. Select **Yes**. +1. When the breakpoint is hit, hover the cursor over the `debugEndpoint` variable. When the Visual Studio Data Tip appears, select the down arrow, and then select **Text Visualizer**. - ![A Visual Studio text visualizer with an Azure Service Bus URL in it.](../images/494cf01e-3e17-4092-b239-9312ac4ab258.PNG) + *Figure 3. Visual Studio text visualizer with an Azure Service Bus URL* -6. Copy the string value from the visualizer and paste it somewhere. + ![A Visual Studio text visualizer with an Azure Service Bus URL in it.](../images/494cf01e-3e17-4092-b239-9312ac4ab258.PNG) -7. Close the visualizer, and then stop debugging in Visual Studio. - -8. Delete or comment out the line you added in the second step of this procedure, and then delete the breakpoint as well. - -9. In the string you copied, replace the "AppEventReceiver.svc" at the end with "RemoteEventReceiver1.svc". - -10. Copy and paste the modified URL as the value of the **RERdebuggingServiceBusUrl** key in the web.config file. +1. Copy the string value from the visualizer and paste it somewhere. +1. Close the visualizer, and then stop debugging in Visual Studio. +1. Delete or comment out the line you added in the second step of this procedure, and then delete the breakpoint as well. +1. In the string you copied, replace the "AppEventReceiver.svc" at the end with "RemoteEventReceiver1.svc". +1. Copy and paste the modified URL as the value of the **RERdebuggingServiceBusUrl** key in the web.config file. > [!NOTE] -> Manually copying the service bus URL and pasting (a modified version of) it into the web.config is not the only way of dealing with the need for a different URL when debugging a remote event receiver when it is running in production. We could programmatically store the value of **System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri** somewhere in SharePoint or the remote database, and then have our first-run code read it and assign it to the `receiver.ReceiverUrl` property. We could register the list item event receiver as part of the add-in installed event handler. We could then programmatically read **System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri**, modify it, and assign it to `receiver.ReceiverUrl` without having to store it anywhere. +> Manually copying the service bus URL and pasting (a modified version of) it into the web.config is not the only way of dealing with the need for a different URL when debugging a remote event receiver when it is running in production. We could programmatically store the value of **System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri** somewhere in SharePoint or the remote database, and then have our first-run code read it and assign it to the `receiver.ReceiverUrl` property. We could register the list item event receiver as part of the add-in installed event handler. We could then programmatically read **System.ServiceModel.OperationContext.Current.Channel.LocalAddress.Uri**, modify it, and assign it to `receiver.ReceiverUrl` without having to store it anywhere. > -> This strategy requires that the **Expected Shipments** list also be created in the add-in installed event handler because it would have to exist before the handler could be registered with it. +> This strategy requires that the **Expected Shipments** list also be created in the add-in installed event handler because it would have to exist before the handler could be registered with it. > > Note also that we could combine our add-in event receiver and list item event receiver into a single receiver (that is, the same .svc and .svc.cs files). In that case, no modification of the URL is necessary before using it as the value of `receiver.ReceiverUrl`. ## Run the add-in and test the list item receiver -1. Open the **Site Contents** page of the Hong Kong SAR store's website, and remove the **Expected Shipments** list if there is one. - -2. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. - -3. When the add-in's start page opens, select the **Back to Site** button on the chrome control at the top. - -4. From the home page of the Hong Kong SAR store, go to the **Site Contents** page and open the **Expected Shipments** list. - -5. Create an item, and on the new item form, notice that the **Arrived** and **Added to Inventory** fields do not appear. - -6. After the item is created, reopen it for editing. Select the **Arrived** check box and save the item. This triggers the item updated event. The item is added to inventory and the value of the **Added to Inventory** field changes to **Yes** (you may have to refresh the page to see the change to **Added to Inventory**). - -7. Use the browser's back button until you are back at the start page for the Chain Store add-in, and then select the **Show Inventory** button. The item you marked as **Arrived** is now listed. - -8. Go back to the **Expected Shipments** list and add another item *with exactly the same product name and supplier name*, but a different quantity. - -9. After the item is created, reopen it for editing. Change the value of **Arrived** to **Yes** and save the item. - -10. Use the browser's back button until you are back at the start page for the Chain Store add-in, and then select the **Show Inventory** button. There is still just one item for the product name and supplier, but the quantity is now the total of the two items on the **Expected Shipments** list. - -11. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. - -12. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. +1. Open the **Site Contents** page of the Hong Kong SAR store's website, and remove the **Expected Shipments** list if there is one. +1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. When the add-in's start page opens, select the **Back to Site** button on the chrome control at the top. +1. From the home page of the Hong Kong SAR store, go to the **Site Contents** page and open the **Expected Shipments** list. +1. Create an item, and on the new item form, notice that the **Arrived** and **Added to Inventory** fields do not appear. +1. After the item is created, reopen it for editing. Select the **Arrived** check box and save the item. This triggers the item updated event. The item is added to inventory and the value of the **Added to Inventory** field changes to **Yes** (you may have to refresh the page to see the change to **Added to Inventory**). +1. Use the browser's back button until you are back at the start page for the Chain Store add-in, and then select the **Show Inventory** button. The item you marked as **Arrived** is now listed. +1. Go back to the **Expected Shipments** list and add another item *with exactly the same product name and supplier name*, but a different quantity. +1. After the item is created, reopen it for editing. Change the value of **Arrived** to **Yes** and save the item. +1. Use the browser's back button until you are back at the start page for the Chain Store add-in, and then select the **Show Inventory** button. There is still just one item for the product name and supplier, but the quantity is now the total of the two items on the **Expected Shipments** list. +1. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. +1. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. ## Next steps - To learn how to publish your add-in to a SharePoint site, see [Deploying and installing SharePoint Add-ins: methods and options](deploying-and-installing-sharepoint-add-ins-methods-and-options.md). You can also pursue advanced work in SharePoint add-in development on the following pages: -- [Design SharePoint Add-ins](design-sharepoint-add-ins.md) -- [Develop SharePoint Add-ins](develop-sharepoint-add-ins.md) -- [Publish SharePoint Add-ins](publish-sharepoint-add-ins.md) -- [Tools and environments for developing SharePoint Add-ins](tools-and-environments-for-developing-sharepoint-add-ins.md) - - - +- [Design SharePoint Add-ins](design-sharepoint-add-ins.md) +- [Develop SharePoint Add-ins](develop-sharepoint-add-ins.md) +- [Publish SharePoint Add-ins](publish-sharepoint-add-ins.md) +- [Tools and environments for developing SharePoint Add-ins](tools-and-environments-for-developing-sharepoint-add-ins.md) diff --git a/docs/sp-add-ins/handle-security-tokens-in-provider-hosted-low-trust-sharepoint-add-ins.md b/docs/sp-add-ins/handle-security-tokens-in-provider-hosted-low-trust-sharepoint-add-ins.md index 691e8f0fd..49516ef0d 100644 --- a/docs/sp-add-ins/handle-security-tokens-in-provider-hosted-low-trust-sharepoint-add-ins.md +++ b/docs/sp-add-ins/handle-security-tokens-in-provider-hosted-low-trust-sharepoint-add-ins.md @@ -1,7 +1,7 @@ --- title: Handle security tokens in provider-hosted low-trust SharePoint Add-ins description: The context, access, and refresh tokens that are used for authorization by low-trust, provider-hosted SharePoint Add-ins, and how to work with them in your code. -ms.date: 09/26/2023 +ms.date: 05/01/2025 ms.localizationpriority: high ms.service: sharepoint --- @@ -24,7 +24,7 @@ There are different flows depending on the design of the add-in, but all of them Depending on which OAuth flow the add-in is using, one or the other of the following is also part of the process: -- **Context token**. Used, in the Context Token flow, to provide the remote component with a refresh token and with information that it needs to request an access token from Azure ACS. +- **Context token**. Used in the Context Token flow, to provide the remote component with a refresh token and with information that it needs to request an access token from Azure ACS. - **Authorization code**. Not a token, but an authorization code, unique to each pair of user and application. It's used in the Authorization Code flow to obtain a first access token and a refresh token. ## Access tokens @@ -45,12 +45,12 @@ Depending on your SharePoint Add-in's architecture and the hosting platform, the - In session state - In application state - In [Windows Server AppFabric Caching](/previous-versions/appfabric/ff383731(v=azure.10)) or its equivalent in a non-Microsoft operating system -- In the [Microsoft Azure Caching Service](/azure/redis-cache/cache-faq) or its equivalent in a non-Microsoft cloud service +- In the [Microsoft Azure Caching Service](/azure/redis/faq) or its equivalent in a non-Microsoft cloud service - In a database - In a [memcached](http://www.memcached.org/) system > [!NOTE] -> In most scenarios, you won't be able to use terms as simple as "AccessToken" as the caching key because your add-in must keep the tokens for different users and SharePoint farms/tenancies distinct. If your add-in uses the [Context Token flow](context-token-oauth-flow-for-sharepoint-add-ins.md), there's special **CacheKey** provided by SharePoint that can be used to distinguish cached tokens. This section explains what the issues are and what to do when your application isn't using the Context Token flow. +> In most scenarios, you won't be able to use terms as simple as "AccessToken" as the caching key because your add-in must keep the tokens for different users and SharePoint farms/tenancies distinct. If your add-in uses the [Context Token flow](context-token-oauth-flow-for-sharepoint-add-ins.md), there's a special **CacheKey** provided by SharePoint that can be used to distinguish cached tokens. This section explains what the issues are and what to do when your application isn't using the Context Token flow. Caching the access token in **session state** is fine for most scenarios. If the remote web application is accessing other services that use OAuth (in addition to SharePoint) and its caching the various access tokens in session state, be sure to use distinct cache keys for the tokens; for example, instead of "AccessToken", use "SharePoint\_AccessToken", "Facebook\_AccessToken", "SAP\_Gateway\_AccessToken", and so on. (If you're not using session state or some other caching that automatically separates each user's cache, you need to relativize your keys for users.) diff --git a/docs/sp-add-ins/include-a-custom-button-in-the-provider-hosted-add-in.md b/docs/sp-add-ins/include-a-custom-button-in-the-provider-hosted-add-in.md index 69b2c72da..1839bed8e 100644 --- a/docs/sp-add-ins/include-a-custom-button-in-the-provider-hosted-add-in.md +++ b/docs/sp-add-ins/include-a-custom-button-in-the-provider-hosted-add-in.md @@ -5,13 +5,11 @@ ms.date: 09/26/2023 ms.localizationpriority: medium ms.service: sharepoint --- - - # Include a custom button in the provider-hosted add-in [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the third in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). +This is the third in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeRibbonButton.sln file. @@ -22,8 +20,8 @@ A SharePoint Add-in can include custom actions, which is the SharePoint term for The custom button is going to be on the ribbon of a specific list that records the employees of the local store. In a later article in this series, you'll learn how to programmatically add a custom list to a host website, but for now you'll add one manually. -1. From the home page of the Fabrikam Hong Kong SAR Store, go to **Site Contents** > **Add an add-in** > **Custom List**. -1. In the **Adding Custom List** dialog, specify **Local Employees** as the name, and then select **Create**. +1. From the home page of the Fabrikam Hong Kong SAR Store, go to **Site Contents** > **Add an add-in** > **Custom List**. +1. In the **Adding Custom List** dialog, specify **Local Employees** as the name, and then select **Create**. 1. On the **Site Contents** page, open the **Local Employees** list. 1. On the **List** tab on the ribbon, select **List Settings**. 1. In the **Columns** section of the **List Settings** page, select the **Title** column. @@ -50,12 +48,12 @@ In this section, you include markup in the add-in that deploys a button to the l 1. If Visual Studio is open, you have to close it and reopen the Chain Store solution so that Visual Studio can discover your new list (run Visual Studio as an administrator). > [!NOTE] - > The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: + > The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: > - > 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. + > 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. > 1. Ensure that all three projects are set to **Start** in the **Action** column. -1. Right-click the **ChainStore** project in **Solution Explorer**, and then select **Add** > **New Item**. +1. Right-click the **ChainStore** project in **Solution Explorer**, and then select **Add** > **New Item**. 1. In the **Add New Item** dialog, select **Ribbon Custom Action**, name it **AddEmployeeToCorpDB**, and then select **Add**. 1. The dialog that opens asks three questions. Give the following answers: @@ -81,7 +79,7 @@ In this section, you include markup in the add-in that deploys a button to the l - The **CommandAction** attribute of the **CommandUIHandler** element begins with the placeholder `~remoteAppUrl`. This will be replaced with the URL of the remote web application when the button is deployed. - A few query parameters have been added to the **CommandAction** value with placeholder values in braces "{ }". These placeholders are resolved at runtime. Note that one of them is the ID of the list item that is selected by the user before she selects the custom button on the ribbon. -1. In the **ChainStoreWeb** project, open the **Pages/EmployeeAdder.aspx** file. Notice that it doesn't have any UI. The add-in is going to use this page as a kind of web service. This is possible because the ASP.NET **System.Web.UI.Page** class implements **System.Web.IHttpHandler** and because the **Page\_Load** event runs automatically when the page is requested. +1. In the **ChainStoreWeb** project, open the **Pages/EmployeeAdder.aspx** file. Notice that it doesn't have any UI. The add-in is going to use this page as a kind of web service. This is possible because the ASP.NET **System.Web.UI.Page** class implements **System.Web.IHttpHandler** and because the **Page\_Load** event runs automatically when the page is requested. 1. Open the code-behind file **Pages/EmployeeAdder.aspx.cs**. The method that adds the employee to the remote database, `AddLocalEmployeeToCorpDB`, is already present. It uses the **SharePointContext** object to get the host web's URL, which the add-in uses as its tenant discriminator. The first thing the **Page_Load** method needs to do is initialize this object. The object is created and cached in the Session when the add-in's start page loads, so add the following code to the **Page_Load** method. (The **SharePointContext** object is defined in the SharePointContext.cs file that the Office Developer Tools for Visual Studio generates when the add-in solution is created.) @@ -92,14 +90,14 @@ In this section, you include markup in the add-in that deploys a button to the l 1. The `AddLocalEmployeeToCorpDB` method takes the employee's name as a parameter, so add the following line to the **Page_Load** method. You'll create the `GetLocalEmployeeName` method in a later step. ```csharp - // Read from SharePoint + // Read from SharePoint string employeeName = GetLocalEmployeeName(); ``` 1. Under this line, add the call to the `AddLocalEmployeeToCorpDB` method. ```csharp - // Write to remote database + // Write to remote database AddLocalEmployeeToCorpDB(employeeName); ``` @@ -111,7 +109,7 @@ In this section, you include markup in the add-in that deploys a button to the l { ListItem localEmployee; - // TODO1: Initialize the localEmployee object by getting + // TODO1: Initialize the localEmployee object by getting // the item from SharePoint. return localEmployee["Title"].ToString(); @@ -160,7 +158,7 @@ In this section, you include markup in the add-in that deploys a button to the l private string GetLocalEmployeeName() { ListItem localEmployee; - + using (var clientContext = spContext.CreateUserClientContextForSPHost()) { List localEmployeesList = clientContext.Web.Lists.GetByTitle("Local Employees"); @@ -213,29 +211,29 @@ As you have seen, SharePoint prompts you to grant the add-in permissions to the ## Run the add-in and test the button -1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. This time the prompt has a drop-down where you select the list that the app needs to read as seen in the following screenshot. - +1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. This time the prompt has a drop-down where you select the list that the app needs to read as seen in the following screenshot. + *Figure 3. SharePoint add-in permission prompt* - + ![The SharePoint add-in permission prompt with the list named Local Employees selected in a drop-down that is labeled "Let it read items in the list"](../images/84e8b42c-4800-4947-acbd-21c6f096f4ea.PNG) 1. Select **Local Employees** from the list, and then select **Trust it**. 1. When the add-in's start page opens, select **Back to Site** on the chrome control at the top. 1. From the website's home page, go to **Site Contents** > **Local Employees**. The list view page opens. -1. Add a few employees to the list. *Do not select the __Added to Corporate DB__ check box.* +1. Add a few employees to the list. *Do not select the __Added to Corporate DB__ check box.* 1. On the ribbon, open the **Items** tab. In the **Actions** section of the tab is the custom button **Add to Corporate DB**. 1. Select an item in the list. The page and ribbon should look similar to the following. - *Figure 4. Local Employees list* + *Figure 4. Local Employees list* ![The Local Employees list. One item is highlighted. Above it is the ribbon, and a button named "Add To Corporate DB" is in the Actions section.](../images/797a5ceb-7291-4b62-8075-2bb6a1b8e8a1.PNG) 1. After selecting an item in the list, select **Add to Corporate DB**. 1. The page seems to reload because the **Page_Load** method of the EmployeeAdder page redirects back to it. -1. Use the browser's back button twice to go back to the add-in's start page. +1. Use the browser's back button twice to go back to the add-in's start page. 1. Select **Show Employees**, and the list of employees will be populated with the employee that you added. It should look similar to the following: - *Figure 5. Corporate employees list on the add-in start page* + *Figure 5. Corporate employees list on the add-in start page* ![The corporate employees list on the add-in start page showing the same employee that was selected in the earlier step.](../images/4a300a4e-f479-4f63-b536-6315c5d9ba4d.PNG) @@ -243,6 +241,5 @@ As you have seen, SharePoint prompts you to grant the add-in permissions to the 1. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. ## Next steps - In the next article, we'll take a brief break from coding to [get a quick overview of the SharePoint client-side object model](get-a-quick-overview-of-the-sharepoint-object-model.md). diff --git a/docs/sp-add-ins/include-an-add-in-part-in-the-provider-hosted-add-in.md b/docs/sp-add-ins/include-an-add-in-part-in-the-provider-hosted-add-in.md index e3dc11838..68cb08815 100644 --- a/docs/sp-add-ins/include-an-add-in-part-in-the-provider-hosted-add-in.md +++ b/docs/sp-add-ins/include-an-add-in-part-in-the-provider-hosted-add-in.md @@ -5,14 +5,12 @@ ms.date: 09/26/2023 ms.localizationpriority: medium ms.service: sharepoint --- - - # Include an add-in part in the provider-hosted add-in [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the sixth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). - +This is the sixth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). + > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeAdd-inPart.sln file. @@ -21,68 +19,57 @@ In this article, you add a special kind of web part called an add-in part to the ## Create the add-in part > [!NOTE] -> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: -> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. -> 2. Ensure that all three projects are set to **Start** in the **Action** column. +> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: +> +> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. +> 1. Ensure that all three projects are set to **Start** in the **Action** column. 1. In **Solution Explorer**, right-click the **ChainStore** project, and then select **Add** > **New Item**. - -2. Select **Client web part (Host Web)**, give it the name **Place Order**, and then select **Add**. ("Client web part" is another name for "add-in part".) - -3. On the next page of the wizard, select the second option: **Select or enter the URL of an existing webpage for the client web part content**. +1. Select **Client web part (Host Web)**, give it the name **Place Order**, and then select **Add**. ("Client web part" is another name for "add-in part".) +1. On the next page of the wizard, select the second option: **Select or enter the URL of an existing webpage for the client web part content**. +1. In the drop-down list, select the URL for the **OrderForm.aspx** page, and then select **Finish**. -4. In the drop-down list, select the URL for the **OrderForm.aspx** page, and then select **Finish**. - An elements.xml file that defines the add-in part is added to the project and opened. - -5. In the **ClientWebPart** element, change the following attributes to these values: - - |**Attribute**|**Value**| - |:-----|:-----| - |Title|Place Order| - |Description|Form to place an order| - |DefaultHeight|320| + +1. In the **ClientWebPart** element, change the following attributes to these values: + + | **Attribute** | **Value** | + | :------------ | :--------------------- | + | Title | Place Order | + | Description | Form to place an order | + | DefaultHeight | 320 | Leave all the other attributes with their defaults and save the file. - + ## Run the add-in and test the add-in part 1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. When the add-in's start page opens, the add-in has been deployed, and the **Place Order** add-in part is available for users to add to any web part area on any SharePoint page on the Hong Kong SAR store's website. Follow these steps to add it to the home page: -2. When the add-in's start page opens, the add-in has been deployed, and the **Place Order** add-in part is available for users to add to any web part area on any SharePoint page on the Hong Kong SAR store's website. Follow these steps to add it to the home page: - 1. Select **Back to Site** on the chrome control at the top of the start page to open the home page of the Hong Kong SAR store. - 2. On the ribbon, open the **Page** tab and select **Edit**. - 3. After the page is in edit mode, open the **Insert** tab on the ribbon, and then select **Add-in Part** (the button may still be called **App Part**). - 4. On the web part insertion control that opens, select the **Place Order** add-in part. The control looks similar to the following. + 1. On the ribbon, open the **Page** tab and select **Edit**. + 1. After the page is in edit mode, open the **Insert** tab on the ribbon, and then select **Add-in Part** (the button may still be called **App Part**). + 1. On the web part insertion control that opens, select the **Place Order** add-in part. The control looks similar to the following. *Figure 1. SharePoint's web part insertion control* ![SharePoint's web part insertion control. The part called "Place Order" is highlighted. Its name and description appears in a box at the right.](../images/aae61f89-2e9e-4808-8b0c-2439dad7c701.PNG) - 5. Select somewhere in one of the web part zones of the form to set the location where the add-in part will go. - 6. Select **Add** on the web part insertion control. The **Place Order** add-in part is added to the web part zone. - 7. On the ribbon, select **Save**. - -3. The order form now appears on the page, and it has the look-and-feel of the rest of the page. It should look like the following. - - *Figure 2. Place Order add-in part* + 1. Select somewhere in one of the web part zones of the form to set the location where the add-in part will go. + 1. Select **Add** on the web part insertion control. The **Place Order** add-in part is added to the web part zone. + 1. On the ribbon, select **Save**. - ![The Place Order add-in part on the page with text boxes for Product, Supplier, and Quantity. There is also a "Place Order" button.](../images/beae2e3c-c1f4-4334-8ab8-0c42252cb2a2.PNG) - -4. Enter values for **Supplier**, **Product**, and **Quantity**, and then select **Place Order**. Nothing appears to happen, but an order is entered in the corporate database. Optionally, you can empty the fields of the add-in part by refreshing the page. +1. The order form now appears on the page, and it has the look-and-feel of the rest of the page. It should look like the following. -5. Use the browser's back button until you are back at the Chain Store add-in's start page, and then select **Show Orders**. Your new order is listed. + *Figure 2. Place Order add-in part* -6. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. + ![The Place Order add-in part on the page with text boxes for Product, Supplier, and Quantity. There is also a "Place Order" button.](../images/beae2e3c-c1f4-4334-8ab8-0c42252cb2a2.PNG) -7. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. +1. Enter values for **Supplier**, **Product**, and **Quantity**, and then select **Place Order**. Nothing appears to happen, but an order is entered in the corporate database. Optionally, you can empty the fields of the add-in part by refreshing the page. +1. Use the browser's back button until you are back at the Chain Store add-in's start page, and then select **Show Orders**. Your new order is listed. +1. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. +1. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. ## Next steps - The add-in depends on two lists that you created manually; you don't want your users to have to do that. In the next article, you begin the process of automatically creating these lists. The first major step is to create custom handlers for the event of installing an add-in: [Handle add-in events in the provider-hosted add-in](handle-add-in-events-in-the-provider-hosted-add-in.md). - - - - diff --git a/docs/sp-add-ins/programmatically-deploy-a-custom-button-in-the-provider-hosted-add-in.md b/docs/sp-add-ins/programmatically-deploy-a-custom-button-in-the-provider-hosted-add-in.md index 780766c54..84c9972e9 100644 --- a/docs/sp-add-ins/programmatically-deploy-a-custom-button-in-the-provider-hosted-add-in.md +++ b/docs/sp-add-ins/programmatically-deploy-a-custom-button-in-the-provider-hosted-add-in.md @@ -5,13 +5,11 @@ ms.date: 09/26/2023 ms.localizationpriority: medium ms.service: sharepoint --- - - # Programmatically deploy a custom button in the provider-hosted add-in [!INCLUDE [sp-add-in-deprecation](../../includes/snippets/sp-add-in-deprecation.md)] -This is the ninth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#SP15createprovider_nextsteps). +This is the ninth in a series of articles about the basics of developing provider-hosted SharePoint Add-ins. You should first be familiar with [SharePoint Add-ins](sharepoint-add-ins.md) and the previous articles in this series, which you can find at [Get started creating provider-hosted SharePoint Add-ins](get-started-creating-provider-hosted-sharepoint-add-ins.md#next-steps). > [!NOTE] > If you have been working through this series about provider-hosted add-ins, you have a Visual Studio solution that you can use to continue with this topic. You can also download the repository at [SharePoint_Provider-hosted_Add-Ins_Tutorials](https://github.com/OfficeDev/SharePoint_Provider-hosted_Add-ins_Tutorials) and open the BeforeProgrammaticButton.sln file. @@ -21,9 +19,10 @@ In this article, you learn how to include a custom ribbon button in a SharePoint ## Re-add the custom button to the project > [!NOTE] -> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: -> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. -> 2. Ensure that all three projects are set to **Start** in the **Action** column. +> The settings for Startup Projects in Visual Studio tend to revert to defaults whenever the solution is reopened. Always take these steps immediately after reopening the sample solution in this series of articles: +> +> 1. Right-click the solution node at the top of **Solution Explorer**, and then select **Set startup projects**. +> 1. Ensure that all three projects are set to **Start** in the **Action** column. In the previous article, you removed the custom **AddEmployeeToCorpDB** ribbon button from the project. Add it back in with the following steps. @@ -33,11 +32,9 @@ In the previous article, you removed the custom **AddEmployeeToCorpDB** ribbon b ![The Solution Explorer toolbar with a box drawn around the "Show All Files" button.](../images/f6b035f5-1aa7-452a-8f59-9dd44b062d06.PNG) -2. In the **ChainStore** project, right-click **AddEmployeeToCorpDB**, and then select **Include in Project**. - -3. Select the **Show All Files** button again. - -4. In the **ChainStore** project, expand **AddEmployeeToCorpDB**, and then open the elements.xml file. +1. In the **ChainStore** project, right-click **AddEmployeeToCorpDB**, and then select **Include in Project**. +1. Select the **Show All Files** button again. +1. In the **ChainStore** project, expand **AddEmployeeToCorpDB**, and then open the elements.xml file. ## Understand a dilemma and its solution @@ -45,205 +42,182 @@ In the elements.xml file, the **RegistrationId** attribute of the **CustomAction Deploying the list in the installation event handler, instead of first-run logic, won't solve the dilemma because SharePoint deploys custom descriptively-defined components, such as the custom button (and the **Place Order** add-in part), *before* it runs the custom handler, so the list won't exist when SharePoint tries to deploy the button. -Creating a custom button entirely programmatically is not practical for reasons that are too advanced to discuss here. Fortunately, it is not necessary. There is a relatively painless way to semi-programmatically create a custom button and assign it to a custom list. +Creating a custom button entirely programmatically is not practical for reasons that are too advanced to discuss here. Fortunately, it is not necessary. There is a relatively painless way to semi-programmatically create a custom button and assign it to a custom list. The following are the basic steps: -1. Keep the descriptively defined button in the project, but assign it to the ribbon of something that always exists on SharePoint sites, instead of to a list that's programmatically deployed with the same add-in. - -2. In the first-run logic, after the list is programmatically created, programmatically add an undefined button to the ribbon of the list. - -3. Initialize the properties of the new button with the values of the original button. At this point there are two identical buttons. The second is assigned to the ribbon of the **Local Employees** list. - -4. Programmatically delete the original button. +1. Keep the descriptively defined button in the project, but assign it to the ribbon of something that always exists on SharePoint sites, instead of to a list that's programmatically deployed with the same add-in. +1. In the first-run logic, after the list is programmatically created, programmatically add an undefined button to the ribbon of the list. +1. Initialize the properties of the new button with the values of the original button. At this point there are two identical buttons. The second is assigned to the ribbon of the **Local Employees** list. +1. Programmatically delete the original button. ## Programmatically register the custom button The following procedure shows how to implement this strategy. 1. In the **ChainStore** project, expand **AddEmployeeToCorpDB**, open the elements.xml file, and then change the value of the **RegistrationId** attribute of the **CustomAction** element to "100". This is the ID of a type of list. Even if there are no instances of lists of this type on the website, the list *type* is on every SharePoint website. The attribute should now look like the following. - + ```XML - RegistrationId="100" + RegistrationId="100" ``` -2. In the file SharePointComponentDeployer.cs, add the following line to the **DeployChainStoreComponentsToHostWeb** method, just under the line that calls `CreateLocalEmployeesList` (you create this method in the next step). - +1. In the file SharePointComponentDeployer.cs, add the following line to the **DeployChainStoreComponentsToHostWeb** method, just under the line that calls `CreateLocalEmployeesList` (you create this method in the next step). + ```csharp - ChangeCustomActionRegistration(); + ChangeCustomActionRegistration(); ``` -3. Add the following method to the `SharePointComponentDeployer` class. +1. Add the following method to the `SharePointComponentDeployer` class. ```csharp - private static void ChangeCustomActionRegistration() - { - using (var clientContext = sPContext.CreateUserClientContextForSPHost()) - { - var query = from action in clientContext.Web.UserCustomActions - where action.Name == "{button_GUID} .AddEmployeeToCorpDB" - select action; - IEnumerable matchingActions = clientContext.LoadQuery(query); - clientContext.ExecuteQuery(); + private static void ChangeCustomActionRegistration() + { + using (var clientContext = sPContext.CreateUserClientContextForSPHost()) + { + var query = from action in clientContext.Web.UserCustomActions + where action.Name == "{button_GUID} .AddEmployeeToCorpDB" + select action; + IEnumerable matchingActions = clientContext.LoadQuery(query); + clientContext.ExecuteQuery(); - UserCustomAction webScopedEmployeeAction = matchingActions.Single(); + UserCustomAction webScopedEmployeeAction = matchingActions.Single(); - // TODO8: Get a reference to the (empty) collection of custom actions - // that are registered with the custom list. + // TODO8: Get a reference to the (empty) collection of custom actions + // that are registered with the custom list. - // TODO9: Add a blank custom action to the list's collection. + // TODO9: Add a blank custom action to the list's collection. - // TODO10: Copy property values from the descriptively deployed - // custom action to the new custom action + // TODO10: Copy property values from the descriptively deployed + // custom action to the new custom action - // TODO11: Delete the original custom action. + // TODO11: Delete the original custom action. - clientContext.ExecuteQuery(); - } - } + clientContext.ExecuteQuery(); + } + } ``` - Note the following about this code: - - - Because the custom action, that is, the custom button, was registered with the ribbon of a list *type*, it is scoped to the entire website and is in the website's collection of custom actions. So the code retrieves it from that collection. - - - The value of the `action.Name` comes from the **ID** attribute of the **CustomAction** element in the elements.xml file in **AddEmployeeToCorpDB**. - + > NOTE: + > - Because the custom action, that is, the custom button, was registered with the ribbon of a list *type*, it is scoped to the entire website and is in the website's collection of custom actions. So the code retrieves it from that collection. + > - The value of the `action.Name` comes from the **ID** attribute of the **CustomAction** element in the elements.xml file in **AddEmployeeToCorpDB**. + > [!IMPORTANT] - > **You must change the `action.Name` value in the code to match the value in your elements.xml file.** The GUID part of the name will be different. Note that there is a `"."` character between the GUID and the rest of the name. The following is an example of the line: - > + > **You must change the `action.Name` value in the code to match the value in your elements.xml file.** The GUID part of the name will be different. Note that there is a `"."` character between the GUID and the rest of the name. The following is an example of the line: + > > `where action.Name == "4a926a42-3577-4e02-9d06-fef78586b1bc.AddEmployeeToCorpDB"` -4. Replace `TODO8` with the following code. Note that when you retract an add-in, components created by the add-in are not removed. After your first-run logic executes, there will be a custom action in the list's **UserCustomActions** collection, and it will not be retracted the next time you select F5. To avoid confusion, the last line in this code `listActions.Clear();` empties the collection. +1. Replace `TODO8` with the following code. Note that when you retract an add-in, components created by the add-in are not removed. After your first-run logic executes, there will be a custom action in the list's **UserCustomActions** collection, and it will not be retracted the next time you select F5. To avoid confusion, the last line in this code `listActions.Clear();` empties the collection. ```csharp - var queryForList = from list in clientContext.Web.Lists - where list.Title == "Local Employees" - select list; - IEnumerable matchingLists = clientContext.LoadQuery(queryForList); - clientContext.ExecuteQuery(); - - List employeeList = matchingLists.First(); - var listActions = employeeList.UserCustomActions; - clientContext.Load(listActions); - listActions.Clear(); + var queryForList = from list in clientContext.Web.Lists + where list.Title == "Local Employees" + select list; + IEnumerable matchingLists = clientContext.LoadQuery(queryForList); + clientContext.ExecuteQuery(); + + List employeeList = matchingLists.First(); + var listActions = employeeList.UserCustomActions; + clientContext.Load(listActions); + listActions.Clear(); ``` -5. Replace `TODO9` with the following line, which adds an undefined custom action to the **Local Employees** list. - +1. Replace `TODO9` with the following line, which adds an undefined custom action to the **Local Employees** list. + ```csharp - var listScopedEmployeeAction = listActions.Add(); + var listScopedEmployeeAction = listActions.Add(); ``` -6. Replace `TODO10` with the following code. +1. Replace `TODO10` with the following code. ```csharp - listScopedEmployeeAction.Title = webScopedEmployeeAction.Title; - listScopedEmployeeAction.Location = webScopedEmployeeAction.Location; - listScopedEmployeeAction.Sequence = webScopedEmployeeAction.Sequence; - listScopedEmployeeAction.CommandUIExtension = webScopedEmployeeAction.CommandUIExtension; - listScopedEmployeeAction.Update(); + listScopedEmployeeAction.Title = webScopedEmployeeAction.Title; + listScopedEmployeeAction.Location = webScopedEmployeeAction.Location; + listScopedEmployeeAction.Sequence = webScopedEmployeeAction.Sequence; + listScopedEmployeeAction.CommandUIExtension = webScopedEmployeeAction.CommandUIExtension; + listScopedEmployeeAction.Update(); ``` - Note the following about this code: - - - It assigns the property values of the web-scoped button (that was deployed with descriptive markup) to the corresponding properties of the list-scoped button, so the two buttons are identical except in scope. - - - The **Sequence** property specifies the relative order that the button will appear in its area of the ribbon. In this case, the button is on the **Actions** section of the **Items** tab of the ribbon. In the descriptive markup, this value was set to 10001, which is high enough to ensure that it will appear after (that is, to the right of) any in-the-box buttons that SharePoint itself puts in the **Actions** section of the ribbon. + > NOTE: + > - It assigns the property values of the web-scoped button (that was deployed with descriptive markup) to the corresponding properties of the list-scoped button, so the two buttons are identical except in scope. + > - The **Sequence** property specifies the relative order that the button will appear in its area of the ribbon. In this case, the button is on the **Actions** section of the **Items** tab of the ribbon. In the descriptive markup, this value was set to 10001, which is high enough to ensure that it will appear after (that is, to the right of) any in-the-box buttons that SharePoint itself puts in the **Actions** section of the ribbon. + +1. Replace `TODO11` with the following line, which deletes the original descriptively-defined button. If we did not have this line, every list on the website that uses list template "100" would have the custom button on it. Because the button's functionality is closely tied to the **Local Employees** list, it would make no sense to have the button on any other list. Also, without this line, the button would appear *twice* on the **Local Employees** list, because that list uses template "100". -7. Replace `TODO11` with the following line, which deletes the original descriptively-defined button. If we did not have this line, every list on the website that uses list template "100" would have the custom button on it. Because the button's functionality is closely tied to the **Local Employees** list, it would make no sense to have the button on any other list. Also, without this line, the button would appear *twice* on the **Local Employees** list, because that list uses template "100". - ```csharp - webScopedEmployeeAction.DeleteObject(); + webScopedEmployeeAction.DeleteObject(); ``` - -8. The entire method should now look like the following (except there should be a GUID in place of the placeholder). - + +1. The entire method should now look like the following (except there should be a GUID in place of the placeholder). + ```csharp - private static void ChangeCustomActionRegistration() - { - using (var clientContext = SPContext.CreateUserClientContextForSPHost()) - { - var query = from action in clientContext.Web.UserCustomActions - where action.Name == "{button_GUID} .AddEmployeeToCorpDB" - select action; - IEnumerable matchingActions = clientContext.LoadQuery(query); - clientContext.ExecuteQuery(); - - UserCustomAction webScopedEmployeeAction = matchingActions.Single(); - - var queryForList = from list in clientContext.Web.Lists - where list.Title == "Local Employees" - select list; - IEnumerable matchingLists = clientContext.LoadQuery(queryForList); - clientContext.ExecuteQuery(); - - List employeeList = matchingLists.First(); - var listActions = employeeList.UserCustomActions; - clientContext.Load(listActions); - listActions.Clear(); - - var listScopedEmployeeAction = listActions.Add(); - - listScopedEmployeeAction.Title = webScopedEmployeeAction.Title; - listScopedEmployeeAction.Location = webScopedEmployeeAction.Location; - listScopedEmployeeAction.Sequence = webScopedEmployeeAction.Sequence; - listScopedEmployeeAction.CommandUIExtension = webScopedEmployeeAction.CommandUIExtension; - listScopedEmployeeAction.Update(); - - webScopedEmployeeAction.DeleteObject(); - - clientContext.ExecuteQuery(); - } - } + private static void ChangeCustomActionRegistration() + { + using (var clientContext = SPContext.CreateUserClientContextForSPHost()) + { + var query = from action in clientContext.Web.UserCustomActions + where action.Name == "{button_GUID} .AddEmployeeToCorpDB" + select action; + IEnumerable matchingActions = clientContext.LoadQuery(query); + clientContext.ExecuteQuery(); + + UserCustomAction webScopedEmployeeAction = matchingActions.Single(); + + var queryForList = from list in clientContext.Web.Lists + where list.Title == "Local Employees" + select list; + IEnumerable matchingLists = clientContext.LoadQuery(queryForList); + clientContext.ExecuteQuery(); + + List employeeList = matchingLists.First(); + var listActions = employeeList.UserCustomActions; + clientContext.Load(listActions); + listActions.Clear(); + + var listScopedEmployeeAction = listActions.Add(); + + listScopedEmployeeAction.Title = webScopedEmployeeAction.Title; + listScopedEmployeeAction.Location = webScopedEmployeeAction.Location; + listScopedEmployeeAction.Sequence = webScopedEmployeeAction.Sequence; + listScopedEmployeeAction.CommandUIExtension = webScopedEmployeeAction.CommandUIExtension; + listScopedEmployeeAction.Update(); + + webScopedEmployeeAction.DeleteObject(); + + clientContext.ExecuteQuery(); + } + } ``` - ## Request full control of the host web Because the add-in now adds and deletes web-scoped custom actions, we need to escalate the permissions that the add-in requests from Manage to Full Control: 1. In **Solution Explorer**, open the AppManifest.xml file in the **ChainStore** project. - -2. Open the **Permissions** tab. Leave the **Scope** value at **Web**, but in the **Permission** field, select **Full Control** from the drop-down. - -3. Save the file. +1. Open the **Permissions** tab. Leave the **Scope** value at **Web**, but in the **Permission** field, select **Full Control** from the drop-down. +1. Save the file. ## Run the add-in and test the button deployment -1. Open the **Site Contents** page of the Hong Kong SAR store's website and remove the **Local Employees** list. - +1. Open the **Site Contents** page of the Hong Kong SAR store's website and remove the **Local Employees** list. + > [!NOTE] > Retracting an add-in in Visual Studio does not remove lists that are created by the add-in, so you need to manually delete it any time you are testing code that creates it. -2. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. Use the F5 key to deploy and run your add-in. Visual Studio hosts the remote web application in IIS Express and hosts the SQL database in SQL Express. It also makes a temporary installation of the add-in on your test SharePoint site and immediately runs the add-in. You are prompted to grant permissions to the add-in before its start page opens. +1. When the add-in's start page opens, select the **Back to Site** link on the chrome control at the top. +1. Go to the **Site Contents** page. The **Local Employees** list is present because your first-run logic added it. -3. When the add-in's start page opens, select the **Back to Site** link on the chrome control at the top. - -4. Go to the **Site Contents** page. The **Local Employees** list is present because your first-run logic added it. - > [!NOTE] > If the list is not there or you have other indications that the first-run code is not executing, it may be that the **Tenants** table is not being reverted to an empty state when you select F5. The most common cause of this is that the **ChainCorporateDB** project is no longer set as a startup project in Visual Studio. See the [note near the top of this article](#re-add-the-custom-button-to-the-project) for how to fix this. Also be sure that you've configured the database to be rebuilt as described in [Configure Visual Studio to rebuild the corporate database with each debugging session](give-your-provider-hosted-add-in-the-sharepoint-look-and-feel.md#Rebuild). -5. Open the list and add an item. - -6. In the list view, select the item, and then open the **Item** tab on the ribbon. - -7. On the **Item** tab, select the **Add to Corporate DB** button. The employee is added to the corporate database, and the **Added to Corporate DB** field is changed to **Yes**. - -8. Go back to the **Site Contents** page and select **Add an add-in**. - -9. Add a new **Custom List**. By default it will be "Generic" type (Generic is list type 100). After the list is created, open the **Item** tab on the ribbon. Notice that the **Add to Corporate DB** button is *not* on the ribbon. This is because your code deleted the web-scoped button. - -10. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time that you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. - -11. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. +1. Open the list and add an item. +1. In the list view, select the item, and then open the **Item** tab on the ribbon. +1. On the **Item** tab, select the **Add to Corporate DB** button. The employee is added to the corporate database, and the **Added to Corporate DB** field is changed to **Yes**. +1. Go back to the **Site Contents** page and select **Add an add-in**. +1. Add a new **Custom List**. By default it will be "Generic" type (Generic is list type 100). After the list is created, open the **Item** tab on the ribbon. Notice that the **Add to Corporate DB** button is *not* on the ribbon. This is because your code deleted the web-scoped button. +1. To end the debugging session, close the browser window or stop debugging in Visual Studio. Each time that you select F5, Visual Studio retracts the previous version of the add-in and installs the latest one. +1. You will work with this add-in and Visual Studio solution in other articles, and it's a good practice to retract the add-in one last time when you are done working with it for a while. Right-click the project in **Solution Explorer** and select **Retract**. ## Next steps - Events on lists and list items can also have custom handlers in SharePoint. You will learn how to create one and deploy it in your first-run logic in [Handle list item events in the provider-hosted add-in](handle-list-item-events-in-the-provider-hosted-add-in.md). - - - - diff --git a/docs/sp-add-ins/publish-sharepoint-add-ins.md b/docs/sp-add-ins/publish-sharepoint-add-ins.md index 43c0690bf..266f10d90 100644 --- a/docs/sp-add-ins/publish-sharepoint-add-ins.md +++ b/docs/sp-add-ins/publish-sharepoint-add-ins.md @@ -1,7 +1,7 @@ --- title: Publish SharePoint Add-ins description: Decide where to publish your SharePoint Add-ins. -ms.date: 03/05/2024 +ms.date: 10/05/2024 ms.localizationpriority: high ms.service: sharepoint --- @@ -25,6 +25,9 @@ To publish an add-in to AppSource, you must first [open a developer account](/of When you upload an add-in to AppSource for publication, Microsoft performs a validation check. For example, it checks that the add-in is free of viruses and that the add-in manifest markup is valid and complete, and verifies that any SharePoint solution packages (.wsp files) that you included in the add-in do not contain elements that aren't allowed, or SharePoint features with a scope that is broader than web. The package is also inspected for objectionable content. If the add-in package passes validation, it's wrapped into a file and signed by Microsoft. +> [!Important] +> Add-ins are registered in Partner Center and from there published to AppSource. As part of the Partner Center registration there's also an option to setup a client id and secret for your add-ins. The use of this client id and secret is only supported when the add-in is **also published**. Leaving add-ins as unpublished in partner center, but relying on the created client id is an unsupported scenario. + > [!NOTE] > Pricing model management is not supported for Office marketplace products. Existing paid products that migrated from Seller Dashboard will need to move to a SaaS model or be made free by July 2020. For details, see [Moving from paid to free add-ins](/office/dev/store/moving-from-paid-to-free-addins). You can monetize your add-in through the Microsoft Commercial Marketplace; for details, see [Monetize your add-in](/office/dev/store/monetize-addins-through-microsoft-commercial-marketplace). diff --git a/docs/sp-add-ins/register-sharepoint-add-ins.md b/docs/sp-add-ins/register-sharepoint-add-ins.md index ebb73b4fc..dcc77e5f6 100644 --- a/docs/sp-add-ins/register-sharepoint-add-ins.md +++ b/docs/sp-add-ins/register-sharepoint-add-ins.md @@ -1,7 +1,7 @@ --- title: Register SharePoint Add-ins description: Register your SharePoint Add-ins in Azure ACS by using Visual Studio, the Seller Dashboard, or an AppRegNew.aspx page, and retrieve registration information. -ms.date: 09/26/2023 +ms.date: 10/17/2024 ms.localizationpriority: high ms.service: sharepoint --- @@ -20,8 +20,6 @@ For the remote components of a provider-hosted SharePoint Add-in to interact wit To register your add-in with Azure ACS, you specify the following information: -- A GUID for the add-in, called a client ID. -- A password for the add-in, called a client secret. - A display name of the add-in that is used on the consent page where the user is prompted to trust the add-in. - A URL for the domain where the remote add-in is hosted. - A redirect URL. @@ -40,7 +38,7 @@ You can register your add-in in one of three ways, depending on where you are in |**Registration method**|**Details**| |:-----|:-----| |Use Visual Studio and Microsoft Office Developer Tools for Visual Studio to create a temporary add-in identity. |The Office Developer Tools for Visual Studio Wizard creates a temporary registration for your add-in with ACS and the App Management Service of your SharePoint test website.

    When you run the add-in from Visual Studio (F5), this identity is used. The tools also insert the client ID and secret in the web.config and AppManifest.xml files.

    When you're ready to publish your add-in, you can use the Visual Studio publish wizard to go to the Seller Dashboard to register it. If you are not marketing your SharePoint Add-in in the Office Store, use AppRegNew.aspx to register it. (Exact steps are in the next section.)

    **Note**: If your add-in requests permission to access SharePoint resources dynamically at run time, instead of on add-in installation, you cannot use Visual Studio to create add-in identities. | -|Register the add-in through the Seller Dashboard. |If you're going to use your add-in in more than one SharePoint tenant or farm, use the Seller Dashboard to register your add-in, regardless of whether you market it in the Office Store or make it available via the add-in catalog.

    When you register in the Seller Dashboard, you can design your add-in with a multitenant architecture without requiring tenant or farm administrators to register it separately.

    Also, if you plan to publish your add-in in the Office Store, you have to use the Seller Dashboard to register your add-in. You don't have to use the store to publish an add-in that is registered with the Seller Dashboard. For more information, see [Create or update client IDs and secrets in the Seller Dashboard](/office/dev/store/create-or-update-client-ids-and-secrets).| +|Register the add-in through the Seller Dashboard. |If you're going to use your add-in in more than one SharePoint tenant or farm, use the Seller Dashboard to register your add-in, regardless of whether you market it in the Office Store or make it available via the add-in catalog.

    When you register in the Seller Dashboard, you can design your add-in with a multi-tenant architecture without requiring tenant or farm administrators to register it separately.

    Also, if you plan to publish your add-in in the Office Store, you have to use the Seller Dashboard to register your add-in. You don't have to use the store to publish an add-in that is registered with the Seller Dashboard. For more information, see [Create or update client IDs and secrets in the Seller Dashboard](/office/dev/store/create-or-update-client-ids-and-secrets).| |Use the AppRegNew.aspx page. |Use the AppRegNew form to register your SharePoint Add-in if you are using the add-in only in one tenant or farm.

    For example, if you're creating add-ins for a single organization and you're going to distribute them via the organization add-in catalog, you can use the AppRegNew.aspx page of any website in a tenancy or farm to register the add-in.

    You cannot publish an add-in that is registered with AppRegNew.aspx to the Office Store. For add-ins that are published to the Office Store, you must get an identity from the Seller Dashboard.| ### To register by using AppRegNew.aspx @@ -48,20 +46,17 @@ You can register your add-in in one of three ways, depending on where you are in > [!NOTE] > Site collection admin is not able to register add-in with Azure ACS in AppRegNew.aspx by default unless explicitly allowed by the SharePoint tenant admin. For more information, see [Set-SPOTenant](/powershell/module/sharepoint-online/set-spotenant#-siteownermanagelegacyserviceprincipalenabled). +> [!IMPORTANT] +> Add-in secrets expire. If you register the add-in on the Seller Dashboard, you can set the expiration for up to three years. In the dashboard, you can also add new secrets when the old ones reach their expiration date. The new secret will be enabled in all instances of the add-in. If you register the add-in with AppRegNew.aspx, the secret expires in one year. For details, see [Replace an expiring client secret in a SharePoint Add-in](replace-an-expiring-client-secret-in-a-sharepoint-add-in.md). + 1. Go to `/_layouts/15/AppRegNew.aspx` by using a web browser. **AppRegNew page form** - ![The form on the App Reg New page with boxes for client ID, client secret, title, app domain, and redirect URL. Buttons named "generate" are beside the first two. In the corner are Create and Cancel buttons.](../images/9a38d876-2189-418c-9314-ae493a4cab61.PNG) + ![The form on the App Reg New page with boxes for client ID, client secret, title, app domain, and redirect URL. Buttons named "generate" are beside the first two. In the corner are Create and Cancel buttons.](../images/appregnewaspx.PNG) 1. Enter values for the follow form fields: - - **Add-in ID**. Also known as client ID; a GUID that can be generated (when you select **Generate**) or pasted into AppRegNew.aspx. The value must be unique for each add-in, and *must be lowercase*. - - **Add-in Secret**. Also known as the client secret, an opaque string. It is generated on the AppRegNew.aspx page by using the **Generate** button. The following is an example of an add-in secret: `xvVpG0AgVIJfch6ldu4dLUlcZyysmGqBRbpFDu6AfJw=`. - - > [!IMPORTANT] - > Add-in secrets expire. If you register the add-in on the Seller Dashboard, you can set the expiration for up to three years. In the dashboard, you can also add new secrets when the old ones reach their expiration date. The new secret will be enabled in all instances of the add-in. If you register the add-in with AppRegNew.aspx, the secret expires in one year. For details, see [Replace an expiring client secret in a SharePoint Add-in](replace-an-expiring-client-secret-in-a-sharepoint-add-in.md). - - **Title**. A user-friendly title; for example, **Contoso photo printing add-in**. Users are prompted to grant or deny the add-in the permissions that the add-in is requesting. This title appears as the name of the add-in on the consent prompt. - **Add-in Domain**. The host name of the remote component of the SharePoint Add-in. If the remote application isn't using port 443, the add-in domain must also include the port number. The add-in domain must match the URL bindings you use for your web application. Do not include protocol ("https:") or "/" characters in this value. If your web application host is using a DNS CNAME alias, use the alias. Some examples: @@ -81,7 +76,7 @@ You can register your add-in in one of three ways, depending on where you are in - https://www.northwindtraders.com/home/index - https://adventureworks.com/ -1. Select **Create** on the form. The page reloads and shows a confirmation of the values that you entered. Make a record of these values in a form that is easy to copy and paste. You need to enter the values in web.config and AppManifest.xml files or in the Visual Studio Publish wizard. +1. Select **Create** on the form. The page reloads and shows you the created Client Id and Client Secret. Make a record of these values in a form that is easy to copy and paste. You need to enter the values in web.config and AppManifest.xml files or in the Visual Studio Publish wizard. Regardless of how you register your SharePoint Add-in, when you are ready to deploy the add-in to staging or production, you need to [Enter the registration values into the web.config and AppManifest.xml files](#EditConfigFiles). If you are using Visual Studio, the Microsoft Office Developer Tools for Visual Studio do this configuration for you. diff --git a/docs/sp-add-ins/replace-an-expiring-client-secret-in-a-sharepoint-add-in.md b/docs/sp-add-ins/replace-an-expiring-client-secret-in-a-sharepoint-add-in.md index 4e4607de0..97d666d95 100644 --- a/docs/sp-add-ins/replace-an-expiring-client-secret-in-a-sharepoint-add-in.md +++ b/docs/sp-add-ins/replace-an-expiring-client-secret-in-a-sharepoint-add-in.md @@ -1,7 +1,7 @@ --- title: Replace an expiring client secret in a SharePoint Add-in description: Add a new client secret for a SharePoint Add-in that is registered with AppRegNew.aspx. -ms.date: 09/26/2023 +ms.date: 04/16/2025 ms.localizationpriority: high ms.service: sharepoint --- @@ -17,7 +17,7 @@ Client secrets for SharePoint Add-ins that are registered by using the **AppRegN ## Recommended maintenance schedule -We recommend creating new secrets a minimum of 30 days before they expire. This gives you a month of time before the old credentials expire. +We recommend creating new secrets a minimum of 30 days before they expire. This gives you a month before the old credentials expire. We recommend only removing secrets a minimum of 7 days after expiration, provided you have removed them from the application configuration. @@ -27,10 +27,20 @@ Removing an expired secret from ACS before you remove it from the application co Ensure the following before you begin: -- You have installed Azure Active Directory PowerShell 2.0: [Install Azure Active Directory PowerShell for Graph](/powershell/azure/active-directory/install-adv2) -- You're a tenant administrator for the Microsoft 365 tenant where the add-in was registered with the **AppRegNew.aspx** page. +- You have installed Microsoft Graph Powershell SDK: [Install the Microsoft Graph PowerShell SDK](/powershell/microsoftgraph/installation) +- You're a tenant administrator (or having **Application.ReadWrite.All** permission) for the Microsoft 365 tenant where the add-in was registered with the **AppRegNew.aspx** page. -## Generate a new secret +> [!Important] +> Microsoft Graph PowerShell versions 2.26 and up resulted in issues, if you've problems please downgrade to version 2.25 or lower. + +## Understand the type of your ACS principal before renewing the secret + +Historically ACS principals were created as Microsoft Entra service principals having the `servicePrincipalType` set to `Legacy`. As of December 2024 the Microsoft Entra principal creation has been streamlined and ACS principals are now created as application principals in Microsoft Entra. If you browse the Microsoft Entra applications you'll now be able to see the ACS principal you've created as of December 2024. ACS principal creation typically is done using `appregnew.aspx`. + +> [!Important] +> Due to this alternate creation the renewal of ACS principals also differs, below two chapters show both approaches, for the ACS service principals and for the ACS application principals. Ensure you use the correct approach. + +## Generate a new secret - for ACS service principals, created before December 2024 1. Create a client ID variable with the following line, using the client ID of the SharePoint Add-in as the parameter: @@ -38,41 +48,111 @@ Ensure the following before you begin: $clientId = 'client id of the add-in' ``` -1. Connect to AzureAD PowerShell. +1. Connect to Microsoft Graph with **Application.ReadWrite.All**, **Directory.ReadWrite.All** scope. ```powershell - $AzureAdCred = Get-Credential - Connect-AzureAD -Credential $AzureAdCred # Login to AzureAD + Connect-MgGraph -Scopes "Application.ReadWrite.All,Directory.ReadWrite.All" # Login with corresponding scope. Should the tenant admin or anyone else have the permission. ``` 1. Generate a new client secret with the following lines: ```powershell - $endDate = (Get-Date).AddYears(1) - $app = Get-AzureADServicePrincipal -Filter "AppId eq '$clientId'" - $objectId = $app.ObjectId - - $base64secret = New-AzureADServicePrincipalPasswordCredential -ObjectId $objectId -EndDate $endDate - New-AzureADServicePrincipalKeyCredential -ObjectId $objectId -EndDate $endDate -Type Symmetric -Usage Verify -Value $base64secret.Value - New-AzureADServicePrincipalKeyCredential -ObjectId $objectId -EndDate $endDate -Type Symmetric -Usage Sign -Value $base64secret.Value - - [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($base64secret.Value)) - $base64secret.EndDate # Print the end date. + $appPrincipal = Get-MgServicePrincipal -Filter "AppId eq '$clientId'" # Get principal id by AppId + $params = @{ + PasswordCredential = @{ + DisplayName = "NewSecret" # Replace with a friendly name. + } + } + $result = Add-MgServicePrincipalPassword -ServicePrincipalId $appPrincipal.Id -BodyParameter $params # Update the secret + $base64Secret = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($result.SecretText)) # Convert to base64 string. + $app = Get-MgServicePrincipal -ServicePrincipalId $appPrincipal.Id # get existing app information + $existingKeyCredentials = $app.KeyCredentials # read existing credentials + $dtStart = [System.DateTime]::Now # Start date + $dtEnd = $dtStart.AddYears(2) # End date (equals to secret end date) + $keyCredentials = @( # construct keys + @{ + Type = "Symmetric" + Usage = "Verify" + Key = [System.Text.Encoding]::ASCII.GetBytes($result.SecretText) + StartDateTime = $dtStart + EndDateTIme = $dtEnd + }, + @{ + type = "Symmetric" + usage = "Sign" + key = [System.Text.Encoding]::ASCII.GetBytes($result.SecretText) + StartDateTime = $dtStart + EndDateTIme = $dtEnd + } + ) + $existingKeyCredentials # combine with existing + Update-MgServicePrincipal -ServicePrincipalId $appPrincipal.Id -KeyCredentials $keyCredentials # Update keys + $base64Secret # Print base64 secret + $result.EndDateTime # Print the end date. ``` 1. The new client secret appears on the Windows PowerShell console. Copy it to a text file. You use it in the next procedure. > [!TIP] - > By default, the secret lasts one year. You can customize by leveraging the example below to specify the EndDateTime. + > By default, the secret lasts two years if you didn't specify the EndDateTime. You can customize by using the example below to specify the EndDateTime. > - > ``` powershell - > $endDate = (Get-Date).AddYears(2) # 2 year. + > ```powershell + > $params = @{ + > PasswordCredential = @{ + > DisplayName = "NewSecret" # Replace with a firendly name. + > EndDateTime = "2025-01-01T00:00:00Z" # Optional. Specify the end date you want. Using ISO 8601 format. + > } + > } > ``` +> [!IMPORTANT] +> Wait at least 24 hours for the propagation of the new ClientSecret to SharePoint. + +## Generate a new secret - for ACS application principals, created from December 2024 onwards + +```PowerShell +Connect-Graph -Scopes "Application.ReadWrite.All,Directory.ReadWrite.All" +$applicationId = '' # replace with your app id +$appPrincipal = Get-MgApplication -Filter "AppId eq '$applicationId'" +$params = @{ + PasswordCredential = @{ + DisplayName = "NewSecret" # Replace with a friendly name. + } +} +$result = Add-MgApplicationPassword -ApplicationId $appPrincipal.Id -BodyParameter $params +$base64Secret = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($result.SecretText)) +$dtStart = $result.StartDateTime +$dtEnd = $result.EndDateTime +$keyCredentials = @( + @{ + Type = "Symmetric" + Usage = "Verify" + Key = [System.Text.Encoding]::UTF8.GetBytes($result.SecretText) + StartDateTime = $dtStart + EndDateTime = $dtEnd + }, + @{ + Type = "Symmetric" + Usage = "Sign" + Key = [System.Text.Encoding]::UTF8.GetBytes($result.SecretText) + StartDateTime = $dtStart + EndDateTime = $dtEnd + } +) +# Add existing valid key credentials to the $keyCredentials +$appPrincipal.KeyCredentials |%{if ($_.EndDateTime -gt [DateTime]::UtcNow) {$keyCredentials += @($_)}} +Update-MgApplication -ApplicationId $appPrincipal.Id -KeyCredentials $keyCredentials # Update keys +$result.SecretText # Print secret text +$base64Secret # Print base64 secret +$result.EndDateTime # Print the end date. +``` + +> [!IMPORTANT] +> Wait at least 24 hours for the propagation of the new ClientSecret to SharePoint. + ## Update the remote web application in Visual Studio to use the new secret > [!IMPORTANT] -> If your add-in was originally created with a pre-release version of the Microsoft Office Developer Tools for Visual Studio, it may contain an out-of-date version of the **TokenHelper.[cs|vb]** file. If the file does not contain the string `secondaryClientSecret`, it is out of date and must be replaced before you can update the web application with a new secret. To obtain a copy of a release version of the file, you need Visual Studio 2012 or later. Create a new SharePoint Add-in project in Visual Studio. Copy the **TokenHelper.[cs|vb]** file from it to the web application project of your SharePoint Add-in. +> If your add-in was created with a pre-release version of the Microsoft Office Developer Tools for Visual Studio, it may contain an out-of-date version of the **TokenHelper.[cs|vb]** file. If the file does not contain the string `secondaryClientSecret`, it is out of date and must be replaced before you can update the web application with a new secret. To obtain a copy of a release version of the file, you need Visual Studio 2012 or later. Create a new SharePoint Add-in project in Visual Studio. Copy the **TokenHelper.[cs|vb]** file from it to the web application project of your SharePoint Add-in. 1. Open the SharePoint Add-in project in Visual Studio, and open the **web.config** file for the web application project. In the `appSettings` section, there are keys for the client ID and client secret. The following is an example: diff --git a/docs/sp-add-ins/retirement-announcement-for-add-ins.md b/docs/sp-add-ins/retirement-announcement-for-add-ins.md index b67cb741d..67f95b842 100644 --- a/docs/sp-add-ins/retirement-announcement-for-add-ins.md +++ b/docs/sp-add-ins/retirement-announcement-for-add-ins.md @@ -10,6 +10,9 @@ ms.service: sharepoint Microsoft strives to deliver utmost value to our customers through modern, optimized, secure solutions in this newly evolved world focused on digital transformation. As part of this evolution of Microsoft 365 solutions we will be retiring the SharePoint Add-In extensibility model and believe Microsoft 365 customers will be better served by modern SharePoint extensibility models. +> [!IMPORTANT] +> The SharePoint add-in model deprecation in SharePoint Online does not impact [SharePoint Framework (SPFx)](https://aka.ms/spfx), which is the primary replacement technology for SharePoint add-ins. SPFx is the most widely used extensibility model in Microsoft 365 and continues to be supported also in future. + SharePoint Add-Ins will stop working for new tenants as of November 1st, 2024 and they will stop working for existing tenants and will be fully retired as of April 2nd, 2026. This applies to all environments including Government Clouds and Department of Defense. In parallel with the SharePoint Add-In retirement, adding, updating and acquiring SharePoint Add-Ins via the public marketplace (a.k.a. store) will also be retiring. As of March 1st, 2024 Microsoft will not accept new SharePoint Add-Ins for listing in the public marketplace, from July 1st, 2024 SharePoint Add-Ins cannot be acquired anymore from the public marketplace. Using a tenant app catalog will stay supported and enables 3rd parties to offer their SharePoint Add-Ins until April 2nd, 2026. @@ -54,6 +57,17 @@ SharePoint hosted Add-Ins can be replaced by [SharePoint Framework](https://aka. To learn more about how to migrate SharePoint Add-Ins to alternative solutions check out these [articles](https://aka.ms/retirement/addins/guidance) and accompanying [videos](https://aka.ms/sp/add-in/modernize/videos). +### Disable Add-In usage for your tenant + +Admins can disable SharePoint Add-Ins with the [Set-SPOTenant SharePoint Management Shell PowerShell command](https://learn.microsoft.com/powershell/module/sharepoint-online/set-spotenant?view=sharepoint-ps). + +```PowerShell +Connect-SPOService -Url https://-admin.sharepoint.com +Set-SPOTenant -IsSharePointAddInsDisabled $true +``` + +After SharePoint Add-Ins are disabled, users will not be able to add SharePoint Add-Ins to their sites, and admins cannot add new SharePoint Add-Ins to the tenant and site collection app catalogs. SharePoint Add-Ins already added to sites will stay available and can still be used by the site's users. + ## How do I get help? You can use the following services and partner programs to help with your migration from SharePoint Add-Ins: diff --git a/docs/sp-add-ins/sharepoint-admin-apis-authentication-and-authorization.md b/docs/sp-add-ins/sharepoint-admin-apis-authentication-and-authorization.md new file mode 100644 index 000000000..0fa393cde --- /dev/null +++ b/docs/sp-add-ins/sharepoint-admin-apis-authentication-and-authorization.md @@ -0,0 +1,56 @@ +--- +title: SharePoint admin APIs authentication and authorization +description: This article describes the authentication and authorization model for SharePoint admin APIs. +author: samkabue +ms.author: samkabue +ms.date: 06/28/2024 +ms.localizationpriority: high +ms.service: sharepoint +--- + +# SharePoint admin APIs authentication and authorization + +SharePoint admin APIs are accessible via [SharePoint client object model (CSOM)](./complete-basic-operations-using-sharepoint-client-library-code.md), [SharePoint REST service](./get-to-know-the-sharepoint-rest-service.md), and [Microsoft Graph](../apis/sharepoint-rest-graph.md). + +## Overview + +Here are some key principles about SharePoint admin APIs authentication and authorization: + +- Each admin API defines the least-permissive permission a caller should have to call the API. +- We use role-based access control to assert a caller can call a particular admin API. If the caller has not been granted the required permission, they'll get an unauthorized access error. + +## Pre-Requisites + +- Caller is a registered Microsoft Entra application with the right application permissions. + +## Authorization + +SharePoint admin APIs can be called by applications registered in Microsoft Entra configured with [access on behalf of a user](/graph/auth-v2-user) or [access without a user](/graph/auth-v2-service). + +### Application access on behalf of a user + +Admin API operations [on behalf of a user](/graph/auth-v2-user) require applications to receive consent for SharePoint `AllSites.FullControl` application permission. This permission requires admin consent on the consuming tenant before any user from the tenant can consent to it. + +### Application access without a user + +Admin API operations [without a user](/graph/auth-v2-service) require applications to receive consent for `Sites.FullControl.All` application permission on the SharePoint resource. This permission requires admin consent on the consuming tenant. + +> [!IMPORTANT] +> Using application access on behalf of a user is the recommended approach. This type of access enhances the security of your tenant and improves auditability of actions performed by the application. For all applications, an administrator on the consuming tenant must consent to your application's request for permission. Learn more [here](/entra/identity/enterprise-apps/grant-admin-consent?pivots=portal). + +> [!NOTE] +> We are currently working on providing more granular, less-permissive scopes for applications to use based on what admin APIs the applications want to have access to. We'll share more information in due course when this is ready for adoption. + +## What's next + +Here are some actions you can take next to use applications for admin API calls: + +1. Configure your [application manifest](/entra/identity-platform/reference-app-manifest#requiredresourceaccess-attribute) to request the required permissions for Office 365 SharePoint Online (resourceAppId: `00000003-0000-0ff1-ce00-000000000000`). +1. [Grant admin consent](/entra/identity/enterprise-apps/grant-admin-consent?pivots=portal) to your application on the target tenant. + + | Access type | Permission name | `resourceAccess` id | `resourceAccess` type | + | :------------------ | :---------------------- | :------------------------------------- | :-------------------- | + | On behalf of a user | `AllSites.FullControl` | `56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0` | Scope | + | Without a user | `Sites.FullControl.All` | `a82116e5-55eb-4c41-a434-62fe8a61c773` | Role | + +1. Use your application to [invoke admin APIs](./get-to-know-the-sharepoint-rest-service.md). diff --git a/docs/sp-add-ins/sharepoint-net-server-csom-jsom-and-rest-api-index.md b/docs/sp-add-ins/sharepoint-net-server-csom-jsom-and-rest-api-index.md index 18ba2894e..b69d81a49 100644 --- a/docs/sp-add-ins/sharepoint-net-server-csom-jsom-and-rest-api-index.md +++ b/docs/sp-add-ins/sharepoint-net-server-csom-jsom-and-rest-api-index.md @@ -1,7 +1,7 @@ --- title: SharePoint .NET Server, CSOM, JSOM, and REST API index description: The most frequently used types and objects that are implemented in the .NET server object model and at least one client programming model. -ms.date: 09/26/2023 +ms.date: 06/16/2024 ms.localizationpriority: high ms.service: sharepoint --- @@ -23,7 +23,7 @@ This table lists the most frequently used core APIs, which are in most cases bas | API | SP.Object/Enumeration (sp.js) | REST Endpoint | | :------------- | :--------------------- | :-------------- | | **AttachmentCollection** **SPAttachmentCollection** | [SP.AttachmentCollection](https://msdn.microsoft.com/library/28247ba7-eeaf-e1fc-0609-fb4c39b5d53c%28Office.15%29.aspx) | `…/_api/web/lists('')/items()/attachmentfiles` | -| **BasePermissions** **SPBasePermissions** | [SP.BasePermissions object](https://msdn.microsoft.com/library/40349d51-1068-08c6-8ba4-b23ee58396c4%28Office.15%29.aspx) | N/A | +| **BasePermissions** **SPBasePermissions** | [SP.BasePermissions object](https://msdn.microsoft.com/library/40349d51-1068-08c6-8ba4-b23ee58396c4%28Office.15%29.aspx) | [..._api/web/getusereffectivepermissions(@user)?@user='\'](https://msdn.microsoft.com/library/dn531433#getusereffectivepermissions-method) | | **CalendarType** **SPCalendarType** | [SP.CalendarType enumeration](https://msdn.microsoft.com/library/33242ef7-1300-b534-6e8e-c5df1a3df85b%28Office.15%29.aspx) | N/A | | **ChangeCollection** **SPChangeCollection** | [SP.ChangeCollection object](https://msdn.microsoft.com/library/528b8776-f295-77ff-5403-a3556b4f3081%28Office.15%29.aspx) | `…/_api/web/getchanges(changequery)` | | **ChangeSite** **SPChangeSite** | [SP.ChangeSite enumeration](https://msdn.microsoft.com/library/fab86803-f106-97d0-6e97-696c91f210cd%28Office.15%29.aspx) | N/A | @@ -45,13 +45,13 @@ This table lists the most frequently used core APIs, which are in most cases bas | **FieldComputed** **SPFieldComputed** | [SP.FieldComputed object](https://msdn.microsoft.com/library/c00fcb21-1aab-6aff-cc9c-a7b1c9cd70f6%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldComputed%20resource) | | **FieldCurrency** **SPFieldCurrency** | [SP.FieldCurrency object](https://msdn.microsoft.com/library/aef1c982-fb34-3c5c-a6dc-659fd16b32e7%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldNumber%20and%20FieldCurrency%20resources) | | **FieldLink** **SPFieldLink** | [SP.FieldLink object](https://msdn.microsoft.com/library/5dc71a19-3260-20fa-73ed-3de3cde37825%28Office.15%29.aspx) | `…/_api/web/contenttypes('')/fieldlinks('')` | -| **FieldLookupValue** **SPFieldLookupValue** | [SP.FieldLookup object](https://msdn.microsoft.com/library/275b256e-1192-75f5-b604-ec002448be02%28Office.15%29.aspx) | N/A | +| **FieldLookupValue** **SPFieldLookupValue** | [SP.FieldLookup object](https://msdn.microsoft.com/library/275b256e-1192-75f5-b604-ec002448be02%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182?#fieldlookup-and-fielduser-resources) | | **FieldMultiChoice** **SPFieldMultiChoice** | [SP.FieldMultiChoice object](https://msdn.microsoft.com/library/a9546014-715a-ed57-993f-bbe237f92880%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldMultiChoice,%20FieldChoice,%20and%20FieldRatingScale%20resources) | | **FieldMultiLineText** **SPFieldMultiLineText** | [SP.FieldMultiLineText object](https://msdn.microsoft.com/library/52d130f2-6858-3aa1-88ce-d5b73eccd150%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldMultiLineText%20resource) | | **FieldNumber** **SPFieldNumber** | [SP.FieldNumber object](https://msdn.microsoft.com/library/1c3d179f-21a7-66cc-ea16-3341ea50f395%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldNumber%20and%20FieldCurrency%20resources) | | **FieldText** **SPFieldText** | [SP.FieldText object](https://msdn.microsoft.com/library/ba9a623c-b387-862d-eb1b-eb9d7fd9e04e%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldText%20resource) | | **FieldUrl** **SPFieldUrl** | [SP.FieldUrl object](https://msdn.microsoft.com/library/4eeff596-fa18-d21e-8cc0-fd8463fb5351%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldUrl%20resource) | -| **FieldUrlValue** **SPFieldUrlValue** | [SP.FieldUrlValue object](https://msdn.microsoft.com/library/3866f4a6-8fda-586a-ecdc-0c7e7d7ad44b%28Office.15%29.aspx) | N/A | +| **FieldUrlValue** **SPFieldUrlValue** | [SP.FieldUrlValue object](https://msdn.microsoft.com/library/3866f4a6-8fda-586a-ecdc-0c7e7d7ad44b%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182?#fieldurl-resource) | | **FieldUser** **SPFieldUser** | [SP.FieldUser object](https://msdn.microsoft.com/library/9058425f-b35a-b8a3-d5d1-b2abdbf08576%28Office.15%29.aspx) | […/_api/web/fields('\')](https://msdn.microsoft.com/library/dn600182.aspx#FieldLookup%20and%20FieldUser%20resources) | | **File** **SPFile** | [SP.File object](https://msdn.microsoft.com/library/860609d0-d317-41ca-9164-159e522d07cb%28Office.15%29.aspx) | […/_api/web/getfilebyserverrelativeurl('\/\')](https://msdn.microsoft.com/library/dn450841.aspx#File%20resource) | | **FileCollection** **SPFileCollection** | [SP.FieldCollection object](https://msdn.microsoft.com/library/db532e07-a4e8-d2f8-4ac8-c14de4adc761%28Office.15%29.aspx) | […/_api/web/getfolderbyserverrelativeurl('/\')/files](https://msdn.microsoft.com/library/dn450841.aspx#FileCollection%20resource) | @@ -65,7 +65,7 @@ This table lists the most frequently used core APIs, which are in most cases bas | **ListDataSource** **SPListDataSource** | [SP.ListDataSource object](https://msdn.microsoft.com/library/099059ae-2261-e3f5-d8f2-7dbcbadeff21%28Office.15%29.aspx) | N/A | | **ListItem** **SPListItem** | [SP.ListItem object](https://msdn.microsoft.com/library/3ea127c9-6cba-fe11-2193-ff2dc5c02fbf%28Office.15%29.aspx) | […/_api/web/lists(guid'\')/items(\)](https://msdn.microsoft.com/library/dn531433.aspx#ListItem%20resource) | | **ListItemCollection** **SPListItemCollection** | [SP.ListItemCollection object](https://msdn.microsoft.com/library/05107bcd-32d5-b2a5-05d2-12152441c1fc%28Office.15%29.aspx) | […/_api/web/lists(guid'\')/items](https://msdn.microsoft.com/library/dn531433.aspx#ListItemCollection%20resource) | -| **ListTemplateType** **SPListTemplateType** | [SP.ListTemplateType enumeration](https://msdn.microsoft.com/library/1ccbd999-9415-8449-6b38-aadb9549f384%28Office.15%29.aspx) | N/A | +| **ListTemplateType** **SPListTemplateType** | [SP.ListTemplateType enumeration](https://msdn.microsoft.com/library/1ccbd999-9415-8449-6b38-aadb9549f384%28Office.15%29.aspx) | […/_api/web/lists(guid'\')/BaseTemplate](https://msdn.microsoft.com/library/dn531433#list-properties) | | **Navigation** **SPNavigation** | [SP.Navigation object](https://msdn.microsoft.com/library/22777706-0bf1-ae70-0d99-529e643a2f31%28Office.15%29.aspx) | `…/_api/web/navigation` | | **NavigationNode** **SPNavigationNode** | [SP.NavigationNode object](https://msdn.microsoft.com/library/ec8a4fe0-6996-dba3-f565-4333c5046311%28Office.15%29.aspx) | N/A | | **Principal** **SPPrincipal** | [SP.Principal object](https://msdn.microsoft.com/library/2d89b994-f692-7b2c-0cd0-be586586d70a%28Office.15%29.aspx) | N/A | @@ -85,6 +85,7 @@ This table lists the most frequently used core APIs, which are in most cases bas | **User** **SPUser** | [SP.User object](https://msdn.microsoft.com/library/d36be210-3c1d-c589-e703-1ad66156dc18%28Office.15%29.aspx) | […/_api/web/siteusers(@v)?@v='\'](https://msdn.microsoft.com/library/dn531432.aspx#User%20resource) | | **UserCollection** **SPUserCollection** | [SP.UserCollection object](https://msdn.microsoft.com/library/1bb7bd28-4f19-a8a7-762f-3887c2b8ef7d%28Office.15%29.aspx) | […/_api/web/sitegroups(\)/users](https://msdn.microsoft.com/library/dn531432.aspx#UserCollection%20resource) | | **Utility** **SPUtility** | [SP.Utilities.Utility object (sp.js)](https://msdn.microsoft.com/library/57148667-64ff-7fed-8665-03226e70a96b%28Office.15%29.aspx) | N/A | +| **UsageInfo** **SPUsageInfo** | [SP.UsageInfo.storage property (sp.js)](https://msdn.microsoft.com/library/jj245691) | `…/_api/site/usage` | | **View** **SPView** | [SP.View object (sp.js)](https://msdn.microsoft.com/library/7b97ecb8-47cc-5c76-231f-81fa4ccae30a%28Office.15%29.aspx) | […/_api/web/lists(guid'\')/views('\')](https://msdn.microsoft.com/library/dn531433.aspx#bk_View) | | **ViewCollection** **SPViewCollection** | [SP.ViewCollection object](https://msdn.microsoft.com/library/3b0214c7-17b3-152c-78fa-a7a01e8b679a%28Office.15%29.aspx) | […/_api/web/lists(guid'\')/views](https://msdn.microsoft.com/library/dn531433.aspx#ViewCollection%20resource) | | **ViewFieldCollection** **SPViewFieldCollection** | [SP.ViewFieldCollection object](https://msdn.microsoft.com/library/05cab807-0609-5881-4119-bea2623eb01d%28Office.15%29.aspx) | […/_api/web/lists(guid'\')/views('\')/fields](https://msdn.microsoft.com/library/dn531433.aspx#ViewFieldCollection%20resource) | diff --git a/docs/spfx/build-for-teams-me-experience.md b/docs/spfx/build-for-teams-me-experience.md index cde59eb8f..067573ef9 100644 --- a/docs/spfx/build-for-teams-me-experience.md +++ b/docs/spfx/build-for-teams-me-experience.md @@ -1,7 +1,7 @@ --- title: Build a Me-experience in Microsoft Teams description: Extend Microsoft Teams using SharePoint Framework to offer your colleagues a Me-experience. -ms.date: 06/13/2022 +ms.date: 08/21/2024 ms.localizationpriority: medium --- @@ -15,11 +15,11 @@ This article presents a sample scenario of how to extend Microsoft Teams using S ![Sample Me-experience in Microsoft Teams](../images/me-experience/me-experience-preview.png) -In the following sections, we present a few ways of how you could implement a Me-experience in Microsoft Teams using SharePoint Framework, and for each one we mention its benefits and considerations for you to consider. +In the following sections, we present a few ways of how you could implement a Me-experience in Microsoft Teams using SharePoint Framework, and for each one, we mention its benefits and considerations for you to consider. ## Embed a modern SharePoint page -Recently SharePoint Online introduced the ability to [embed modern SharePoint pages in Microsoft Teams](/sharepoint/dev/features/embed-pages-to-teams?WT.mc_id=m365-9762-wmastyka). Using this capability, you can create a modern SharePoint page with several SharePoint Framework web parts that show personalized information for the current user such as recent documents or upcoming meetings. +Recently SharePoint Online introduced the ability to [embed modern SharePoint pages in Microsoft Teams](/sharepoint/dev/features/embed-pages-to-teams). Using this capability, you can create a modern SharePoint page with several SharePoint Framework web parts that show personalized information for the current user such as recent documents or upcoming meetings. ![Modern SharePoint page with several SharePoint Framework web parts showing personalized information for the current user](../images/me-experience/me-experience-sharepoint-page.png) @@ -28,7 +28,7 @@ Once the page is ready, in Microsoft Teams, you would create a personal app poin ![Building personal Teams app using App Studio](../images/me-experience/me-experience-app-studio.png) > [!CAUTION] -> When embedding a modern SharePoint page in Teams, you shouldn't use the URL of the page as it won't work in the desktop Teams app. Instead, use a special [URL pointing to the `teamslogon.aspx` page](/sharepoint/dev/features/embed-pages-to-teams?WT.mc_id=m365-9762-wmastyka#embed-sharepoint-modern-sites--pages-into-microsoft-teams-with-app-studio). +> When embedding a modern SharePoint page in Teams, you shouldn't use the URL of the page as it won't work in the desktop Teams app. Instead, use a special [URL pointing to the `teamslogon.aspx` page](/sharepoint/dev/features/embed-pages-to-teams#embed-sharepoint-modern-sites--pages-into-microsoft-teams-with-app-studio). To improve the experience, you would enable showing the page in full screen, which will remove the header and navigation allowing users to focus on the content. @@ -46,13 +46,13 @@ While creating the dashboard SharePoint page, you can make use of all page capab #### Combine information from different sources -By using a mix of web parts, you can combine truly personal information, such as emails, meetings, or the documents the person recently worked on, with other information coming from the organization, but nevertheless relevant to the person based on their role or region. +By using a mix of web parts, you can combine truly personal information, such as emails, meetings, or the documents the person recently worked on, with other information coming from the organization, but relevant to the person based on their role or region. It also doesn't matter if the web parts you put on the page are provided by Microsoft or built by your organization and whether they're deployed in a single or multiple solutions. -#### Package and distribute application in your organization without code +#### Package and distribute applications in your organization without code -To offer the Me-experience built this way to your users, you would package it as a personal Teams app. Using [App Studio](/microsoftteams/platform/concepts/build-and-test/app-studio-overview?WT.mc_id=m365-9762-wmastyka), you can create the personal app and publish it to your organizational catalog for everyone else to use. +To offer the Me-experience built this way to your users, you would package it as a personal Teams app. Using [App Studio](/microsoftteams/platform/concepts/build-and-test/app-studio-overview), you can create the personal app and publish it to your organizational catalog for everyone else to use. ### Considerations for embedding SharePoint pages as tabs @@ -72,13 +72,16 @@ This approach is ideal for organizations that want to offer their users a Me-exp ## Build a multi-tab personal Teams app +> [!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. + Another approach to offer your users a Me-experience in Microsoft Teams using SharePoint Framework is by building a multi-tab [personal Teams app](/microsoftteams/platform/concepts/design/personal-apps?WT.mc_id=m365-9762-wmastyka). ![Multi-tab personal Teams app built using SharePoint Framework](../images/me-experience/me-experience-multitab-personal-app.png) -Personal Teams apps can consist of one or more tabs. Each tab points to a different URL. When [building personal Teams app using SharePoint Framework](/sharepoint/dev/spfx/integrate-with-teams-introduction?WT.mc_id=m365-9762-wmastyka), you can make each tab point to a SharePoint Framework web part. By combining relevant web parts in a single personal Teams app, you can offer users a single place to access relevant information. +Personal Teams apps can consist of one or more tabs. Each tab points to a different URL. When [building personal Teams app using SharePoint Framework](/sharepoint/dev/spfx/integrate-with-teams-introduction), you can make each tab point to a SharePoint Framework web part. By combining relevant web parts in a single personal Teams app, you can offer users a single place to access relevant information. -In this approach, you would start by putting all web parts that you want to expose in a SharePoint Framework project. +In this approach, you would start by putting all the web parts that you want to expose in a SharePoint Framework project. ![SharePoint Framework project with the different web parts that make up the Me-experience](../images/me-experience/me-experience-spfx-project.png) @@ -158,7 +161,7 @@ To let users configure web parts exposed on the different tabs, you could build ### Advantages of building multi-tab personal Teams apps -Building the Me-experience as a multi-tab personal Teams app requires some development work. In return, it offers more benefits related to personalization and distribution of the solution. +Building the Me-experience as a multi-tab personal Teams app requires some development work. In return, it offers more benefits related to the personalization and distribution of the solution. #### User-specific configuration @@ -178,7 +181,7 @@ In comparison to building a dashboard using a modern SharePoint page and exposin #### Limited to custom web parts -When building multi-tab personal Teams apps, you can point only to custom web parts. Referencing standard web part provided by Microsoft is not supported. +When building multi-tab personal Teams apps, you can point only to custom web parts. Referencing the standard web part provided by Microsoft is not supported. #### All web parts should be in the same project @@ -186,7 +189,7 @@ While not necessary, having all web parts in the same project will help you simp #### Custom web part required for exposing settings -Personal Teams apps don't have a standard UI for configuring settings. Instead, the recommended pattern is to [expose settings on a separate tab](/microsoftteams/platform/concepts/design/personal-apps?WT.mc_id=m365-9762-wmastyka#help-and-settings). The developer is in control of the user experience of that tab and can adjust it to match the specific application requirements. +Personal Teams apps don't have a standard UI for configuring settings. Instead, the recommended pattern is to [expose settings on a separate tab](/microsoftteams/platform/concepts/design/personal-apps#help-and-settings). The developer is in control of the user experience of that tab and can adjust it to match the specific application requirements. Translating this to SharePoint Framework, it means that you would need to build a separate web part that allows users to configure the application. The settings tab can expose configuration for all the other tabs so that users can configure the whole application from one place. @@ -194,7 +197,7 @@ Translating this to SharePoint Framework, it means that you would need to build Personal Teams apps don't offer any infrastructure for persisting their configuration. Each application must decide for itself how and where it persists user's preferences. -While SharePoint Framework web parts have a standard way of persisting settings when used on SharePoint pages or in Microsoft Teams tabs, when exposed as personal Teams apps, they can't use this infrastructure. Instead, you need to [choose a way to store user's preferences](/sharepoint/dev/spfx/build-for-teams-configure-in-teams?WT.mc_id=m365-9762-wmastyka). Additionally, you need to ensure that your web parts can retrieve their configuration from this location. +While SharePoint Framework web parts have a standard way of persisting settings when used on SharePoint pages or in Microsoft Teams tabs, when exposed as personal Teams apps, they can't use this infrastructure. Instead, you need to [choose a way to store user's preferences](/sharepoint/dev/spfx/build-for-teams-configure-in-teams). Additionally, you need to ensure that your web parts can retrieve their configuration from this location. #### Each web part is a separate tab @@ -263,7 +266,7 @@ export default class Planning extends React.Component { } ``` -Such container web part allows you to reuse your existing code without duplicating it. Additionally, you will improve the user experience by combining related information and decrease the number of different tabs exposed. +Such a container web part allows you to reuse your existing code without duplicating it. Additionally, you will improve the user experience by combining related information and decrease the number of different tabs exposed. ### Advantages of combining multiple web parts in a single tab @@ -271,13 +274,13 @@ Combining information from multiple web parts in a single tab allows you to simp #### Group related information together -The ability to rearrange how information is presented in when exposed in a personal Teams app allows you to improve the user-experience. By putting related or similar information on a single tab, you help users to quickly glance over what's relevant to them. +The ability to rearrange how information is presented in when exposed in a personal Teams app allows you to improve the user experience. By putting related or similar information on a single tab, you help users quickly glance over what's relevant to them. Grouping related information together also lowers the number of different tabs displayed in the personal app, making it easier for users to navigate between the different sections. #### Control the user experience -When grouping related information together, you will build new React component and reference existing components from within. While doing this, you have the full control of how the information is presented and can consider different aspects such as importance of the displayed information, its relevance to the user, device, screen size, etc. +When grouping related information together, you will build a new React component and reference existing components from within. While doing this, you have full control of how the information is presented and can consider different aspects such as importance of the displayed information, its relevance to the user, device, screen size, etc. #### Reuse existing code @@ -285,7 +288,7 @@ When you build SharePoint Framework web parts using React, the main functionalit ### Considerations for grouping multiple web parts in a single tab -Combining multiple web parts in a single tab allows you to make a better use of the available screen estate and provide the user with a comprehensive view of the relevant information. There are however some specific considerations that you should take into account before you choose this approach. +Combining multiple web parts in a single tab allows you to make better use of the available screen estate and provides the user with a comprehensive view of the relevant information. There are however some specific considerations that you should take into account before you choose this approach. #### Combining web parts requires development effort diff --git a/docs/spfx/compatibility.md b/docs/spfx/compatibility.md index e5cfe4856..55dc39aae 100644 --- a/docs/spfx/compatibility.md +++ b/docs/spfx/compatibility.md @@ -1,39 +1,42 @@ --- title: SharePoint Framework development tools and libraries compatibility -description: Find which versions of the SharePoint Framework are compatible with each version of SharePoint, development tools and libraries. -ms.date: 06/26/2023 +description: Find which versions of the SharePoint Framework are compatible with each version of SharePoint, development tools, and libraries. +ms.date: 05/15/2025 ms.localizationpriority: high --- # SharePoint Framework development tools and libraries compatibility -As the SharePoint Framework (SPFx) evolves, so do the various development tools and libraries that it uses. +As the SharePoint Framework (SPFx) evolves, so do the various development tools and libraries it uses. ## SharePoint Framework version compatibility -Because SharePoint Online and the on-premises versions of SharePoint Server have different release cycles for new capabilities, they also have support different SharePoint Framework capabilities. +Because SharePoint Online and the on-premises versions of SharePoint Server have different release cycles for new capabilities, they also support different SharePoint Framework capabilities. SharePoint Online always uses the latest version of the SharePoint Framework, but SharePoint 2016 and SharePoint 2019 only support the versions that match the server-side dependencies of the deployed packages. | SharePoint version | Supported SPFx version | Supported features | | ---------------------------------------| ---------------------- | --------------------------------------------------------------------------------------- | | SharePoint Online | All versions | All features | -| SharePoint Server Subscription Edition | v1.5 or lower | SPFx client-side web parts in classic and modern pages, and extensions in modern pages. | +| SharePoint Server Subscription Edition | v1.5 or lower | SPFx client-side web parts in classic and modern pages, and extensions in modern pages. | | SharePoint Server 2019 | v1.4.1 or lower | SPFx client-side web parts in classic and modern pages, and extensions in modern pages. | | SharePoint 2016 Feature Pack 2 | v1.1 | SPFx client-side web parts hosted in classic SharePoint pages. | For more information about SharePoint Framework development with SharePoint 2016 Feature Pack 2 and SharePoint 2019, see: - [SharePoint Framework development with SharePoint 2016 Feature Pack 2](sharepoint-2016-support.md) -- [SharePoint Framework development with SharePoint Server 2019 and Subscription Edition](sharepoint-2019-and-subscription-edition-support.md) - this guidance applies also for SharePoint Server Subscription Edition +- [SharePoint Framework development with SharePoint Server 2019 and Subscription Edition](sharepoint-2019-and-subscription-edition-support.md) - this guidance also applies to SharePoint Server Subscription Edition ## SPFx development environment compatibility -As each new version of the SharePoint Framework is released, support for newer versions libraries is constantly added to ensure that the toolset remains up to date. +As each new version of the SharePoint Framework is released, support for newer library versions is constantly added to ensure the toolset remains current. The following table lists SharePoint Framework and compatible versions of common tools and libraries: | SPFx | Node.js (LTS) | TypeScript | React | | ------------------------------- | --------------- | -------------- | ----------- | +| [1.21.1](release-1.21.1.md) | v22 | v5.3 | v17.0.1 | +| [1.21.0](release-1.21.md) | v22 | v5.3 | v17.0.1 | +| [1.20.0](release-1.20.md) | v18 | v4.5, v4.7 | v17.0.1 | | [1.19.0](release-1.19.md) | v18 | v4.5, v4.7 | v17.0.1 | | [1.18.2](release-1.18.2.md) | v16, v18 | v4.5, v4.7 | v17.0.1 | | [1.18.1](release-1.18.1.md) | v16, v18 | v4.5, v4.7 | v17.0.1 | diff --git a/docs/spfx/content-securty-policy-trusted-script-sources.md b/docs/spfx/content-securty-policy-trusted-script-sources.md new file mode 100644 index 000000000..da35369a5 --- /dev/null +++ b/docs/spfx/content-securty-policy-trusted-script-sources.md @@ -0,0 +1,175 @@ +--- +title: Support for Content Security Policy (CSP) in SharePoint Online +description: Learn how SharePoint Online implements Content Security Policy to protect against various attack vectors, and how you can ensure your SharePoint Framework components are valid. +ms.date: 05/02/2025 +author: andrewconnell-msft2 +ms.author: v-jconnell +--- +# Support for Content Security Policy (CSP) in SharePoint Online + +In web development, Content Security Policy (CSP) is a security feature that help prevent against various attack vectors including [cross-site scripting](https://developer.mozilla.org/docs/Glossary/Cross-site_scripting) (XSS), [clickjacking](https://developer.mozilla.org/docs/Web/Security/Attacks/Clickjacking), and other code injection attacks. + +CSP enables a site to control which resources a page is allowed to load. It works though a series of instructions to the browser from the website that instruct the browser what the page is allowed to load. + +Learn more about CSP on MDN: [Content Security Policy (CSP)](https://developer.mozilla.org/docs/Web/HTTP/Guides/CSP). + +In this article, you'll learn how CSP works with custom SharePoint Framework (SPFx) solutions, how to identify and find CSP violations, and how to configure trusted sources in SharePoint Online. + +> [!IMPORTANT] +> Content Security Policy (CSP) is currently rolling out in SharePoint Online, however **no scripts are currently being blocked. CSP violations are only being logged at this time.** + +## How Content Security Policy Works in SharePoint Online + +When a browser requests a script, if CSP is enabled on the site, the browser checks the script location against the CSP rules. If the CSP restrictions allow the location of the script to be loaded by the browser, the browser proceeds with the request. However if CSP rules to not allow the location, the browser doesn't load the script and logs the error in the browser's Console. + +## Content Security Policy and SPFx Solutions + +By default, SharePoint Online is configured to allow the browser to load scripts used to implement SharePoint Online. This includes scripts from custom SPFx solutions that include scripts in the **\*.sppkg** deployment packages. + +The default setting for new SPFx solutions is to include the JavaScript bundles that implement SPFx components in the package. When an SPFx app is installed, the assets included in the package are deployed to the site's **ClientSideAssets** folder. + +SPFx developers have multiple options they can implement to load scripts in their solutions for various scenarios. These include: + +### Option 1: Deploy SPFx Scripts to an External CDN + +SPFx developers can optionally configure their SPFx solutions to not include the JavaScript bundles in the package and instead, deploy these scripts to their own locations. For instance, a vendor might elect to deploy their scripts to their own managed Content Delivery Network (CDN). + +When implementing this scenario, the SPFx package is configured to load scripts from a remote domain. The developer then must deploy the scripts to that location in addition to deploying the SPFx package (**\*.sppkg**) to the SharePoint Online App Catalog. + +This is done by setting the `cdnBasePath` property in the **./config/write-manifests.json** file. + +> [!NOTE] +> Learn more how to configure SPFx solutions so the JavaScript bundles and other scripts are deployed to a location other than SharePoint Online in the following articles: +> +> - [Deploy your SharePoint client-side web part to Azure CDN](web-parts/get-started/deploy-web-part-to-cdn.md) +> - [Host your client-side web part from Microsoft 365 CDN (Hello World part 4)](web-parts/get-started/hosting-webpart-from-office-365-cdn.md) +> - [Host an SPFx extension from the Microsoft 365 CDN (Hello World part 4)](extensions/get-started/hosting-extension-from-office365-cdn.md) + +### Option 2: Pull Script Dependencies from a CDN + +Another common scenario is when a SPFx solution takes a dependency on a popular library, but instead of including it in the SPFx component's JavaScript bundle, they configure the solution to exclude it from the bundle and instead instruct the SPFx runtime to pull the library from the remote CDN. + +This is done by adding the external script reference to the `externals` property in the **./config/config.json** file. + +> [!NOTE] +> Learn more how to configure the SPFx bundling process to exclude the library from the bundle and instruct the SPFx runtime to load the library from the remote CDN prior to loading the SPFx component's bundle in the following article: +> +> - [Add an external library to your SharePoint client-side web part](web-parts/basics/add-an-external-library.md) + +### Option 3: Dynamically Load a Script with the SPComponent Loader + +Another option SPFx developers can implement is to conditionally load a script through code. This is done using the [SPComponentLoader](/javascript/api/sp-loader/spcomponentloader). + +```ts +async SPComponentLoader.loadScript('https://some-external-site/script.js'); +``` + +## Content Security Policy Impact on SPFx Solutions + +As stated above, the CSP settings in SharePoint Online are configured to load scripts hosted in SharePoint Online. This means that if you include the resources in your SPFx package, *the default configuration for new SPFx solutions*, the CSP settings in SharePoint Online will have no impact on your custom solution. + +However, if your solution implements any of the three (3) options previously listed, or another option such as dynamically adding a `