diff --git a/.eslintrc.js b/.eslintrc.js index 6692e32..2b01e83 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + require('@rushstack/eslint-config/patch/modern-module-resolution'); module.exports = { extends: ['@microsoft/eslint-config-spfx/lib/profiles/react'], diff --git a/.github/workflows/jekyll_gh_pages.yml b/.github/workflows/jekyll_gh_pages.yml index 6bd9014..78df56f 100644 --- a/.github/workflows/jekyll_gh_pages.yml +++ b/.github/workflows/jekyll_gh_pages.yml @@ -1,58 +1,61 @@ -# Sample workflow for building and deploying a Jekyll site to GitHub Pages -name: Deploy SharePoint Integration Documentation - -on: - # Runs on pushes targeting the default branch - push: - branches: ['1.x'] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: 'pages' - cancel-in-progress: false - -jobs: - # Build job - build: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Pages - uses: actions/configure-pages@v3 - - - name: Move LaserficheSharePointIntegrationAppManifest.json - run: cp ./UserDocuments/LaserficheSharePointIntegrationAppManifest.json ./jekyll_files/docs/assets/LaserficheSharePointIntegrationAppManifest.json - - - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 - with: - source: ./jekyll_files - destination: ./_site - - name: Upload artifact - uses: actions/upload-pages-artifact@v2 - - # Deployment job - deploy: - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v2 +# Copyright (c) Laserfiche. +# Licensed under the MIT License. See LICENSE in the project root for license information. + +# Sample workflow for building and deploying a Jekyll site to GitHub Pages +name: Deploy SharePoint Integration Documentation + +on: + # Runs on pushes targeting the default branch + push: + branches: ['1.x'] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: 'pages' + cancel-in-progress: false + +jobs: + # Build job + build: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Pages + uses: actions/configure-pages@v3 + + - name: Move LaserficheSharePointIntegrationAppManifest.json + run: cp ./UserDocuments/LaserficheSharePointIntegrationAppManifest.json ./jekyll_files/docs/assets/LaserficheSharePointIntegrationAppManifest.json + + - name: Build with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./jekyll_files + destination: ./_site + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + + # Deployment job + deploy: + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4c1255..837e5c0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,58 +1,61 @@ -name: SPFx CI CD - -on: - push: - branches: ['\d+.x'] - pull_request: - branches: ['\d+.x'] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -env: - packagePath: sharepoint/solution/LaserficheSharePointOnlineIntegration.sppkg - packagePathUserDocs: UserDocuments - fullVersion: 1.0.0.${{github.run_number}} - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node.js environment - uses: actions/setup-node@v3 - with: - node-version: 16.x - - - name: Tag commit - uses: rickstaa/action-create-tag@v1 - with: - tag: ${{env.fullVersion}} - commit_sha: ${{ github.sha }} - message: Workflow run ${{github.server_url}}/${{github.repository}}/actions/runs/${{ github.run_id}} - - - name: replace config/package-solution.json version - run: sed -i 's/"1.0.0.0"/"${{env.fullVersion}}"/g' config/package-solution.json - - - name: replace package.json version - run: sed -i 's/"1.0.0.0"/"${{env.fullVersion}}"/g' package.json - - - name: Install dependencies - run: npm ci - - - name: Build solution - run: gulp build - - - name: Bundle and package - run: | - gulp bundle --ship - gulp package-solution --ship - - - name: Upload Build Package - uses: actions/upload-artifact@v3 - with: - path: | - ${{ env.packagePath }} - ${{ env.packagePathUserDocs }} +# Copyright (c) Laserfiche. +# Licensed under the MIT License. See LICENSE in the project root for license information. + +name: SPFx CI CD + +on: + push: + branches: ['\d+.x'] + pull_request: + branches: ['\d+.x'] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + packagePath: sharepoint/solution/LaserficheSharePointOnlineIntegration.sppkg + packagePathUserDocs: UserDocuments + fullVersion: 1.0.0.${{github.run_number}} + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js environment + uses: actions/setup-node@v3 + with: + node-version: 16.x + + - name: Tag commit + uses: rickstaa/action-create-tag@v1 + with: + tag: ${{env.fullVersion}} + commit_sha: ${{ github.sha }} + message: Workflow run ${{github.server_url}}/${{github.repository}}/actions/runs/${{ github.run_id}} + + - name: replace config/package-solution.json version + run: sed -i 's/"1.0.0.0"/"${{env.fullVersion}}"/g' config/package-solution.json + + - name: replace package.json version + run: sed -i 's/"1.0.0.0"/"${{env.fullVersion}}"/g' package.json + + - name: Install dependencies + run: npm ci + + - name: Build solution + run: gulp build + + - name: Bundle and package + run: | + gulp bundle --ship + gulp package-solution --ship + + - name: Upload Build Package + uses: actions/upload-artifact@v3 + with: + path: | + ${{ env.packagePath }} + ${{ env.packagePathUserDocs }} diff --git a/.github/workflows/veracode_build.yml b/.github/workflows/veracode_build.yml index 86b6a17..6ae73d4 100644 --- a/.github/workflows/veracode_build.yml +++ b/.github/workflows/veracode_build.yml @@ -1,52 +1,55 @@ -name: Veracode SPFx CI CD - -on: - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - schedule: - - cron: '0 12 * * 6' - -jobs: - build: - runs-on: ubuntu-latest - steps: - - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node.js environment - uses: actions/setup-node@v3 - with: - node-version: 16.x - - - name: Install dependencies - run: npm ci - - - name: Build solution - run: gulp build - - - name: 'create an empty ./veracode folder' - run: 'mkdir -p ./veracode' - - - name: 'Compress SharePoint files' - run: tar -czvf ./veracode/sharepoint-integration.tar.gz ./lib - - - - name: Veracode Upload And Scan (Static Application Security Testing) - uses: veracode/veracode-uploadandscan-action@0.2.6 - with: - appname: 'SharePoint Integration' - createprofile: true - filepath: 'veracode' - vid: '${{ secrets.VERACODE_API_ID }}' - vkey: '${{ secrets.VERACODE_API_KEY }}' - - - name: Run Veracode Software Composition Analysis (SCA) - env: - SRCCLR_API_TOKEN: ${{ secrets.SRCCLR_API_TOKEN }} - uses: veracode/veracode-sca@v2.1.6 - with: - create-issues: false - allow-dirty: true - recursive: true - +# Copyright (c) Laserfiche. +# Licensed under the MIT License. See LICENSE in the project root for license information. + +name: Veracode SPFx CI CD + +on: + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + schedule: + - cron: '0 12 * * 6' + +jobs: + build: + runs-on: ubuntu-latest + steps: + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js environment + uses: actions/setup-node@v3 + with: + node-version: 16.x + + - name: Install dependencies + run: npm ci + + - name: Build solution + run: gulp build + + - name: 'create an empty ./veracode folder' + run: 'mkdir -p ./veracode' + + - name: 'Compress SharePoint files' + run: tar -czvf ./veracode/sharepoint-integration.tar.gz ./lib + + + - name: Veracode Upload And Scan (Static Application Security Testing) + uses: veracode/veracode-uploadandscan-action@0.2.6 + with: + appname: 'SharePoint Integration' + createprofile: true + filepath: 'veracode' + vid: '${{ secrets.VERACODE_API_ID }}' + vkey: '${{ secrets.VERACODE_API_KEY }}' + + - name: Run Veracode Software Composition Analysis (SCA) + env: + SRCCLR_API_TOKEN: ${{ secrets.SRCCLR_API_TOKEN }} + uses: veracode/veracode-sca@v2.1.6 + with: + create-issues: false + allow-dirty: true + recursive: true + diff --git a/.vscode/extensions.json b/.vscode/extensions.json index fc2051e..4f22493 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,6 +2,7 @@ "recommendations": [ "msjsdiag.debugger-for-chrome", "esbenp.prettier-vscode", - "bradlc.vscode-tailwindcss" + "bradlc.vscode-tailwindcss", + "epivision.vscode-file-header" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index a31a2c3..8aa3e4a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,20 @@ "**/lib-amd": true, "src/**/*.scss.ts": true }, - "typescript.tsdk": ".\\node_modules\\typescript\\lib" + "typescript.tsdk": ".\\node_modules\\typescript\\lib", + "powerHeader.commentMode": "line", + "powerHeader.autoInsert.enable": true, + "powerHeader.autoInsert.allow": "all", + "powerHeader.template": "Copyright (c) .\\nLicensed under the License. See LICENSE.md in the project root for license information.", + "powerHeader.variables": ["='Laserfiche'", "='MIT'"], + "[html]": { + "powerHeader.commentMode": "block" + }, + "[css]": { + "powerHeader.commentMode": "block" + }, + "[markdown]": { + "powerHeader.commentMode": "block" + }, + "powerHeader.autoInsert.languages": ["plaintext", "Log", "json"] } \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b575c89..555dcaf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,38 +1,41 @@ -# Contributing to laserfiche-sharepoint-integration - -We encourage and appreciate feedback and contribution from the community! - -- [Code of Conduct](#coc) -- [Question or Problem](#question) -- [Issue and Feature Requests](#issue) -- [PR Submission Guidelines](#submit-pr) -- [Coding Rules](#rules) - -## Code of Conduct - - Please read and follow our [Code of Conduct](./code_of_conduct.md). - -## Question or Problem? - -Please post general questions on [Laserfiche Answers](https://answers.laserfiche.com/). Please include *laserfiche-sharepoint-integration* for reference. - -## Issue and Feature Requests - -Search [Github Issues](https://github.com/Laserfiche/laserfiche-sharepoint-integration/issues) for existing bugs report or features request related to your question. Please submit an Issue or Feature Request if your issues or requests have not been addressed. - -## PR Submission Guidelines - -- Search Github [Pull Requests](https://github.com/Laserfiche/laserfiche-sharepoint-integration/pulls) for PRs related to your submission. Make sure that this is not a duplication. -- Link the issue addressed by the PR. -- Add unit tests or document manual tests to validate the changes. -- Workflow shall triggers all unit tests. For a pull request to be accepted, all unit tests must pass when run workflow. - -After the submission, core members of the project will review the code. - -## Coding Rules - -Please follow the rules as you work on the code: - -- Please add unit tests for each fixed bug or added feature. -- Please use clean and informative names. -- Leave the code better than you find it. + + +# Contributing to laserfiche-sharepoint-integration + +We encourage and appreciate feedback and contribution from the community! + +- [Code of Conduct](#coc) +- [Question or Problem](#question) +- [Issue and Feature Requests](#issue) +- [PR Submission Guidelines](#submit-pr) +- [Coding Rules](#rules) + +## Code of Conduct + + Please read and follow our [Code of Conduct](./code_of_conduct.md). + +## Question or Problem? + +Please post general questions on [Laserfiche Answers](https://answers.laserfiche.com/). Please include *laserfiche-sharepoint-integration* for reference. + +## Issue and Feature Requests + +Search [Github Issues](https://github.com/Laserfiche/laserfiche-sharepoint-integration/issues) for existing bugs report or features request related to your question. Please submit an Issue or Feature Request if your issues or requests have not been addressed. + +## PR Submission Guidelines + +- Search Github [Pull Requests](https://github.com/Laserfiche/laserfiche-sharepoint-integration/pulls) for PRs related to your submission. Make sure that this is not a duplication. +- Link the issue addressed by the PR. +- Add unit tests or document manual tests to validate the changes. +- Workflow shall triggers all unit tests. For a pull request to be accepted, all unit tests must pass when run workflow. + +After the submission, core members of the project will review the code. + +## Coding Rules + +Please follow the rules as you work on the code: + +- Please add unit tests for each fixed bug or added feature. +- Please use clean and informative names. +- Leave the code better than you find it. diff --git a/LICENSE.md b/LICENSE.md index c203a9d..1f96718 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,9 +1,12 @@ -The MIT License (MIT) - -Copyright © 2023 Laserfiche - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +The MIT License (MIT) + +Copyright © 2023 Laserfiche + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 71a2a68..0ad982e 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,75 @@ -# laserfiche-sharepoint-integration - -## Summary - -This project, built with React, contains 3 SharePoint web parts and a command set that can be used to communicate with Laserfiche. To learn more about web parts, consult Microsoft's documentation for [using them](https://support.microsoft.com/en-us/office/using-web-parts-on-sharepoint-pages-336e8e92-3e2d-4298-ae01-d404bbe751e0) and [building them](https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part). - -Project contains: - -- 3 Web Parts (UI Components that are placed on SharePoint pages) - - [Laserfiche Administrator Configuration](./src/webparts/laserficheAdminConfiguration/) - - [Laserfiche Repository Explorer](./src/webparts/LaserficheRepositoryAccessWebPart/) - - [Laserfiche Sign In](./src/webparts/sendToLaserficheLoginComponent/) -- 1 Command Set (Action available on items in lists and libraries) - - [Send to Laserfiche](./src/extensions/savetoLaserfiche/) - -Admin and User Documentation is available on [GitHub pages](https://laserfiche.github.io/laserfiche-sharepoint-integration/) - -## Prerequisites - -See .github/workflows/main.yml for Node and NPM version used. - -## Change Log - -See CHANGELOG [here](./jekyll_files/CHANGELOG.md). - -## Contribution - -We welcome contributions and feedback. Please follow our [contributing guidelines](./CONTRIBUTING.md). - ---- - -## To run locally in your SharePoint Workbench - -- Ensure that you are at the solution folder - - run **npm install** - - run **npm run gulp-trust-dev-cert** - - Replace `REPLACE_WITH_YOUR_SHAREPOINT_SITE` in serve.json with your sharepoint site - - run **npm run serve** - - this should open up a window in the browser called a SharePoint workbench. - - To use a.clouddev.laserfiche.com: Open browser dev tools and go to site Local Storage: set 'spDevMode' to true - -## To test in a SharePoint site using localhost - -- run **npm install** -- **npm run build** -- **npm run package** -- this should result in the creation of a file with the path `/sharepoint/solution/laserfiche-sharepoint-integration.sppkg` from the root folder. -- Navigate to the solution folder -- run **npm run gulp-trust-dev-cert** (one-time only) -- Replace `REPLACE_WITH_YOUR_SHAREPOINT_SITE` in serve.json with your sharepoint site -- run **npm run serve** to host the code for the integration -- reference the [Admin Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation) for instructions on how to use the solution file you generated in the first steps to test your changes to the web parts in SharePoint sites. - -## To test in a SharePoint site with files hosted by SharePoint - -- run **npm install** -- **npm run bundle** -- **npm run package-solution** -- This will create the solution file at /sharepoint/solution/laserfiche-sharepoint-integration.sppkg. -- Once you've built and packaged the solution file, you can use it as a production package and upload it in the SharePoint admin center (see [Admin Docs](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation)) - -## To build documentation locally - -1. Follow the instructions [here](https://jekyllrb.com/docs/) to install jekyll and bundler. - - if any dependency installation fails, try downloading the package manually. - - navigate to the download directory. - - run `gem install problematic-dependency-name`, where the last word is replaced by the package you downloaded manually. - - retry installing the original package now that its dependency is installed. -1. Run `bundle install` to install all the dependencies needed to serve. -1. Navigate to the `jekyll_files` directory. -1. Run `bundle exec jekyll serve` to serve the documentation. -1. Open `localhost:4000` in a browser. + + +# laserfiche-sharepoint-integration + +## Summary + +This project, built with React, contains 3 SharePoint web parts and a command set that can be used to communicate with Laserfiche. To learn more about web parts, consult Microsoft's documentation for [using them](https://support.microsoft.com/en-us/office/using-web-parts-on-sharepoint-pages-336e8e92-3e2d-4298-ae01-d404bbe751e0) and [building them](https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part). + +Project contains: + +- 3 Web Parts (UI Components that are placed on SharePoint pages) + - [Laserfiche Administrator Configuration](./src/webparts/laserficheAdminConfiguration/) + - [Laserfiche Repository Explorer](./src/webparts/LaserficheRepositoryAccessWebPart/) + - [Laserfiche Sign In](./src/webparts/sendToLaserficheLoginComponent/) +- 1 Command Set (Action available on items in lists and libraries) + - [Send to Laserfiche](./src/extensions/savetoLaserfiche/) + +Admin and User Documentation is available on [GitHub pages](https://laserfiche.github.io/laserfiche-sharepoint-integration/) + +## Prerequisites + +See .github/workflows/main.yml for Node and NPM version used. + +## Change Log + +See CHANGELOG [here](./jekyll_files/CHANGELOG.md). + +## Contribution + +We welcome contributions and feedback. Please follow our [contributing guidelines](./CONTRIBUTING.md). + +--- + +## To run locally in your SharePoint Workbench + +- Ensure that you are at the solution folder + - run **npm install** + - run **npm run gulp-trust-dev-cert** + - Replace `REPLACE_WITH_YOUR_SHAREPOINT_SITE` in serve.json with your sharepoint site + - run **npm run serve** + - this should open up a window in the browser called a SharePoint workbench. + - To use a.clouddev.laserfiche.com: Open browser dev tools and go to site Local Storage: set 'spDevMode' to true + +## To test in a SharePoint site using localhost + +- run **npm install** +- **npm run build** +- **npm run package** +- this should result in the creation of a file with the path `/sharepoint/solution/laserfiche-sharepoint-integration.sppkg` from the root folder. +- Navigate to the solution folder +- run **npm run gulp-trust-dev-cert** (one-time only) +- Replace `REPLACE_WITH_YOUR_SHAREPOINT_SITE` in serve.json with your sharepoint site +- run **npm run serve** to host the code for the integration +- reference the [Admin Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation) for instructions on how to use the solution file you generated in the first steps to test your changes to the web parts in SharePoint sites. + +## To test in a SharePoint site with files hosted by SharePoint + +- run **npm install** +- **npm run bundle** +- **npm run package-solution** +- This will create the solution file at /sharepoint/solution/laserfiche-sharepoint-integration.sppkg. +- Once you've built and packaged the solution file, you can use it as a production package and upload it in the SharePoint admin center (see [Admin Docs](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation)) + +## To build documentation locally + +1. Follow the instructions [here](https://jekyllrb.com/docs/) to install jekyll and bundler. + - if any dependency installation fails, try downloading the package manually. + - navigate to the download directory. + - run `gem install problematic-dependency-name`, where the last word is replaced by the package you downloaded manually. + - retry installing the original package now that its dependency is installed. +1. Run `bundle install` to install all the dependencies needed to serve. +1. Navigate to the `jekyll_files` directory. +1. Run `bundle exec jekyll serve` to serve the documentation. +1. Open `localhost:4000` in a browser. diff --git a/code_of_conduct.md b/code_of_conduct.md index d29f768..351c46e 100644 --- a/code_of_conduct.md +++ b/code_of_conduct.md @@ -1,3 +1,6 @@ + + # Contributor Covenant Code of Conduct diff --git a/gulpfile.js b/gulpfile.js index 328cda4..9fff067 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,32 +1,35 @@ -'use strict'; - -const gulp = require('gulp'); - -const build = require('@microsoft/sp-build-web'); - -build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); - -var getTasks = build.rig.getTasks; -build.rig.getTasks = function () { - var result = getTasks.call(build.rig); - - result.set('serve', result.get('serve-deprecated')); - - return result; -}; - -build.configureWebpack.mergeConfig({ - additionalConfiguration: (generatedConfiguration) => { - generatedConfiguration.module.rules.push( - { - test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/, - use: { - loader: 'url-loader' - } - } - ); - return generatedConfiguration; - } - }); - -build.initialize(require('gulp')); +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +'use strict'; + +const gulp = require('gulp'); + +const build = require('@microsoft/sp-build-web'); + +build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); + +var getTasks = build.rig.getTasks; +build.rig.getTasks = function () { + var result = getTasks.call(build.rig); + + result.set('serve', result.get('serve-deprecated')); + + return result; +}; + +build.configureWebpack.mergeConfig({ + additionalConfiguration: (generatedConfiguration) => { + generatedConfiguration.module.rules.push( + { + test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/, + use: { + loader: 'url-loader' + } + } + ); + return generatedConfiguration; + } + }); + +build.initialize(require('gulp')); diff --git a/jekyll_files/docs/admin-documentation/adding-app-organization.md b/jekyll_files/docs/admin-documentation/adding-app-organization.md index bfd6b58..3060cd7 100644 --- a/jekyll_files/docs/admin-documentation/adding-app-organization.md +++ b/jekyll_files/docs/admin-documentation/adding-app-organization.md @@ -1,26 +1,29 @@ ---- -layout: default -title: Adding App to Organization -nav_order: 1 -parent: Laserfiche SharePoint Integration Administration Guide ---- - -# Adding App to Organization - -### Prerequisites - -- Have a SharePoint Online account with administrator privileges for the tenant app catalog. -- Download the latest Laserfiche SharePoint Integration [package](../assets/LaserficheSharePointOnlineIntegration.sppkg) - -### Steps - -1. Navigate to the following url: https://{your-full-subdomain.and-domain.com}/sites/appcatalog/AppCatalog/Forms/AllItems.aspx, where the part in curly braces is replaced by the domain and subdomain of your SharePoint-related websites. -1. If you can see the "+New" and "Upload" buttons, then proceed to the next step. If not, ask an administrator to [add you as an admin to the SharePoint Online App Catalog](https://learn.microsoft.com/en-us/office365/customlearning/addappadmin#add-an-administrator). -1. Click Upload and select the Laserfiche SharePoint package file (.sppkg). - -1. Click on the Deploy button when prompted to trust the solution. - - -### Next Steps - -Follow the steps for [Adding App to SharePoint Site](./adding-app-to-sp-site) + + +--- +layout: default +title: Adding App to Organization +nav_order: 1 +parent: Laserfiche SharePoint Integration Administration Guide +--- + +# Adding App to Organization + +### Prerequisites + +- Have a SharePoint Online account with administrator privileges for the tenant app catalog. +- Download the latest Laserfiche SharePoint Integration [package](../assets/LaserficheSharePointOnlineIntegration.sppkg) + +### Steps + +1. Navigate to the following url: https://{your-full-subdomain.and-domain.com}/sites/appcatalog/AppCatalog/Forms/AllItems.aspx, where the part in curly braces is replaced by the domain and subdomain of your SharePoint-related websites. +1. If you can see the "+New" and "Upload" buttons, then proceed to the next step. If not, ask an administrator to [add you as an admin to the SharePoint Online App Catalog](https://learn.microsoft.com/en-us/office365/customlearning/addappadmin#add-an-administrator). +1. Click Upload and select the Laserfiche SharePoint package file (.sppkg). + +1. Click on the Deploy button when prompted to trust the solution. + + +### Next Steps + +Follow the steps for [Adding App to SharePoint Site](./adding-app-to-sp-site) diff --git a/jekyll_files/docs/admin-documentation/adding-app-to-sp-site.md b/jekyll_files/docs/admin-documentation/adding-app-to-sp-site.md index 4c8586a..5a56ad3 100644 --- a/jekyll_files/docs/admin-documentation/adding-app-to-sp-site.md +++ b/jekyll_files/docs/admin-documentation/adding-app-to-sp-site.md @@ -1,50 +1,53 @@ ---- -layout: default -title: Adding App to SharePoint Site -nav_order: 2 -parent: Laserfiche SharePoint Integration Administration Guide ---- - -# Adding App to SharePoint Site - -### Prerequisites - -- Be an owner of a SharePoint site you want to add the integration to. -- The site must exist in an organization which has the integration installed. (see [Adding App to Organization](./adding-app-organization)) - -### Steps - -1. Go to the SharePoint site that you would like to install the integration on. If you do not have a SharePoint site already, you can find instructions [here](https://support.microsoft.com/en-gb/office/create-a-site-in-sharepoint-4d1e11bf-8ddc-499d-b889-2b48d10b1ce8) on how to create one. -1. Navigate to the app catalog by clicking on the "Site contents" item in the - navigation bar. - -1. Open the "New" Dropdown menu by clicking on the "+" icon. - -1. Add the App named “Laserfiche SharePoint Online Integration”. - -1. Navigate to your SharePoint site. If successfully installed, the app will be listed under the “Site contents” tab. - - -### The Laserfiche Sign In Page - -1. In your SharePoint site, select the "Pages" item in the navigation bar on the left side of the page. - -1. Create and open a new site page by clicking the "+ New" button and selecting "Site Page" from the dropdown. -1. Title the page “LaserficheSignIn”. -1. Move your cursor just below the title area to the white space beneath. This should reveal a hidden "+" button. If you hover over it, it should display the message "Add a new web part in column one”. - -1. Click on that button and Search for “Laserfiche Sign In". - -1. Click on the search result with a white L on an orange square. The Laserfiche Sign In web part should now appear on your Page. Before creating subsequent pages, make sure to click the 'Publish' button to save the page. - -### The Repository Explorer Page - -Follow the same steps as above, but title the Page whatever you wish and add the “Repository Explorer” web part. - -### The Admin Configuration Page - -Follow the same steps as above, but title the page whatever you wish and add the “Admin Configuration” web part instead of “Laserfiche Sign In". - -### Next Steps - -Before you can log in and use the web pages you just created, you will need to [Register them in the Laserfiche Developer Console](../admin-documentation/register-app-in-laserfiche). After you register your Apps, you should be able to log in and use the web parts. For Documentation on how to use the integration, reference the [User Documentation](../user-documentation/). + + +--- +layout: default +title: Adding App to SharePoint Site +nav_order: 2 +parent: Laserfiche SharePoint Integration Administration Guide +--- + +# Adding App to SharePoint Site + +### Prerequisites + +- Be an owner of a SharePoint site you want to add the integration to. +- The site must exist in an organization which has the integration installed. (see [Adding App to Organization](./adding-app-organization)) + +### Steps + +1. Go to the SharePoint site that you would like to install the integration on. If you do not have a SharePoint site already, you can find instructions [here](https://support.microsoft.com/en-gb/office/create-a-site-in-sharepoint-4d1e11bf-8ddc-499d-b889-2b48d10b1ce8) on how to create one. +1. Navigate to the app catalog by clicking on the "Site contents" item in the + navigation bar. + +1. Open the "New" Dropdown menu by clicking on the "+" icon. + +1. Add the App named “Laserfiche SharePoint Online Integration”. + +1. Navigate to your SharePoint site. If successfully installed, the app will be listed under the “Site contents” tab. + + +### The Laserfiche Sign In Page + +1. In your SharePoint site, select the "Pages" item in the navigation bar on the left side of the page. + +1. Create and open a new site page by clicking the "+ New" button and selecting "Site Page" from the dropdown. +1. Title the page “LaserficheSignIn”. +1. Move your cursor just below the title area to the white space beneath. This should reveal a hidden "+" button. If you hover over it, it should display the message "Add a new web part in column one”. + +1. Click on that button and Search for “Laserfiche Sign In". + +1. Click on the search result with a white L on an orange square. The Laserfiche Sign In web part should now appear on your Page. Before creating subsequent pages, make sure to click the 'Publish' button to save the page. + +### The Repository Explorer Page + +Follow the same steps as above, but title the Page whatever you wish and add the “Repository Explorer” web part. + +### The Admin Configuration Page + +Follow the same steps as above, but title the page whatever you wish and add the “Admin Configuration” web part instead of “Laserfiche Sign In". + +### Next Steps + +Before you can log in and use the web pages you just created, you will need to [Register them in the Laserfiche Developer Console](../admin-documentation/register-app-in-laserfiche). After you register your Apps, you should be able to log in and use the web parts. For Documentation on how to use the integration, reference the [User Documentation](../user-documentation/). diff --git a/jekyll_files/docs/admin-documentation/configuring-metadata-mappings.md b/jekyll_files/docs/admin-documentation/configuring-metadata-mappings.md index 11510da..6d7c14a 100644 --- a/jekyll_files/docs/admin-documentation/configuring-metadata-mappings.md +++ b/jekyll_files/docs/admin-documentation/configuring-metadata-mappings.md @@ -1,46 +1,49 @@ ---- -layout: default -title: Configuring Metadata Mappings -nav_order: 4 -parent: Laserfiche SharePoint Integration Administration Guide ---- - -# Configuring Metadata Mappings - -### Prerequisites - -- be a Site Owner of the SharePoint Site for which the integration will be configured - -## Introduction - -You must configure mappings for your site before you can send documents to Laserfiche. Mappings are set based on the SharePoint Content Type of the item you are trying to save. You must set up a mapping for each SharePoint Content Type you use in your site, or set a default mapping for anything not specifically mapped that you would still like to save to Laserfiche. - -A mapping allows you to specify options for how to save to Laserfiche for that Content Type, including a destination folder, a template with mapped metadata from SharePoint properties to Laserfiche fields, and what happens in SharePoint once you save to Laserfiche. - -## Steps - -### Create a Profile - -In the "Profiles" tab of the Admin Configuration web part, click on the “Add Profile” button to add a new profile. Click on the pencil icon to edit an existing profile. Either selection will open the Profile Editor View. - - -### Define the Profile in the Profile Editor - -- Name: this is the identifier used to associate SharePoint content types with this profile in the Profile Mapping tab. -- Laserfiche Template: If a profile is assigned a template, then all files saved to Laserfiche through that profile will be assigned that template in Laserfiche. [Learn more about templates](https://doc.laserfiche.com/laserfiche.documentation/en-us/Content/Fields_and_Templates.html). -- Laserfiche Destination: This option specifies the path to the folder in the Laserfiche Repository where the files associated with this profile will be saved. -- After Import: This option specifies what to do with the SharePoint file after exporting it to Laserfiche. - -- Mappings from SharePoint Column to Laserfiche Field Values - This is where the actual metadata transfer is configured. - Each Field in the template can be assigned a SharePoint column, so that when files are exported from SharePoint to Laserfiche, the file in Laserfiche will have a field with the same value as the Column of the file in SharePoint. - templates with required fields MUST have columns assigned to them. - The association between SharePoint columns and Laserfiche fields should be one-to-one, i.e., you should not attempt to map multiple SharePoint columns to the same Laserfiche field. - - -### Map Content Types to Profiles in the Profile Mapping Tab - -Displays a list of SharePoint Content Types and their corresponding Laserfiche Profile. If you add a content type/profile pair, then -any SharePoint content matching that type will be assigned the corresponding profile when you attempt to save the content to Laserfiche. - - -### Default Profile - -If you attempt to save a file to Laserfiche and it does not have a SharePoint Content Type or its SharePoint Content Type is not mapped to any Laserfiche Profile, you will not be able to save that file. You must either create a mapping for each Content Type that will exist on your site or set a default mapping which will apply to any file in SharePoint that does not have a Content Type or does not have a corresponding Laserfiche Profile for its Content Type. - + + +--- +layout: default +title: Configuring Metadata Mappings +nav_order: 4 +parent: Laserfiche SharePoint Integration Administration Guide +--- + +# Configuring Metadata Mappings + +### Prerequisites + +- be a Site Owner of the SharePoint Site for which the integration will be configured + +## Introduction + +You must configure mappings for your site before you can send documents to Laserfiche. Mappings are set based on the SharePoint Content Type of the item you are trying to save. You must set up a mapping for each SharePoint Content Type you use in your site, or set a default mapping for anything not specifically mapped that you would still like to save to Laserfiche. + +A mapping allows you to specify options for how to save to Laserfiche for that Content Type, including a destination folder, a template with mapped metadata from SharePoint properties to Laserfiche fields, and what happens in SharePoint once you save to Laserfiche. + +## Steps + +### Create a Profile + +In the "Profiles" tab of the Admin Configuration web part, click on the “Add Profile” button to add a new profile. Click on the pencil icon to edit an existing profile. Either selection will open the Profile Editor View. + + +### Define the Profile in the Profile Editor + +- Name: this is the identifier used to associate SharePoint content types with this profile in the Profile Mapping tab. +- Laserfiche Template: If a profile is assigned a template, then all files saved to Laserfiche through that profile will be assigned that template in Laserfiche. [Learn more about templates](https://doc.laserfiche.com/laserfiche.documentation/en-us/Content/Fields_and_Templates.html). +- Laserfiche Destination: This option specifies the path to the folder in the Laserfiche Repository where the files associated with this profile will be saved. +- After Import: This option specifies what to do with the SharePoint file after exporting it to Laserfiche. + +- Mappings from SharePoint Column to Laserfiche Field Values - This is where the actual metadata transfer is configured. - Each Field in the template can be assigned a SharePoint column, so that when files are exported from SharePoint to Laserfiche, the file in Laserfiche will have a field with the same value as the Column of the file in SharePoint. - templates with required fields MUST have columns assigned to them. - The association between SharePoint columns and Laserfiche fields should be one-to-one, i.e., you should not attempt to map multiple SharePoint columns to the same Laserfiche field. + + +### Map Content Types to Profiles in the Profile Mapping Tab + +Displays a list of SharePoint Content Types and their corresponding Laserfiche Profile. If you add a content type/profile pair, then +any SharePoint content matching that type will be assigned the corresponding profile when you attempt to save the content to Laserfiche. + + +### Default Profile + +If you attempt to save a file to Laserfiche and it does not have a SharePoint Content Type or its SharePoint Content Type is not mapped to any Laserfiche Profile, you will not be able to save that file. You must either create a mapping for each Content Type that will exist on your site or set a default mapping which will apply to any file in SharePoint that does not have a Content Type or does not have a corresponding Laserfiche Profile for its Content Type. + diff --git a/jekyll_files/docs/admin-documentation/index.md b/jekyll_files/docs/admin-documentation/index.md index d2dd6cd..307c7c3 100644 --- a/jekyll_files/docs/admin-documentation/index.md +++ b/jekyll_files/docs/admin-documentation/index.md @@ -1,16 +1,19 @@ ---- -layout: default -title: Laserfiche SharePoint Integration Administration Guide -nav_order: 2 -has_children: true ---- - -# Laserfiche SharePoint Integration Administration Guide - -The following guides detail how to set up the Laserfiche/SharePoint integration. Unlike the user guides, the admin guides -may require you to hold certain privileges, such as the ability to edit a page on a SharePoint site. Each guide contains important -information to help you set up the integration. If you are setting up for the first time, we recommend starting at the top. - -## Important Security Notice - -JavaScript code running in same domain/origin as your SharePoint tenant has access to the Laserfiche Integration security token. This token must be kept secure to avoid unauthorized access to Laserfiche systems. To this end, ensure that only trusted code is allowed to run in the same domain/origin. + + +--- +layout: default +title: Laserfiche SharePoint Integration Administration Guide +nav_order: 2 +has_children: true +--- + +# Laserfiche SharePoint Integration Administration Guide + +The following guides detail how to set up the Laserfiche/SharePoint integration. Unlike the user guides, the admin guides +may require you to hold certain privileges, such as the ability to edit a page on a SharePoint site. Each guide contains important +information to help you set up the integration. If you are setting up for the first time, we recommend starting at the top. + +## Important Security Notice + +JavaScript code running in same domain/origin as your SharePoint tenant has access to the Laserfiche Integration security token. This token must be kept secure to avoid unauthorized access to Laserfiche systems. To this end, ensure that only trusted code is allowed to run in the same domain/origin. diff --git a/jekyll_files/docs/admin-documentation/register-app-in-laserfiche.md b/jekyll_files/docs/admin-documentation/register-app-in-laserfiche.md index b1c274c..4fed4ac 100644 --- a/jekyll_files/docs/admin-documentation/register-app-in-laserfiche.md +++ b/jekyll_files/docs/admin-documentation/register-app-in-laserfiche.md @@ -1,31 +1,34 @@ ---- -layout: default -title: Registering App in Laserfiche -nav_order: 3 -parent: Laserfiche SharePoint Integration Administration Guide ---- - -# Registering App in Laserfiche - -### Prerequisites - -- Have developer rights in your Laserfiche account. - -### Steps - -1. Open the [Developer Console](https://developer.laserfiche.com/developer-console.html). - -1. Attempt to Create a New App from Manifest, and upload the manifest provided [here](../assets/LaserficheSharePointIntegrationAppManifest.json). - -1. If the attempt fails because an app with that client ID already exists, find the app with that client id by opening [this url](https://app.laserfiche.com/devconsole/apps/8ee987ea-a0b1-4ca2-85c4-a79b335cd214/config) in a new tab. - -1. One way or another, an app with that client ID should now exist. Open the app and switch from the general tab to the authentication tab. - -1. Copy the URL from your SharePoint LaserficheSignIn page, append the query parameter `?autologin` and add it to the developer console as a new redirect URI. The URI should end with `SitePages/LaserficheSignIn.aspx?autologin`. - - - For example, if your LaserficheSignInPage was named `https://subdomain.sharepoint.com/sites/my-test-site/SitePages/LaserficheSignIn.aspx`, then the redirect URI you would add to the Laserfiche devconsole would be `https://subdomain.sharepoint.com/sites/my-test-site/SitePages/LaserficheSignIn.aspx?autologin`. -1. You should now be able to sign in on each of the components. - -### Next Steps - -[Configure Metadata Mappings](./configuring-metadata-mappings) in the Admin Configuration web part + + +--- +layout: default +title: Registering App in Laserfiche +nav_order: 3 +parent: Laserfiche SharePoint Integration Administration Guide +--- + +# Registering App in Laserfiche + +### Prerequisites + +- Have developer rights in your Laserfiche account. + +### Steps + +1. Open the [Developer Console](https://developer.laserfiche.com/developer-console.html). + +1. Attempt to Create a New App from Manifest, and upload the manifest provided [here](../assets/LaserficheSharePointIntegrationAppManifest.json). + +1. If the attempt fails because an app with that client ID already exists, find the app with that client id by opening [this url](https://app.laserfiche.com/devconsole/apps/8ee987ea-a0b1-4ca2-85c4-a79b335cd214/config) in a new tab. + +1. One way or another, an app with that client ID should now exist. Open the app and switch from the general tab to the authentication tab. + +1. Copy the URL from your SharePoint LaserficheSignIn page, append the query parameter `?autologin` and add it to the developer console as a new redirect URI. The URI should end with `SitePages/LaserficheSignIn.aspx?autologin`. + + - For example, if your LaserficheSignInPage was named `https://subdomain.sharepoint.com/sites/my-test-site/SitePages/LaserficheSignIn.aspx`, then the redirect URI you would add to the Laserfiche devconsole would be `https://subdomain.sharepoint.com/sites/my-test-site/SitePages/LaserficheSignIn.aspx?autologin`. +1. You should now be able to sign in on each of the components. + +### Next Steps + +[Configure Metadata Mappings](./configuring-metadata-mappings) in the Admin Configuration web part diff --git a/jekyll_files/docs/user-documentation/index.md b/jekyll_files/docs/user-documentation/index.md index 288b7d1..9fc3d06 100644 --- a/jekyll_files/docs/user-documentation/index.md +++ b/jekyll_files/docs/user-documentation/index.md @@ -1,20 +1,23 @@ ---- -layout: default -title: Laserfiche SharePoint Integration User Guide -nav_order: 3 -has_children: true ---- - -# Laserfiche SharePoint Integration User Guide - -## Overview - -Laserfiche SharePoint Integration provides two services: - -### The Save To Laserfiche Command - -This provides the option to export documents directly from SharePoint to Laserfiche. - -### The Repository View - -This web part allows you to view your Laserfiche Repository inside SharePoint webpages. + + +--- +layout: default +title: Laserfiche SharePoint Integration User Guide +nav_order: 3 +has_children: true +--- + +# Laserfiche SharePoint Integration User Guide + +## Overview + +Laserfiche SharePoint Integration provides two services: + +### The Save To Laserfiche Command + +This provides the option to export documents directly from SharePoint to Laserfiche. + +### The Repository View + +This web part allows you to view your Laserfiche Repository inside SharePoint webpages. diff --git a/jekyll_files/docs/user-documentation/repository-explorer-usage.md b/jekyll_files/docs/user-documentation/repository-explorer-usage.md index fbb2fa8..843a415 100644 --- a/jekyll_files/docs/user-documentation/repository-explorer-usage.md +++ b/jekyll_files/docs/user-documentation/repository-explorer-usage.md @@ -1,26 +1,29 @@ ---- -layout: default -title: View Laserfiche Repository from SharePoint -nav_order: 2 -parent: Laserfiche SharePoint Integration User Guide ---- - -# View Laserfiche Repository from SharePoint - -## Usage - -- Navigate to the SharePoint Page containing the Repository Explorer web part. If none exists, consult the Admin Documentation for [How to Add App to SharePoint Site](../admin-documentation/adding-app-to-sp-site). - -- Sign In: To view your folders and documents, authenticate yourself - by clicking on the button labeled "Sign in to Laserfiche" and - subsequently logging in. -- Buttons - - Open: Clicking this button will open the selected entry, if one exists. - - Upload File: Clicking this button will prompt you to select a file to upload to the currently open folder in the Repository Access web part. - - New Folder: Clicking this button will prompt you to input a name for a new folder within the currently open folder. -- Navigation - - Navigation Down - - Double-click on a folder to view its contents within the web part. - - Double-click on a file to view it in Laserfiche Repository. - - Navigation Up - - Use the links in the Breadcrumb Navigation to jump back up to a higher level folder. + + +--- +layout: default +title: View Laserfiche Repository from SharePoint +nav_order: 2 +parent: Laserfiche SharePoint Integration User Guide +--- + +# View Laserfiche Repository from SharePoint + +## Usage + +- Navigate to the SharePoint Page containing the Repository Explorer web part. If none exists, consult the Admin Documentation for [How to Add App to SharePoint Site](../admin-documentation/adding-app-to-sp-site). + +- Sign In: To view your folders and documents, authenticate yourself + by clicking on the button labeled "Sign in to Laserfiche" and + subsequently logging in. +- Buttons + - Open: Clicking this button will open the selected entry, if one exists. + - Upload File: Clicking this button will prompt you to select a file to upload to the currently open folder in the Repository Access web part. + - New Folder: Clicking this button will prompt you to input a name for a new folder within the currently open folder. +- Navigation + - Navigation Down + - Double-click on a folder to view its contents within the web part. + - Double-click on a file to view it in Laserfiche Repository. + - Navigation Up + - Use the links in the Breadcrumb Navigation to jump back up to a higher level folder. diff --git a/jekyll_files/docs/user-documentation/sign-in-usage.md b/jekyll_files/docs/user-documentation/sign-in-usage.md index af645f4..8e53485 100644 --- a/jekyll_files/docs/user-documentation/sign-in-usage.md +++ b/jekyll_files/docs/user-documentation/sign-in-usage.md @@ -1,21 +1,24 @@ ---- -layout: default -title: Save a Document to Laserfiche -nav_order: 1 -parent: Laserfiche SharePoint Integration User Guide ---- - -# Save a Document to Laserfiche - -### Prerequisites - -- Be able to open the documents tab in Laserfiche - -### Steps - -1. Navigate to the Documents tab in your SharePoint Site and choose which document you wish to send to Laserfiche. -1. Right-click on the entry you chose or select the ellipses to the right of the name. - -1. Choose `Save to Laserfiche` from the drop-down menu. -1. If the Document saved, you should see the following message: - + + +--- +layout: default +title: Save a Document to Laserfiche +nav_order: 1 +parent: Laserfiche SharePoint Integration User Guide +--- + +# Save a Document to Laserfiche + +### Prerequisites + +- Be able to open the documents tab in Laserfiche + +### Steps + +1. Navigate to the Documents tab in your SharePoint Site and choose which document you wish to send to Laserfiche. +1. Right-click on the entry you chose or select the ellipses to the right of the name. + +1. Choose `Save to Laserfiche` from the drop-down menu. +1. If the Document saved, you should see the following message: + diff --git a/src/Utils/CreateConfigurations.ts b/src/Utils/CreateConfigurations.ts index b66b33f..faaeddc 100644 --- a/src/Utils/CreateConfigurations.ts +++ b/src/Utils/CreateConfigurations.ts @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { SPHttpClient, SPHttpClientResponse, diff --git a/src/Utils/Funcs.ts b/src/Utils/Funcs.ts index 1e51652..f987037 100644 --- a/src/Utils/Funcs.ts +++ b/src/Utils/Funcs.ts @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { UrlUtils } from '@laserfiche/lf-js-utils'; import { WFieldType } from '@laserfiche/lf-repository-api-client'; import { BaseComponentContext } from '@microsoft/sp-component-base'; @@ -64,4 +67,4 @@ export function getCorrespondingTypeFieldName(fieldType: WFieldType): string { case WFieldType.LongInteger: return 'Long Integer'; } -} \ No newline at end of file +} diff --git a/src/Utils/Types.ts b/src/Utils/Types.ts index 4291698..713b2a2 100644 --- a/src/Utils/Types.ts +++ b/src/Utils/Types.ts @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { IPostEntryWithEdocMetadataRequest } from '@laserfiche/lf-repository-api-client'; import { ActionTypes } from '../webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents'; diff --git a/src/extensions/savetoLaserfiche/CommonDialogs.tsx b/src/extensions/savetoLaserfiche/CommonDialogs.tsx index ab99477..dbbfbfc 100644 --- a/src/extensions/savetoLaserfiche/CommonDialogs.tsx +++ b/src/extensions/savetoLaserfiche/CommonDialogs.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import * as React from 'react'; import styles from './SendToLaserFiche.module.scss'; import { SPComponentLoader } from '@microsoft/sp-loader'; diff --git a/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx b/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx index b630c3b..a882616 100644 --- a/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx +++ b/src/extensions/savetoLaserfiche/GetDocumentDataDialog.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { BaseDialog } from '@microsoft/sp-dialog'; import styles from './SendToLaserFiche.module.scss'; import * as ReactDOM from 'react-dom'; diff --git a/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx b/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx index d599012..66eeb80 100644 --- a/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx +++ b/src/extensions/savetoLaserfiche/SaveDocumentToLaserfiche.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { PostEntryWithEdocMetadataRequest, FileParameter, diff --git a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx index b4bb9f7..60971ba 100644 --- a/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx +++ b/src/extensions/savetoLaserfiche/SaveToLaserficheDialog.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { NgElement, WithProperties } from '@angular/elements'; import { LfLoginComponent } from '@laserfiche/types-lf-ui-components'; import * as React from 'react'; diff --git a/src/extensions/savetoLaserfiche/SavetoLaserficheCommandSet.tsx b/src/extensions/savetoLaserfiche/SavetoLaserficheCommandSet.tsx index 07f0ecd..448d2ab 100644 --- a/src/extensions/savetoLaserfiche/SavetoLaserficheCommandSet.tsx +++ b/src/extensions/savetoLaserfiche/SavetoLaserficheCommandSet.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { Log } from '@microsoft/sp-core-library'; import { GetDocumentDataCustomDialog } from './GetDocumentDataDialog'; import { diff --git a/src/extensions/savetoLaserfiche/loc/en-us.js b/src/extensions/savetoLaserfiche/loc/en-us.js index 236e9f3..f2081ab 100644 --- a/src/extensions/savetoLaserfiche/loc/en-us.js +++ b/src/extensions/savetoLaserfiche/loc/en-us.js @@ -1,6 +1,9 @@ -define([], function() { - return { - "Command1": "Command 1", - "Command2": "Command 2" - } -}); \ No newline at end of file +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +define([], function() { + return { + "Command1": "Command 1", + "Command2": "Command 2" + } +}); diff --git a/src/extensions/savetoLaserfiche/loc/myStrings.d.ts b/src/extensions/savetoLaserfiche/loc/myStrings.d.ts index 52651f8..2877d41 100644 --- a/src/extensions/savetoLaserfiche/loc/myStrings.d.ts +++ b/src/extensions/savetoLaserfiche/loc/myStrings.d.ts @@ -1,9 +1,12 @@ -declare interface ISavetoLaserficheCommandSetStrings { - Command1: string; - Command2: string; -} - -declare module 'SavetoLaserficheCommandSetStrings' { - const strings: ISavetoLaserficheCommandSetStrings; - export = strings; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +declare interface ISavetoLaserficheCommandSetStrings { + Command1: string; + Command2: string; +} + +declare module 'SavetoLaserficheCommandSetStrings' { + const strings: ISavetoLaserficheCommandSetStrings; + export = strings; +} diff --git a/src/index.ts b/src/index.ts index fb81db1..58ae446 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,4 @@ -// A file is required to be in the root of the /src directory by the TypeScript compiler +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +// A file is required to be in the root of the /src directory by the TypeScript compiler diff --git a/src/repository-client/repository-client-types.ts b/src/repository-client/repository-client-types.ts index 5159b3d..de9d6c0 100644 --- a/src/repository-client/repository-client-types.ts +++ b/src/repository-client/repository-client-types.ts @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { IRepositoryApiClientEx } from '@laserfiche/lf-ui-components-services'; export interface IRepositoryApiClientExInternal extends IRepositoryApiClientEx { diff --git a/src/repository-client/repository-client.ts b/src/repository-client/repository-client.ts index c745374..2d3460c 100644 --- a/src/repository-client/repository-client.ts +++ b/src/repository-client/repository-client.ts @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { IRepositoryApiClient, RepositoryApiClient, diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/LaserficheRepositoryAccessWebPartWebPart.ts b/src/webparts/LaserficheRepositoryAccessWebPart/LaserficheRepositoryAccessWebPartWebPart.ts index 050d948..b6e585d 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/LaserficheRepositoryAccessWebPartWebPart.ts +++ b/src/webparts/LaserficheRepositoryAccessWebPart/LaserficheRepositoryAccessWebPartWebPart.ts @@ -1,25 +1,28 @@ -import * as React from 'react'; -import * as ReactDom from 'react-dom'; -import { Version } from '@microsoft/sp-core-library'; -import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; -import LaserficheRepositoryAccessWebPart from './components/LaserficheRepositoryAccessWebPart'; -import { ILaserficheRepositoryAccessWebPartProps } from './components/ILaserficheRepositoryAccessWebPartProps'; - -export default class LaserficheRepositoryAccessWebPartWebPart extends BaseClientSideWebPart<{}> { - public render(): void { - const element: React.ReactElement = - React.createElement(LaserficheRepositoryAccessWebPart, { - context: this.context, - }); - - ReactDom.render(element, this.domElement); - } - - protected onDispose(): void { - ReactDom.unmountComponentAtNode(this.domElement); - } - - protected get dataVersion(): Version { - return Version.parse('1.0'); - } -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import * as ReactDom from 'react-dom'; +import { Version } from '@microsoft/sp-core-library'; +import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; +import LaserficheRepositoryAccessWebPart from './components/LaserficheRepositoryAccessWebPart'; +import { ILaserficheRepositoryAccessWebPartProps } from './components/ILaserficheRepositoryAccessWebPartProps'; + +export default class LaserficheRepositoryAccessWebPartWebPart extends BaseClientSideWebPart<{}> { + public render(): void { + const element: React.ReactElement = + React.createElement(LaserficheRepositoryAccessWebPart, { + context: this.context, + }); + + ReactDom.render(element, this.domElement); + } + + protected onDispose(): void { + ReactDom.unmountComponentAtNode(this.domElement); + } + + protected get dataVersion(): Version { + return Version.parse('1.0'); + } +} diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessDocument.ts b/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessDocument.ts index be197be..521c83a 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessDocument.ts +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessDocument.ts @@ -1,20 +1,23 @@ -export interface IDocument { - key: string; - name: string; - value: string; - parentId: number; - iconName: string; - fileType: string; - modifiedBy: string; - dateModified: string; - dateModifiedValue: number; - title: string; - id: number; - creationTime: string; - lastModifiedTime: string; - entryType: string; - volumeName: string; - templateName: string; - extension: string; - pageCount: number; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +export interface IDocument { + key: string; + name: string; + value: string; + parentId: number; + iconName: string; + fileType: string; + modifiedBy: string; + dateModified: string; + dateModifiedValue: number; + title: string; + id: number; + creationTime: string; + lastModifiedTime: string; + entryType: string; + volumeName: string; + templateName: string; + extension: string; + pageCount: number; +} diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessWebPartProps.ts b/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessWebPartProps.ts index a5ee62d..d21ec98 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessWebPartProps.ts +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/ILaserficheRepositoryAccessWebPartProps.ts @@ -1,5 +1,8 @@ -import { WebPartContext } from '@microsoft/sp-webpart-base'; - -export interface ILaserficheRepositoryAccessWebPartProps { - context: WebPartContext; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from '@microsoft/sp-webpart-base'; + +export interface ILaserficheRepositoryAccessWebPartProps { + context: WebPartContext; +} diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx index a28c052..e36f802 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/LaserficheRepositoryAccessWebPart.tsx @@ -1,247 +1,250 @@ -import * as React from 'react'; -import SvgHtmlIcons from '../components/SVGHtmlIcons'; -import { SPComponentLoader } from '@microsoft/sp-loader'; -import { - AbortedLoginError, - LfLoginComponent, -} from '@laserfiche/types-lf-ui-components'; -import { IRepositoryApiClientExInternal } from '../../../repository-client/repository-client-types'; -import { RepositoryClientExInternal } from '../../../repository-client/repository-client'; -import { - clientId, - LASERFICHE_SIGNIN_PAGE_NAME, - LF_INDIGO_PINK_CSS_URL, - LF_MS_OFFICE_LITE_CSS_URL, - LF_UI_COMPONENTS_URL, - LOGIN_WINDOW_SUCCESS, - ZONE_JS_URL, -} from '../../constants'; -import { NgElement, WithProperties } from '@angular/elements'; -import { useEffect, useState } from 'react'; -import RepositoryViewComponent from './RepositoryViewWebPart'; -require('../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); -require('../../../Assets/CSS/bootstrap.min.css'); -import './LaserficheRepositoryAccess.module.scss'; -import { ILaserficheRepositoryAccessWebPartProps } from './ILaserficheRepositoryAccessWebPartProps'; -import { getRegion, getSPListURL } from '../../../Utils/Funcs'; -import styles from './LaserficheRepositoryAccess.module.scss'; -import { MessageDialog } from '../../../extensions/savetoLaserfiche/CommonDialogs'; - -declare global { - // eslint-disable-next-line - namespace JSX { - interface IntrinsicElements { - // eslint-disable-next-line - ['lf-field-container']: any; - // eslint-disable-next-line - ['lf-login']: any; - } - } -} - -const YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART = - 'You must be a currently licensed Laserfiche Cloud user to use this web part.'; -const FOR_MORE_INFO_VISIT = 'For more information visit'; -const ONCE_SIGNED_IN_YOULL_SEE_REPOSITORY = - "Once signed in you'll be able to view your Laserfiche repository."; - -const needLaserficheSignInPage = `Missing ${LASERFICHE_SIGNIN_PAGE_NAME} SharePoint page. Please refer to the Adding App to SharePoint Site topic in the administration guide for configuration steps.`; -export default function LaserficheRepositoryAccessWebPart( - props: ILaserficheRepositoryAccessWebPartProps -): JSX.Element { - const [webClientUrl, setWebClientUrl] = React.useState(''); - const loginComponent: React.RefObject< - NgElement & WithProperties - > = React.useRef(); - const [loggedIn, setLoggedIn] = useState(false); - const [repoClient, setRepoClient] = useState< - IRepositoryApiClientExInternal | undefined - >(undefined); - const [messageErrorModal, setMessageErrorModal] = useState< - JSX.Element | undefined - >(undefined); - - const region = getRegion(); - - const redirectPage = window.location.origin + window.location.pathname; - - useEffect(() => { - const ensureRepoClientInitializedAsync: () => Promise = async () => { - if (!repoClient) { - const repoClientCreator = new RepositoryClientExInternal(); - const repoClient = - await repoClientCreator.createRepositoryClientAsync(); - setRepoClient(repoClient); - } - }; - - const getAndInitializeRepositoryClientAndServicesAsync: () => Promise = - async () => { - const accessToken = - loginComponent?.current?.authorization_credentials?.accessToken; - setWebClientUrl( - loginComponent?.current?.account_endpoints.webClientUrl - ); - if (accessToken) { - await ensureRepoClientInitializedAsync(); - } else { - // user is not logged in - } - }; - - const initializeComponentAsync: () => Promise = async () => { - await SPComponentLoader.loadScript(ZONE_JS_URL); - await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); - SPComponentLoader.loadCss(LF_INDIGO_PINK_CSS_URL); - SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); - try { - const loginCompleted: () => Promise = async () => { - await getAndInitializeRepositoryClientAndServicesAsync(); - setLoggedIn(true); - }; - const logoutCompleted: () => Promise = async () => { - setLoggedIn(false); - }; - - loginComponent.current.addEventListener( - 'loginCompleted', - loginCompleted - ); - loginComponent.current.addEventListener( - 'logoutCompleted', - logoutCompleted - ); - if (loginComponent.current.authorization_credentials) { - await getAndInitializeRepositoryClientAndServicesAsync(); - setLoggedIn(true); - } - } catch (err) { - console.error(`Unable to initialize repository explorer: ${err}`); - } - }; - - void initializeComponentAsync(); - }, []); - - async function pageConfigurationCheck(): Promise { - try { - const res = await fetch( - `${getSPListURL(props.context, 'Site Pages')}/items`, - { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - } - ); - const sitePages = await res.json(); - for (let o = 0; o < sitePages.value.length; o++) { - const pageName = sitePages.value[o].Title; - if (pageName === LASERFICHE_SIGNIN_PAGE_NAME) { - return true; - } - } - } catch (error) { - console.warn(`Unable to determine if a SharePoint Page with name ${LASERFICHE_SIGNIN_PAGE_NAME} exists.`) - return false; - } - return false; - } - - async function clickLogin(): Promise { - const url = - props.context.pageContext.web.absoluteUrl + - '/SitePages/LaserficheSignIn.aspx?autologin'; - const hasSignIn = await pageConfigurationCheck(); - if (!hasSignIn) { - const mes = ( - { - setMessageErrorModal(undefined); - }} - /> - ); - setMessageErrorModal(mes); - return; - } - const loginWindow = window.open(url, 'loginWindow', 'popup'); - loginWindow.resizeTo(800, 600); - window.addEventListener('message', (event) => { - if (event.origin === window.origin) { - if (event.data === LOGIN_WINDOW_SUCCESS) { - loginWindow.close(); - } else if (event.data) { - const parsedError: AbortedLoginError = event.data; - if (parsedError.ErrorMessage && parsedError.ErrorType) { - loginWindow.close(); - const mes = ( - { - setMessageErrorModal(undefined); - }} - /> - ); - setMessageErrorModal(mes); - } - } - } - }); - } - - return ( - -
- -
-
-
-
- {messageErrorModal !== undefined && ( -
- {messageErrorModal} -
- )} - - {!loggedIn && ( - - {`${YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART} ${FOR_MORE_INFO_VISIT} `} - - laserfiche.com - - {`. ${ONCE_SIGNED_IN_YOULL_SEE_REPOSITORY}`} - - )} -
-
- ); -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import SvgHtmlIcons from '../components/SVGHtmlIcons'; +import { SPComponentLoader } from '@microsoft/sp-loader'; +import { + AbortedLoginError, + LfLoginComponent, +} from '@laserfiche/types-lf-ui-components'; +import { IRepositoryApiClientExInternal } from '../../../repository-client/repository-client-types'; +import { RepositoryClientExInternal } from '../../../repository-client/repository-client'; +import { + clientId, + LASERFICHE_SIGNIN_PAGE_NAME, + LF_INDIGO_PINK_CSS_URL, + LF_MS_OFFICE_LITE_CSS_URL, + LF_UI_COMPONENTS_URL, + LOGIN_WINDOW_SUCCESS, + ZONE_JS_URL, +} from '../../constants'; +import { NgElement, WithProperties } from '@angular/elements'; +import { useEffect, useState } from 'react'; +import RepositoryViewComponent from './RepositoryViewWebPart'; +require('../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); +require('../../../Assets/CSS/bootstrap.min.css'); +import './LaserficheRepositoryAccess.module.scss'; +import { ILaserficheRepositoryAccessWebPartProps } from './ILaserficheRepositoryAccessWebPartProps'; +import { getRegion, getSPListURL } from '../../../Utils/Funcs'; +import styles from './LaserficheRepositoryAccess.module.scss'; +import { MessageDialog } from '../../../extensions/savetoLaserfiche/CommonDialogs'; + +declare global { + // eslint-disable-next-line + namespace JSX { + interface IntrinsicElements { + // eslint-disable-next-line + ['lf-field-container']: any; + // eslint-disable-next-line + ['lf-login']: any; + } + } +} + +const YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART = + 'You must be a currently licensed Laserfiche Cloud user to use this web part.'; +const FOR_MORE_INFO_VISIT = 'For more information visit'; +const ONCE_SIGNED_IN_YOULL_SEE_REPOSITORY = + "Once signed in you'll be able to view your Laserfiche repository."; + +const needLaserficheSignInPage = `Missing ${LASERFICHE_SIGNIN_PAGE_NAME} SharePoint page. Please refer to the Adding App to SharePoint Site topic in the administration guide for configuration steps.`; +export default function LaserficheRepositoryAccessWebPart( + props: ILaserficheRepositoryAccessWebPartProps +): JSX.Element { + const [webClientUrl, setWebClientUrl] = React.useState(''); + const loginComponent: React.RefObject< + NgElement & WithProperties + > = React.useRef(); + const [loggedIn, setLoggedIn] = useState(false); + const [repoClient, setRepoClient] = useState< + IRepositoryApiClientExInternal | undefined + >(undefined); + const [messageErrorModal, setMessageErrorModal] = useState< + JSX.Element | undefined + >(undefined); + + const region = getRegion(); + + const redirectPage = window.location.origin + window.location.pathname; + + useEffect(() => { + const ensureRepoClientInitializedAsync: () => Promise = async () => { + if (!repoClient) { + const repoClientCreator = new RepositoryClientExInternal(); + const repoClient = + await repoClientCreator.createRepositoryClientAsync(); + setRepoClient(repoClient); + } + }; + + const getAndInitializeRepositoryClientAndServicesAsync: () => Promise = + async () => { + const accessToken = + loginComponent?.current?.authorization_credentials?.accessToken; + setWebClientUrl( + loginComponent?.current?.account_endpoints.webClientUrl + ); + if (accessToken) { + await ensureRepoClientInitializedAsync(); + } else { + // user is not logged in + } + }; + + const initializeComponentAsync: () => Promise = async () => { + await SPComponentLoader.loadScript(ZONE_JS_URL); + await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); + SPComponentLoader.loadCss(LF_INDIGO_PINK_CSS_URL); + SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); + try { + const loginCompleted: () => Promise = async () => { + await getAndInitializeRepositoryClientAndServicesAsync(); + setLoggedIn(true); + }; + const logoutCompleted: () => Promise = async () => { + setLoggedIn(false); + }; + + loginComponent.current.addEventListener( + 'loginCompleted', + loginCompleted + ); + loginComponent.current.addEventListener( + 'logoutCompleted', + logoutCompleted + ); + if (loginComponent.current.authorization_credentials) { + await getAndInitializeRepositoryClientAndServicesAsync(); + setLoggedIn(true); + } + } catch (err) { + console.error(`Unable to initialize repository explorer: ${err}`); + } + }; + + void initializeComponentAsync(); + }, []); + + async function pageConfigurationCheck(): Promise { + try { + const res = await fetch( + `${getSPListURL(props.context, 'Site Pages')}/items`, + { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + } + ); + const sitePages = await res.json(); + for (let o = 0; o < sitePages.value.length; o++) { + const pageName = sitePages.value[o].Title; + if (pageName === LASERFICHE_SIGNIN_PAGE_NAME) { + return true; + } + } + } catch (error) { + console.warn(`Unable to determine if a SharePoint Page with name ${LASERFICHE_SIGNIN_PAGE_NAME} exists.`) + return false; + } + return false; + } + + async function clickLogin(): Promise { + const url = + props.context.pageContext.web.absoluteUrl + + '/SitePages/LaserficheSignIn.aspx?autologin'; + const hasSignIn = await pageConfigurationCheck(); + if (!hasSignIn) { + const mes = ( + { + setMessageErrorModal(undefined); + }} + /> + ); + setMessageErrorModal(mes); + return; + } + const loginWindow = window.open(url, 'loginWindow', 'popup'); + loginWindow.resizeTo(800, 600); + window.addEventListener('message', (event) => { + if (event.origin === window.origin) { + if (event.data === LOGIN_WINDOW_SUCCESS) { + loginWindow.close(); + } else if (event.data) { + const parsedError: AbortedLoginError = event.data; + if (parsedError.ErrorMessage && parsedError.ErrorType) { + loginWindow.close(); + const mes = ( + { + setMessageErrorModal(undefined); + }} + /> + ); + setMessageErrorModal(mes); + } + } + } + }); + } + + return ( + +
+ +
+
+
+
+ {messageErrorModal !== undefined && ( +
+ {messageErrorModal} +
+ )} + + {!loggedIn && ( + + {`${YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART} ${FOR_MORE_INFO_VISIT} `} + + laserfiche.com + + {`. ${ONCE_SIGNED_IN_YOULL_SEE_REPOSITORY}`} + + )} +
+
+ ); +} diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx index 64c0c83..8b0b7c5 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/RepositoryViewWebPart.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { NgElement, WithProperties } from '@angular/elements'; import { EntryType, diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/components/SVGHtmlIcons.tsx b/src/webparts/LaserficheRepositoryAccessWebPart/components/SVGHtmlIcons.tsx index 9c54005..6b39007 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/components/SVGHtmlIcons.tsx +++ b/src/webparts/LaserficheRepositoryAccessWebPart/components/SVGHtmlIcons.tsx @@ -1,3485 +1,3488 @@ -import * as React from 'react'; - -export default class SvgHtmlIcons extends React.Component { - public render(): React.ReactElement { - return ( -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Record Folder Icon_8.27.18 - - - - - - - - - - - - Record Series Icon_8.27.18 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Destroyed Folder_8.27.18 - - - - - - - - - - - - - - - - - - Destroyed Record Folder_8.27.18 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Remove Hold - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Add Hold - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Hold Actions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {' '} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ); - } -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; + +export default class SvgHtmlIcons extends React.Component { + public render(): React.ReactElement { + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Record Folder Icon_8.27.18 + + + + + + + + + + + + Record Series Icon_8.27.18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Destroyed Folder_8.27.18 + + + + + + + + + + + + + + + + + + Destroyed Record Folder_8.27.18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Remove Hold + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Add Hold + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hold Actions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {' '} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); + } +} diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/loc/en-us.js b/src/webparts/LaserficheRepositoryAccessWebPart/loc/en-us.js index 262ad02..a11b688 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/loc/en-us.js +++ b/src/webparts/LaserficheRepositoryAccessWebPart/loc/en-us.js @@ -1,10 +1,13 @@ -define([], function() { - return { - "PropertyPaneDescription": "", - "BasicGroupName": "Laserfiche WebPart Properties", - "LaserficheApiUrlFieldLabel": "Enter Laserfiche API URL", - "RepositoryApiUrlFieldLabel":"Enter Laserfiche Repository API URL", - "WebPartTitle":"Enter the WebPart Title", - "LaserficheRedirectUrl":"Enter the Laserfiche Redirect Url" - } -}); \ No newline at end of file +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +define([], function() { + return { + "PropertyPaneDescription": "", + "BasicGroupName": "Laserfiche WebPart Properties", + "LaserficheApiUrlFieldLabel": "Enter Laserfiche API URL", + "RepositoryApiUrlFieldLabel":"Enter Laserfiche Repository API URL", + "WebPartTitle":"Enter the WebPart Title", + "LaserficheRedirectUrl":"Enter the Laserfiche Redirect Url" + } +}); diff --git a/src/webparts/LaserficheRepositoryAccessWebPart/loc/mystrings.d.ts b/src/webparts/LaserficheRepositoryAccessWebPart/loc/mystrings.d.ts index ef65f8c..37ee6eb 100644 --- a/src/webparts/LaserficheRepositoryAccessWebPart/loc/mystrings.d.ts +++ b/src/webparts/LaserficheRepositoryAccessWebPart/loc/mystrings.d.ts @@ -1,11 +1,14 @@ -declare interface ILaserficheRepositoryAccessWebPartWebPartStrings { - PropertyPaneDescription: string; - BasicGroupName: string; - LaserficheApiUrlFieldLabel: string; - RepositoryApiUrlFieldLabel: string; -} - -declare module 'LaserficheRepositoryAccessWebPartWebPartStrings' { - const strings: ILaserficheRepositoryAccessWebPartWebPartStrings; - export = strings; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +declare interface ILaserficheRepositoryAccessWebPartWebPartStrings { + PropertyPaneDescription: string; + BasicGroupName: string; + LaserficheApiUrlFieldLabel: string; + RepositoryApiUrlFieldLabel: string; +} + +declare module 'LaserficheRepositoryAccessWebPartWebPartStrings' { + const strings: ILaserficheRepositoryAccessWebPartWebPartStrings; + export = strings; +} diff --git a/src/webparts/constants.ts b/src/webparts/constants.ts index 44f0a1b..5c3eb03 100644 --- a/src/webparts/constants.ts +++ b/src/webparts/constants.ts @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + export const clientId = '8ee987ea-a0b1-4ca2-85c4-a79b335cd214'; export const LASERFICHE_ADMIN_CONFIGURATION_NAME = 'LaserficheAdminConfiguration'; diff --git a/src/webparts/laserficheAdminConfiguration/LaserficheAdminConfigurationWebPart.ts b/src/webparts/laserficheAdminConfiguration/LaserficheAdminConfigurationWebPart.ts index dc48ce2..4205b20 100644 --- a/src/webparts/laserficheAdminConfiguration/LaserficheAdminConfigurationWebPart.ts +++ b/src/webparts/laserficheAdminConfiguration/LaserficheAdminConfigurationWebPart.ts @@ -1,26 +1,29 @@ -import * as React from 'react'; -import * as ReactDom from 'react-dom'; -import { Version } from '@microsoft/sp-core-library'; -import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; - -import LaserficheAdminConfiguration from './components/LaserficheAdminConfiguration'; -import { ILaserficheAdminConfigurationProps } from './components/ILaserficheAdminConfigurationProps'; - -export default class LaserficheAdminConfigurationWebPart extends BaseClientSideWebPart<{}> { - public render(): void { - const element: React.ReactElement = - React.createElement(LaserficheAdminConfiguration, { - context: this.context, - }); - - ReactDom.render(element, this.domElement); - } - - protected onDispose(): void { - ReactDom.unmountComponentAtNode(this.domElement); - } - - protected get dataVersion(): Version { - return Version.parse('1.0'); - } -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import * as ReactDom from 'react-dom'; +import { Version } from '@microsoft/sp-core-library'; +import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; + +import LaserficheAdminConfiguration from './components/LaserficheAdminConfiguration'; +import { ILaserficheAdminConfigurationProps } from './components/ILaserficheAdminConfigurationProps'; + +export default class LaserficheAdminConfigurationWebPart extends BaseClientSideWebPart<{}> { + public render(): void { + const element: React.ReactElement = + React.createElement(LaserficheAdminConfiguration, { + context: this.context, + }); + + ReactDom.render(element, this.domElement); + } + + protected onDispose(): void { + ReactDom.unmountComponentAtNode(this.domElement); + } + + protected get dataVersion(): Version { + return Version.parse('1.0'); + } +} diff --git a/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/AddNewManageConfiguration.tsx b/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/AddNewManageConfiguration.tsx index ef74a61..f151956 100644 --- a/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/AddNewManageConfiguration.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/AddNewManageConfiguration.tsx @@ -1,247 +1,250 @@ -import * as React from 'react'; -import { IAddNewManageConfigurationProps } from './IAddNewManageConfigurationProps'; -import ManageConfiguration from '../ManageConfigurationComponent'; -import { useState } from 'react'; -import { - ActionTypes, - LfFolder, - ProfileConfiguration, - validateNewConfiguration, -} from '../ProfileConfigurationComponents'; -import { SPHttpClient, ISPHttpClientOptions } from '@microsoft/sp-http'; -import { IListItem } from '../IListItem'; -import { - LASERFICHE_ADMIN_CONFIGURATION_NAME, - MANAGE_CONFIGURATIONS, -} from '../../../constants'; -import { getSPListURL } from '../../../../Utils/Funcs'; -import styles from './../LaserficheAdminConfiguration.module.scss'; -require('../../../../Assets/CSS/bootstrap.min.css'); -require('./../../../../Assets/CSS/commonStyles.css'); -require('../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); - -declare global { - // eslint-disable-next-line - namespace JSX { - interface IntrinsicElements { - // eslint-disable-next-line - ['lf-repository-browser']: any; - } - } -} - -const rootFolder: LfFolder = { - id: '1', - path: '\\', -}; - -const initialConfig: ProfileConfiguration = { - selectedFolder: rootFolder, - DocumentName: 'FileName', - ConfigurationName: '', - mappedFields: [], - Action: ActionTypes.COPY, -}; - -export default function AddNewManageConfiguration( - props: IAddNewManageConfigurationProps -): JSX.Element { - const [profileConfig, setProfileConfig] = useState(initialConfig); - const [validate, setValidate] = useState(false); - const [configNameError, setConfigNameError] = useState(undefined); - const handleProfileConfigUpdate: ( - profileConfig: ProfileConfiguration - ) => void = (profileConfig: ProfileConfiguration) => { - setValidate(false); - setProfileConfig(profileConfig); - }; - function handleProfileConfigNameChange(e: React.ChangeEvent): void { - const newName = (e.target as HTMLInputElement).value; - const profileConfiguration = { ...profileConfig }; - profileConfiguration.ConfigurationName = newName; - setValidate(false); - setProfileConfig(profileConfiguration); - } - - async function saveSPConfigurationsAsync( - Id: string, - configsToSave: ProfileConfiguration[] - ): Promise { - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items(${Id})`; - const body: string = JSON.stringify({ - Title: MANAGE_CONFIGURATIONS, - JsonValue: JSON.stringify(configsToSave), - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - 'IF-MATCH': '*', - 'X-HTTP-Method': 'MERGE', - }, - body: body, - }; - const response = await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - if (!response.ok) { - throw Error(response.statusText); - } - } - - async function saveNewManageConfigurationAsync(): Promise { - setValidate(true); - setConfigNameError(undefined); - const validate = validateNewConfiguration(profileConfig); - if (validate) { - const manageConfigurationConfig: IListItem[] = await GetItemIdForManageConfigurations(); - if (manageConfigurationConfig?.length > 0) { - const configWithCurrentName = manageConfigurationConfig[0]; - const savedProfileConfigurations: ProfileConfiguration[] = - JSON.parse(configWithCurrentName.JsonValue) ?? []; - const profileExists = savedProfileConfigurations.find( - (config) => - config.ConfigurationName === profileConfig.ConfigurationName - ); - if (!profileExists) { - const allConfigurations = - savedProfileConfigurations.concat(profileConfig); - await saveSPConfigurationsAsync( - configWithCurrentName.Id, - allConfigurations - ); - } else { - setConfigNameError( - - Profile with this name already exists, please provide different - name - - ); - } - } else { - await saveNewPageConfigurationAsync(); - } - } else { - throw Error('Invalid configuration. Please review any errors.'); - } - } - - async function GetItemIdForManageConfigurations(): Promise { - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_CONFIGURATIONS}'`; - const res = await fetch(restApiUrl, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }); - const results = await res.json(); - if (results.value.length > 0) { - return results.value as IListItem[]; - } else { - return null; - } - } - - async function saveNewPageConfigurationAsync(): Promise { - const profileConfigAsString = JSON.stringify([profileConfig]); - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items`; - const body: string = JSON.stringify({ - Title: MANAGE_CONFIGURATIONS, - JsonValue: profileConfigAsString, - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - }, - body: body, - }; - const response = await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - if (!response.ok) { - throw Error(response.statusText); - } - } - - let configNameValidation: JSX.Element | undefined; - if (validate) { - if (configNameError) { - configNameValidation = configNameError; - } else if ( - !profileConfig.ConfigurationName || - profileConfig.ConfigurationName.length === 0 - ) { - configNameValidation = ( - Please specify a name for this configuration - ); - } else if (/[^ A-Za-z0-9]/.test(profileConfig.ConfigurationName)) { - // TODO can we allow special characters - configNameValidation = ( - Invalid Name, only alphanumeric or space are allowed. - ); - } - } - - const header = ( -
-
Add New Profile
-
- ); - const extraConfiguration = ( - <> -
- -
- - -
-
- - ); - return ( - - ); -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import { IAddNewManageConfigurationProps } from './IAddNewManageConfigurationProps'; +import ManageConfiguration from '../ManageConfigurationComponent'; +import { useState } from 'react'; +import { + ActionTypes, + LfFolder, + ProfileConfiguration, + validateNewConfiguration, +} from '../ProfileConfigurationComponents'; +import { SPHttpClient, ISPHttpClientOptions } from '@microsoft/sp-http'; +import { IListItem } from '../IListItem'; +import { + LASERFICHE_ADMIN_CONFIGURATION_NAME, + MANAGE_CONFIGURATIONS, +} from '../../../constants'; +import { getSPListURL } from '../../../../Utils/Funcs'; +import styles from './../LaserficheAdminConfiguration.module.scss'; +require('../../../../Assets/CSS/bootstrap.min.css'); +require('./../../../../Assets/CSS/commonStyles.css'); +require('../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); + +declare global { + // eslint-disable-next-line + namespace JSX { + interface IntrinsicElements { + // eslint-disable-next-line + ['lf-repository-browser']: any; + } + } +} + +const rootFolder: LfFolder = { + id: '1', + path: '\\', +}; + +const initialConfig: ProfileConfiguration = { + selectedFolder: rootFolder, + DocumentName: 'FileName', + ConfigurationName: '', + mappedFields: [], + Action: ActionTypes.COPY, +}; + +export default function AddNewManageConfiguration( + props: IAddNewManageConfigurationProps +): JSX.Element { + const [profileConfig, setProfileConfig] = useState(initialConfig); + const [validate, setValidate] = useState(false); + const [configNameError, setConfigNameError] = useState(undefined); + const handleProfileConfigUpdate: ( + profileConfig: ProfileConfiguration + ) => void = (profileConfig: ProfileConfiguration) => { + setValidate(false); + setProfileConfig(profileConfig); + }; + function handleProfileConfigNameChange(e: React.ChangeEvent): void { + const newName = (e.target as HTMLInputElement).value; + const profileConfiguration = { ...profileConfig }; + profileConfiguration.ConfigurationName = newName; + setValidate(false); + setProfileConfig(profileConfiguration); + } + + async function saveSPConfigurationsAsync( + Id: string, + configsToSave: ProfileConfiguration[] + ): Promise { + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items(${Id})`; + const body: string = JSON.stringify({ + Title: MANAGE_CONFIGURATIONS, + JsonValue: JSON.stringify(configsToSave), + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + 'IF-MATCH': '*', + 'X-HTTP-Method': 'MERGE', + }, + body: body, + }; + const response = await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + if (!response.ok) { + throw Error(response.statusText); + } + } + + async function saveNewManageConfigurationAsync(): Promise { + setValidate(true); + setConfigNameError(undefined); + const validate = validateNewConfiguration(profileConfig); + if (validate) { + const manageConfigurationConfig: IListItem[] = await GetItemIdForManageConfigurations(); + if (manageConfigurationConfig?.length > 0) { + const configWithCurrentName = manageConfigurationConfig[0]; + const savedProfileConfigurations: ProfileConfiguration[] = + JSON.parse(configWithCurrentName.JsonValue) ?? []; + const profileExists = savedProfileConfigurations.find( + (config) => + config.ConfigurationName === profileConfig.ConfigurationName + ); + if (!profileExists) { + const allConfigurations = + savedProfileConfigurations.concat(profileConfig); + await saveSPConfigurationsAsync( + configWithCurrentName.Id, + allConfigurations + ); + } else { + setConfigNameError( + + Profile with this name already exists, please provide different + name + + ); + } + } else { + await saveNewPageConfigurationAsync(); + } + } else { + throw Error('Invalid configuration. Please review any errors.'); + } + } + + async function GetItemIdForManageConfigurations(): Promise { + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_CONFIGURATIONS}'`; + const res = await fetch(restApiUrl, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const results = await res.json(); + if (results.value.length > 0) { + return results.value as IListItem[]; + } else { + return null; + } + } + + async function saveNewPageConfigurationAsync(): Promise { + const profileConfigAsString = JSON.stringify([profileConfig]); + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items`; + const body: string = JSON.stringify({ + Title: MANAGE_CONFIGURATIONS, + JsonValue: profileConfigAsString, + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + }, + body: body, + }; + const response = await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + if (!response.ok) { + throw Error(response.statusText); + } + } + + let configNameValidation: JSX.Element | undefined; + if (validate) { + if (configNameError) { + configNameValidation = configNameError; + } else if ( + !profileConfig.ConfigurationName || + profileConfig.ConfigurationName.length === 0 + ) { + configNameValidation = ( + Please specify a name for this configuration + ); + } else if (/[^ A-Za-z0-9]/.test(profileConfig.ConfigurationName)) { + // TODO can we allow special characters + configNameValidation = ( + Invalid Name, only alphanumeric or space are allowed. + ); + } + } + + const header = ( +
+
Add New Profile
+
+ ); + const extraConfiguration = ( + <> +
+ +
+ + +
+
+ + ); + return ( + + ); +} diff --git a/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/IAddNewManageConfigurationProps.ts b/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/IAddNewManageConfigurationProps.ts index dac8d8c..7f1341c 100644 --- a/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/IAddNewManageConfigurationProps.ts +++ b/src/webparts/laserficheAdminConfiguration/components/AddNewManageConfiguration/IAddNewManageConfigurationProps.ts @@ -1,8 +1,11 @@ -import { WebPartContext } from '@microsoft/sp-webpart-base'; -import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; - -export interface IAddNewManageConfigurationProps { - context: WebPartContext; - repoClient: IRepositoryApiClientExInternal; - loggedIn: boolean; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from '@microsoft/sp-webpart-base'; +import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; + +export interface IAddNewManageConfigurationProps { + context: WebPartContext; + repoClient: IRepositoryApiClientExInternal; + loggedIn: boolean; +} diff --git a/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/AdminMainPage.tsx b/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/AdminMainPage.tsx index 3b9ea39..40e97a2 100644 --- a/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/AdminMainPage.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/AdminMainPage.tsx @@ -1,70 +1,73 @@ -import * as React from 'react'; -import { NavLink } from 'react-router-dom'; -import { useEffect } from 'react'; -import { IAdminPageProps } from './IAdminPageProps'; -import { CreateConfigurations } from '../../../../Utils/CreateConfigurations'; -require('../../../../Assets/CSS/bootstrap.min.css'); -require('./../../../../Assets/CSS/commonStyles.css'); -import styles from './../LaserficheAdminConfiguration.module.scss'; - -declare global { - // eslint-disable-next-line - namespace JSX { - interface IntrinsicElements { - // eslint-disable-next-line - ['lf-login']: any; - } - } -} - -export default function AdminMainPage(props: IAdminPageProps): JSX.Element { - useEffect(() => { - CreateConfigurations.ensureAdminConfigListCreatedAsync(props.context).catch( - (err: Error) => { - console.warn( - `Error: ${err.message}` - ); - } - ); - }, []); - - const linkData: LinkInfo[] = [ - { route: '/HomePage', name: 'About' }, - { route: '/ManageConfigurationsPage', name: 'Profiles' }, - { route: '/ManageMappingsPage', name: 'Profile Mapping' }, - ]; - - return ( -
-
- Profile Editor - {props.loggedIn && } -
-
- ); -} - -interface LinkInfo { - route: string; - name: string; -} - -function Links(props: { linkData: LinkInfo[] }): JSX.Element { - const linkEls = props.linkData.map((link: LinkInfo) => ( - - - {link.name} - - - )); - return
{linkEls}
; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import { NavLink } from 'react-router-dom'; +import { useEffect } from 'react'; +import { IAdminPageProps } from './IAdminPageProps'; +import { CreateConfigurations } from '../../../../Utils/CreateConfigurations'; +require('../../../../Assets/CSS/bootstrap.min.css'); +require('./../../../../Assets/CSS/commonStyles.css'); +import styles from './../LaserficheAdminConfiguration.module.scss'; + +declare global { + // eslint-disable-next-line + namespace JSX { + interface IntrinsicElements { + // eslint-disable-next-line + ['lf-login']: any; + } + } +} + +export default function AdminMainPage(props: IAdminPageProps): JSX.Element { + useEffect(() => { + CreateConfigurations.ensureAdminConfigListCreatedAsync(props.context).catch( + (err: Error) => { + console.warn( + `Error: ${err.message}` + ); + } + ); + }, []); + + const linkData: LinkInfo[] = [ + { route: '/HomePage', name: 'About' }, + { route: '/ManageConfigurationsPage', name: 'Profiles' }, + { route: '/ManageMappingsPage', name: 'Profile Mapping' }, + ]; + + return ( +
+
+ Profile Editor + {props.loggedIn && } +
+
+ ); +} + +interface LinkInfo { + route: string; + name: string; +} + +function Links(props: { linkData: LinkInfo[] }): JSX.Element { + const linkEls = props.linkData.map((link: LinkInfo) => ( + + + {link.name} + + + )); + return
{linkEls}
; +} diff --git a/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/IAdminPageProps.ts b/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/IAdminPageProps.ts index 584880b..a43245e 100644 --- a/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/IAdminPageProps.ts +++ b/src/webparts/laserficheAdminConfiguration/components/AdminMainPage/IAdminPageProps.ts @@ -1,8 +1,11 @@ -import { WebPartContext } from '@microsoft/sp-webpart-base'; -import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; - -export interface IAdminPageProps { - context: WebPartContext; - loggedIn: boolean; - repoClient: IRepositoryApiClientExInternal; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from '@microsoft/sp-webpart-base'; +import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; + +export interface IAdminPageProps { + context: WebPartContext; + loggedIn: boolean; + repoClient: IRepositoryApiClientExInternal; +} diff --git a/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/EditManageConfiguration.tsx b/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/EditManageConfiguration.tsx index 136f6d2..44630c7 100644 --- a/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/EditManageConfiguration.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/EditManageConfiguration.tsx @@ -1,178 +1,181 @@ -import * as React from 'react'; -import { SPHttpClient, ISPHttpClientOptions } from '@microsoft/sp-http'; -import { IEditManageConfigurationProps } from './IEditManageConfigurationProps'; -import { IListItem } from '../IListItem'; - -import { useEffect, useState } from 'react'; -import { - ProfileHeader, - validateNewConfiguration, -} from '../ProfileConfigurationComponents'; -import ManageConfiguration from '../ManageConfigurationComponent'; -import { ProfileConfiguration } from '../ProfileConfigurationComponents'; -import { - LASERFICHE_ADMIN_CONFIGURATION_NAME, - MANAGE_CONFIGURATIONS, -} from '../../../constants'; -import { getSPListURL } from '../../../../Utils/Funcs'; -require('../../../../Assets/CSS/bootstrap.min.css'); -require('./../../../../Assets/CSS/commonStyles.css'); -require('../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); - -declare global { - // eslint-disable-next-line - namespace JSX { - interface IntrinsicElements { - // eslint-disable-next-line - ['lf-login']: any; - // eslint-disable-next-line - ['lf-repository-browser']: any; - } - } -} - -export default function EditManageConfiguration( - props: IEditManageConfigurationProps -): JSX.Element { - const [profileConfig, setProfileConfig] = useState< - ProfileConfiguration | undefined - >(undefined); - - const [validate, setValidate] = useState(false); - const handleProfileConfigUpdate: ( - profileConfig: ProfileConfiguration - ) => void = (profileConfig: ProfileConfiguration) => { - setValidate(false); - setProfileConfig(profileConfig); - }; - - async function GetItemIdForManageConfigurations(): Promise { - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_CONFIGURATIONS}'`; - const res = await fetch(restApiUrl, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }); - const results = await res.json(); - if (results.value.length > 0) { - return results.value as IListItem[]; - } else { - return null; - } - } - - useEffect(() => { - const initializeComponentAsync: () => Promise = async () => { - try { - const results = await GetItemIdForManageConfigurations(); - const configurationName = props.match.params.name; - if (results?.length > 0) { - const profileConfigs = JSON.parse(results[0].JsonValue); - if (profileConfigs.length > 0) { - for (let i = 0; i < profileConfigs.length; i++) { - if (profileConfigs[i].ConfigurationName === configurationName) { - const selectedConfig: ProfileConfiguration = profileConfigs[i]; - setProfileConfig(selectedConfig); - } - } - } - } - } catch (err) { - console.error(`Error initializing edit configuration page: ${err}`); - } - }; - void initializeComponentAsync(); - }, []); - - async function saveEditExistingConfigurationAsync(): Promise { - setValidate(true); - const validate = validateNewConfiguration(profileConfig); - if (validate) { - const manageConfigurationConfig: IListItem[] = - await GetItemIdForManageConfigurations(); - if (manageConfigurationConfig?.length > 0) { - const configWithCurrentName = manageConfigurationConfig[0]; - const savedProfileConfigurations: ProfileConfiguration[] = JSON.parse( - configWithCurrentName.JsonValue - ); - const profileIndex = savedProfileConfigurations.findIndex( - (config) => - config.ConfigurationName === profileConfig.ConfigurationName - ); - if (profileIndex !== -1) { - savedProfileConfigurations[profileIndex] = profileConfig; - const configsToSave = savedProfileConfigurations; - await saveSPConfigurationsAsync( - configWithCurrentName.Id, - configsToSave - ); - } else { - // error this config should exist - } - } - } else { - throw Error('Invalid configuration. Please review any errors.'); - } - } - - async function saveSPConfigurationsAsync( - Id: string, - configsToSave: ProfileConfiguration[] - ): Promise { - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items(${Id})`; - const body: string = JSON.stringify({ - Title: MANAGE_CONFIGURATIONS, - JsonValue: JSON.stringify(configsToSave), - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - 'IF-MATCH': '*', - 'X-HTTP-Method': 'MERGE', - }, - body: body, - }; - const response = await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - if (!response.ok) { - throw Error(response.statusText); - } - } - - const header = ( -
- -
- ); - return ( - <> - {profileConfig && ( - - )} - - ); -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import { SPHttpClient, ISPHttpClientOptions } from '@microsoft/sp-http'; +import { IEditManageConfigurationProps } from './IEditManageConfigurationProps'; +import { IListItem } from '../IListItem'; + +import { useEffect, useState } from 'react'; +import { + ProfileHeader, + validateNewConfiguration, +} from '../ProfileConfigurationComponents'; +import ManageConfiguration from '../ManageConfigurationComponent'; +import { ProfileConfiguration } from '../ProfileConfigurationComponents'; +import { + LASERFICHE_ADMIN_CONFIGURATION_NAME, + MANAGE_CONFIGURATIONS, +} from '../../../constants'; +import { getSPListURL } from '../../../../Utils/Funcs'; +require('../../../../Assets/CSS/bootstrap.min.css'); +require('./../../../../Assets/CSS/commonStyles.css'); +require('../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); + +declare global { + // eslint-disable-next-line + namespace JSX { + interface IntrinsicElements { + // eslint-disable-next-line + ['lf-login']: any; + // eslint-disable-next-line + ['lf-repository-browser']: any; + } + } +} + +export default function EditManageConfiguration( + props: IEditManageConfigurationProps +): JSX.Element { + const [profileConfig, setProfileConfig] = useState< + ProfileConfiguration | undefined + >(undefined); + + const [validate, setValidate] = useState(false); + const handleProfileConfigUpdate: ( + profileConfig: ProfileConfiguration + ) => void = (profileConfig: ProfileConfiguration) => { + setValidate(false); + setProfileConfig(profileConfig); + }; + + async function GetItemIdForManageConfigurations(): Promise { + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_CONFIGURATIONS}'`; + const res = await fetch(restApiUrl, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const results = await res.json(); + if (results.value.length > 0) { + return results.value as IListItem[]; + } else { + return null; + } + } + + useEffect(() => { + const initializeComponentAsync: () => Promise = async () => { + try { + const results = await GetItemIdForManageConfigurations(); + const configurationName = props.match.params.name; + if (results?.length > 0) { + const profileConfigs = JSON.parse(results[0].JsonValue); + if (profileConfigs.length > 0) { + for (let i = 0; i < profileConfigs.length; i++) { + if (profileConfigs[i].ConfigurationName === configurationName) { + const selectedConfig: ProfileConfiguration = profileConfigs[i]; + setProfileConfig(selectedConfig); + } + } + } + } + } catch (err) { + console.error(`Error initializing edit configuration page: ${err}`); + } + }; + void initializeComponentAsync(); + }, []); + + async function saveEditExistingConfigurationAsync(): Promise { + setValidate(true); + const validate = validateNewConfiguration(profileConfig); + if (validate) { + const manageConfigurationConfig: IListItem[] = + await GetItemIdForManageConfigurations(); + if (manageConfigurationConfig?.length > 0) { + const configWithCurrentName = manageConfigurationConfig[0]; + const savedProfileConfigurations: ProfileConfiguration[] = JSON.parse( + configWithCurrentName.JsonValue + ); + const profileIndex = savedProfileConfigurations.findIndex( + (config) => + config.ConfigurationName === profileConfig.ConfigurationName + ); + if (profileIndex !== -1) { + savedProfileConfigurations[profileIndex] = profileConfig; + const configsToSave = savedProfileConfigurations; + await saveSPConfigurationsAsync( + configWithCurrentName.Id, + configsToSave + ); + } else { + // error this config should exist + } + } + } else { + throw Error('Invalid configuration. Please review any errors.'); + } + } + + async function saveSPConfigurationsAsync( + Id: string, + configsToSave: ProfileConfiguration[] + ): Promise { + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items(${Id})`; + const body: string = JSON.stringify({ + Title: MANAGE_CONFIGURATIONS, + JsonValue: JSON.stringify(configsToSave), + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + 'IF-MATCH': '*', + 'X-HTTP-Method': 'MERGE', + }, + body: body, + }; + const response = await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + if (!response.ok) { + throw Error(response.statusText); + } + } + + const header = ( +
+ +
+ ); + return ( + <> + {profileConfig && ( + + )} + + ); +} diff --git a/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/IEditManageConfigurationProps.ts b/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/IEditManageConfigurationProps.ts index 6b40225..301a170 100644 --- a/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/IEditManageConfigurationProps.ts +++ b/src/webparts/laserficheAdminConfiguration/components/EditManageConfiguration/IEditManageConfigurationProps.ts @@ -1,10 +1,13 @@ -import { WebPartContext } from '@microsoft/sp-webpart-base'; -import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; - -export interface IEditManageConfigurationProps { - context: WebPartContext; - // eslint-disable-next-line - match: any; - loggedIn: boolean; - repoClient: IRepositoryApiClientExInternal; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from '@microsoft/sp-webpart-base'; +import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; + +export interface IEditManageConfigurationProps { + context: WebPartContext; + // eslint-disable-next-line + match: any; + loggedIn: boolean; + repoClient: IRepositoryApiClientExInternal; +} diff --git a/src/webparts/laserficheAdminConfiguration/components/HomePage/HomePage.tsx b/src/webparts/laserficheAdminConfiguration/components/HomePage/HomePage.tsx index 5ac945e..70a6a56 100644 --- a/src/webparts/laserficheAdminConfiguration/components/HomePage/HomePage.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/HomePage/HomePage.tsx @@ -1,67 +1,70 @@ -import * as React from 'react'; -require('./../../../../Assets/CSS/commonStyles.css'); -require('../../../../Assets/CSS/bootstrap.min.css'); - -const YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART = - 'You must be a currently licensed Laserfiche Cloud user to use this web part.'; -const FOR_MORE_INFO_VISIT = 'For more information visit'; -const USE_LASERFICHE_ADMIN_PAGE_TO_EDIT_SP_LF_CONFIG_SIGN_IN_AND_SELECT_TASK_TO_COMPLETE = - 'Use the Laserfiche Administration page to edit your SharePoint and Laserfiche configuration. Sign in and select the task you want to perform from the menu at the top of this section.'; -const PROFILES_GOVERN_HOW_SP_SAVED_TO_LF_CAN_CREATE_MULTIPLE_PROFILES_FOR_DIFFERENT_SP_CONTENT_TYPES = - 'Profiles govern how documents in SharePoint will be saved to Laserfiche. You can create multiple profiles for different SharePoint content types. For example, if you want applications stored differently than invoices, create separate profiles for each content type.'; -const IN_THIS_TAB_CAN_MAP_SPECIFIC_SP_CONTENT_TYPE_TO_LF_PROFILE_PROFILE_THEN_USED_TO_SAVE_SP_DOCS_WITH_THAT_CONTENT_TYPE = - 'In this tab, you can map a specific SharePoint content type to a corresponding Laserfiche profile. This profile will then be used when saving all documents of the specified SharePoint content type.'; - -export default function HomePage(): JSX.Element { - return ( -
-
-

- {`${YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART} ${FOR_MORE_INFO_VISIT} `} - - laserfiche.com - - {`.`} -

-

- { - USE_LASERFICHE_ADMIN_PAGE_TO_EDIT_SP_LF_CONFIG_SIGN_IN_AND_SELECT_TASK_TO_COMPLETE - } -

-

- For more information, see the{' '} - - help documentation. - -

-
-

- Profiles -

-

- - { - PROFILES_GOVERN_HOW_SP_SAVED_TO_LF_CAN_CREATE_MULTIPLE_PROFILES_FOR_DIFFERENT_SP_CONTENT_TYPES - } - -

-

- Profile Mapping -

-

- - { - IN_THIS_TAB_CAN_MAP_SPECIFIC_SP_CONTENT_TYPE_TO_LF_PROFILE_PROFILE_THEN_USED_TO_SAVE_SP_DOCS_WITH_THAT_CONTENT_TYPE - } - -

-
-
-
- ); -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +require('./../../../../Assets/CSS/commonStyles.css'); +require('../../../../Assets/CSS/bootstrap.min.css'); + +const YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART = + 'You must be a currently licensed Laserfiche Cloud user to use this web part.'; +const FOR_MORE_INFO_VISIT = 'For more information visit'; +const USE_LASERFICHE_ADMIN_PAGE_TO_EDIT_SP_LF_CONFIG_SIGN_IN_AND_SELECT_TASK_TO_COMPLETE = + 'Use the Laserfiche Administration page to edit your SharePoint and Laserfiche configuration. Sign in and select the task you want to perform from the menu at the top of this section.'; +const PROFILES_GOVERN_HOW_SP_SAVED_TO_LF_CAN_CREATE_MULTIPLE_PROFILES_FOR_DIFFERENT_SP_CONTENT_TYPES = + 'Profiles govern how documents in SharePoint will be saved to Laserfiche. You can create multiple profiles for different SharePoint content types. For example, if you want applications stored differently than invoices, create separate profiles for each content type.'; +const IN_THIS_TAB_CAN_MAP_SPECIFIC_SP_CONTENT_TYPE_TO_LF_PROFILE_PROFILE_THEN_USED_TO_SAVE_SP_DOCS_WITH_THAT_CONTENT_TYPE = + 'In this tab, you can map a specific SharePoint content type to a corresponding Laserfiche profile. This profile will then be used when saving all documents of the specified SharePoint content type.'; + +export default function HomePage(): JSX.Element { + return ( +
+
+

+ {`${YOU_MUST_BE_CLOUD_USER_TO_USE_WEB_PART} ${FOR_MORE_INFO_VISIT} `} + + laserfiche.com + + {`.`} +

+

+ { + USE_LASERFICHE_ADMIN_PAGE_TO_EDIT_SP_LF_CONFIG_SIGN_IN_AND_SELECT_TASK_TO_COMPLETE + } +

+

+ For more information, see the{' '} + + help documentation. + +

+
+

+ Profiles +

+

+ + { + PROFILES_GOVERN_HOW_SP_SAVED_TO_LF_CAN_CREATE_MULTIPLE_PROFILES_FOR_DIFFERENT_SP_CONTENT_TYPES + } + +

+

+ Profile Mapping +

+

+ + { + IN_THIS_TAB_CAN_MAP_SPECIFIC_SP_CONTENT_TYPE_TO_LF_PROFILE_PROFILE_THEN_USED_TO_SAVE_SP_DOCS_WITH_THAT_CONTENT_TYPE + } + +

+
+
+
+ ); +} diff --git a/src/webparts/laserficheAdminConfiguration/components/ILaserficheAdminConfigurationProps.ts b/src/webparts/laserficheAdminConfiguration/components/ILaserficheAdminConfigurationProps.ts index d590a53..162795a 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ILaserficheAdminConfigurationProps.ts +++ b/src/webparts/laserficheAdminConfiguration/components/ILaserficheAdminConfigurationProps.ts @@ -1,5 +1,8 @@ -import { WebPartContext } from "@microsoft/sp-webpart-base"; - -export interface ILaserficheAdminConfigurationProps { - context: WebPartContext; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from "@microsoft/sp-webpart-base"; + +export interface ILaserficheAdminConfigurationProps { + context: WebPartContext; +} diff --git a/src/webparts/laserficheAdminConfiguration/components/IListItem.ts b/src/webparts/laserficheAdminConfiguration/components/IListItem.ts index 5960d79..64ad524 100644 --- a/src/webparts/laserficheAdminConfiguration/components/IListItem.ts +++ b/src/webparts/laserficheAdminConfiguration/components/IListItem.ts @@ -1,5 +1,8 @@ -export interface IListItem { - Id: string; - Title: string; - JsonValue: string; // TODO type JSON value for each config page -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +export interface IListItem { + Id: string; + Title: string; + JsonValue: string; // TODO type JSON value for each config page +} diff --git a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx index 8870235..8b0ed12 100644 --- a/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/LaserficheAdminConfiguration.tsx @@ -1,291 +1,294 @@ -import * as React from 'react'; -import { useState } from 'react'; -import { ILaserficheAdminConfigurationProps } from './ILaserficheAdminConfigurationProps'; -import { HashRouter, Route, Switch } from 'react-router-dom'; -import { Stack, StackItem } from 'office-ui-fabric-react'; -import AdminMainPage from '../components/AdminMainPage/AdminMainPage'; -import HomePage from './HomePage/HomePage'; -import ManageConfigurationsPage from './ManageConfigurationsPage/ManageConfigurationsPage'; -import ManageMappingsPage from './ManageMappingsPage/ManageMappingsPage'; -import EditManageConfiguration from './EditManageConfiguration/EditManageConfiguration'; -import AddNewManageConfiguration from './AddNewManageConfiguration/AddNewManageConfiguration'; -import { - clientId, - LASERFICHE_SIGNIN_PAGE_NAME, - LF_INDIGO_PINK_CSS_URL, - LF_MS_OFFICE_LITE_CSS_URL, - LF_UI_COMPONENTS_URL, - LOGIN_WINDOW_SUCCESS, - ZONE_JS_URL, -} from '../../constants'; -import { NgElement, WithProperties } from '@angular/elements'; -import { - AbortedLoginError, - LfLoginComponent, -} from '@laserfiche/types-lf-ui-components'; -import { RepositoryClientExInternal } from '../../../repository-client/repository-client'; -import { IRepositoryApiClientExInternal } from '../../../repository-client/repository-client-types'; -import { SPComponentLoader } from '@microsoft/sp-loader'; -import { getRegion, getSPListURL } from '../../../Utils/Funcs'; -import styles from './LaserficheAdminConfiguration.module.scss'; -import { SPPermission } from '@microsoft/sp-page-context'; -import { MessageDialog } from '../../../extensions/savetoLaserfiche/CommonDialogs'; - -const YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN = - 'You do not have the necessary rights to view or edit the Laserfiche SharePoint Integration configuration. Please contact your administrator for help.'; - -const needLaserficheSignInPage = `Missing "${LASERFICHE_SIGNIN_PAGE_NAME}" SharePoint page. Please refer to the Adding App to SharePoint Site topic in the administration guide for configuration steps.`; -export default function LaserficheAdminConfiguration( - props: ILaserficheAdminConfigurationProps -): JSX.Element { - const loginComponent: React.RefObject< - NgElement & WithProperties - > = React.createRef(); - const [loggedIn, setLoggedIn] = useState(false); - const [repoClient, setRepoClient] = useState< - IRepositoryApiClientExInternal | undefined - >(undefined); - const [messageErrorModal, setMessageErrorModal] = useState< - JSX.Element | undefined - >(undefined); - - const region = getRegion(); - - const redirectPage = window.location.origin + window.location.pathname; - - function isAdmin(): boolean { - const permission = new SPPermission( - props.context.pageContext.web.permissions.value - ); - const isFullControl = permission.hasPermission(SPPermission.manageWeb); - return isFullControl; - } - - async function getAndInitializeRepositoryClientAndServicesAsync(): Promise { - const accessToken = - loginComponent?.current?.authorization_credentials?.accessToken; - if (accessToken) { - await ensureRepoClientInitializedAsync(); - } else { - // user is not logged in - } - } - - async function ensureRepoClientInitializedAsync(): Promise { - if (!repoClient) { - const repoClientCreator = new RepositoryClientExInternal(); - const newRepoClient = - await repoClientCreator.createRepositoryClientAsync(); - setRepoClient(newRepoClient); - } - } - - React.useEffect(() => { - const initializeComponentAsync: () => Promise = async () => { - SPComponentLoader.loadCss(LF_INDIGO_PINK_CSS_URL); - SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); - await SPComponentLoader.loadScript(ZONE_JS_URL); - await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); - try { - const loginCompleted: () => Promise = async () => { - await getAndInitializeRepositoryClientAndServicesAsync(); - setLoggedIn(true); - }; - const logoutCompleted: () => Promise = async () => { - setLoggedIn(false); - }; - - loginComponent.current.addEventListener( - 'loginCompleted', - loginCompleted - ); - loginComponent.current.addEventListener( - 'logoutCompleted', - logoutCompleted - ); - if (loginComponent.current.authorization_credentials) { - await getAndInitializeRepositoryClientAndServicesAsync(); - setLoggedIn(true); - } - } catch (err) { - console.error(`Error initializing configuration page: ${err}`); - } - }; - - void initializeComponentAsync(); - }, []); - - async function pageConfigurationCheck(): Promise { - try { - const res = await fetch( - `${getSPListURL(props.context, 'Site Pages')}/items`, - { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - } - ); - const sitePages = await res.json(); - for (let o = 0; o < sitePages.value.length; o++) { - const pageName = sitePages.value[o].Title; - if (pageName === LASERFICHE_SIGNIN_PAGE_NAME) { - return true; - } - } - } catch (error) { - console.warn(`Unable to determine if a SharePoint Page with name ${LASERFICHE_SIGNIN_PAGE_NAME} exists.`) - return false; - } - return false; - } - - async function clickLogin(): Promise { - const url = - props.context.pageContext.web.absoluteUrl + - '/SitePages/LaserficheSignIn.aspx?autologin'; - const hasSignIn = await pageConfigurationCheck(); - if (!hasSignIn) { - const mes = ( - { - setMessageErrorModal(undefined); - }} - /> - ); - setMessageErrorModal(mes); - return; - } - const loginWindow = window.open(url, 'loginWindow', 'popup'); - loginWindow.resizeTo(800, 600); - window.addEventListener('message', (event) => { - if (event.origin === window.origin) { - if (event.data === LOGIN_WINDOW_SUCCESS) { - loginWindow.close(); - } else if (event.data) { - const parsedError: AbortedLoginError = event.data; - if (parsedError.ErrorMessage && parsedError.ErrorType) { - loginWindow.close(); - const mes = ( - { - setMessageErrorModal(undefined); - }} - /> - ); - setMessageErrorModal(mes); - } - } - } - }); - } - - return ( - - - - {isAdmin() && ( - <> -
-
- - - - } - path='/HomePage' - /> - } path='/' /> - ( - - )} - path='/ManageConfigurationsPage' - /> - ( - - )} - path='/ManageMappingsPage' - /> - ( - - )} - path='/AddNewManageConfiguration' - /> - ( - - )} - path='/EditManageConfiguration/:name' - /> - - - - )} - {!isAdmin() && ( - - - {YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN} - - - )} - {messageErrorModal !== undefined && ( -
- {messageErrorModal} -
- )} -
-
-
- ); -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import { useState } from 'react'; +import { ILaserficheAdminConfigurationProps } from './ILaserficheAdminConfigurationProps'; +import { HashRouter, Route, Switch } from 'react-router-dom'; +import { Stack, StackItem } from 'office-ui-fabric-react'; +import AdminMainPage from '../components/AdminMainPage/AdminMainPage'; +import HomePage from './HomePage/HomePage'; +import ManageConfigurationsPage from './ManageConfigurationsPage/ManageConfigurationsPage'; +import ManageMappingsPage from './ManageMappingsPage/ManageMappingsPage'; +import EditManageConfiguration from './EditManageConfiguration/EditManageConfiguration'; +import AddNewManageConfiguration from './AddNewManageConfiguration/AddNewManageConfiguration'; +import { + clientId, + LASERFICHE_SIGNIN_PAGE_NAME, + LF_INDIGO_PINK_CSS_URL, + LF_MS_OFFICE_LITE_CSS_URL, + LF_UI_COMPONENTS_URL, + LOGIN_WINDOW_SUCCESS, + ZONE_JS_URL, +} from '../../constants'; +import { NgElement, WithProperties } from '@angular/elements'; +import { + AbortedLoginError, + LfLoginComponent, +} from '@laserfiche/types-lf-ui-components'; +import { RepositoryClientExInternal } from '../../../repository-client/repository-client'; +import { IRepositoryApiClientExInternal } from '../../../repository-client/repository-client-types'; +import { SPComponentLoader } from '@microsoft/sp-loader'; +import { getRegion, getSPListURL } from '../../../Utils/Funcs'; +import styles from './LaserficheAdminConfiguration.module.scss'; +import { SPPermission } from '@microsoft/sp-page-context'; +import { MessageDialog } from '../../../extensions/savetoLaserfiche/CommonDialogs'; + +const YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN = + 'You do not have the necessary rights to view or edit the Laserfiche SharePoint Integration configuration. Please contact your administrator for help.'; + +const needLaserficheSignInPage = `Missing "${LASERFICHE_SIGNIN_PAGE_NAME}" SharePoint page. Please refer to the Adding App to SharePoint Site topic in the administration guide for configuration steps.`; +export default function LaserficheAdminConfiguration( + props: ILaserficheAdminConfigurationProps +): JSX.Element { + const loginComponent: React.RefObject< + NgElement & WithProperties + > = React.createRef(); + const [loggedIn, setLoggedIn] = useState(false); + const [repoClient, setRepoClient] = useState< + IRepositoryApiClientExInternal | undefined + >(undefined); + const [messageErrorModal, setMessageErrorModal] = useState< + JSX.Element | undefined + >(undefined); + + const region = getRegion(); + + const redirectPage = window.location.origin + window.location.pathname; + + function isAdmin(): boolean { + const permission = new SPPermission( + props.context.pageContext.web.permissions.value + ); + const isFullControl = permission.hasPermission(SPPermission.manageWeb); + return isFullControl; + } + + async function getAndInitializeRepositoryClientAndServicesAsync(): Promise { + const accessToken = + loginComponent?.current?.authorization_credentials?.accessToken; + if (accessToken) { + await ensureRepoClientInitializedAsync(); + } else { + // user is not logged in + } + } + + async function ensureRepoClientInitializedAsync(): Promise { + if (!repoClient) { + const repoClientCreator = new RepositoryClientExInternal(); + const newRepoClient = + await repoClientCreator.createRepositoryClientAsync(); + setRepoClient(newRepoClient); + } + } + + React.useEffect(() => { + const initializeComponentAsync: () => Promise = async () => { + SPComponentLoader.loadCss(LF_INDIGO_PINK_CSS_URL); + SPComponentLoader.loadCss(LF_MS_OFFICE_LITE_CSS_URL); + await SPComponentLoader.loadScript(ZONE_JS_URL); + await SPComponentLoader.loadScript(LF_UI_COMPONENTS_URL); + try { + const loginCompleted: () => Promise = async () => { + await getAndInitializeRepositoryClientAndServicesAsync(); + setLoggedIn(true); + }; + const logoutCompleted: () => Promise = async () => { + setLoggedIn(false); + }; + + loginComponent.current.addEventListener( + 'loginCompleted', + loginCompleted + ); + loginComponent.current.addEventListener( + 'logoutCompleted', + logoutCompleted + ); + if (loginComponent.current.authorization_credentials) { + await getAndInitializeRepositoryClientAndServicesAsync(); + setLoggedIn(true); + } + } catch (err) { + console.error(`Error initializing configuration page: ${err}`); + } + }; + + void initializeComponentAsync(); + }, []); + + async function pageConfigurationCheck(): Promise { + try { + const res = await fetch( + `${getSPListURL(props.context, 'Site Pages')}/items`, + { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + } + ); + const sitePages = await res.json(); + for (let o = 0; o < sitePages.value.length; o++) { + const pageName = sitePages.value[o].Title; + if (pageName === LASERFICHE_SIGNIN_PAGE_NAME) { + return true; + } + } + } catch (error) { + console.warn(`Unable to determine if a SharePoint Page with name ${LASERFICHE_SIGNIN_PAGE_NAME} exists.`) + return false; + } + return false; + } + + async function clickLogin(): Promise { + const url = + props.context.pageContext.web.absoluteUrl + + '/SitePages/LaserficheSignIn.aspx?autologin'; + const hasSignIn = await pageConfigurationCheck(); + if (!hasSignIn) { + const mes = ( + { + setMessageErrorModal(undefined); + }} + /> + ); + setMessageErrorModal(mes); + return; + } + const loginWindow = window.open(url, 'loginWindow', 'popup'); + loginWindow.resizeTo(800, 600); + window.addEventListener('message', (event) => { + if (event.origin === window.origin) { + if (event.data === LOGIN_WINDOW_SUCCESS) { + loginWindow.close(); + } else if (event.data) { + const parsedError: AbortedLoginError = event.data; + if (parsedError.ErrorMessage && parsedError.ErrorType) { + loginWindow.close(); + const mes = ( + { + setMessageErrorModal(undefined); + }} + /> + ); + setMessageErrorModal(mes); + } + } + } + }); + } + + return ( + + + + {isAdmin() && ( + <> +
+
+ + + + } + path='/HomePage' + /> + } path='/' /> + ( + + )} + path='/ManageConfigurationsPage' + /> + ( + + )} + path='/ManageMappingsPage' + /> + ( + + )} + path='/AddNewManageConfiguration' + /> + ( + + )} + path='/EditManageConfiguration/:name' + /> + + + + )} + {!isAdmin() && ( + + + {YOU_DO_NOT_HAVE_RIGHTS_FOR_ADMIN_CONFIG_PLEASE_CONTACT_ADMIN} + + + )} + {messageErrorModal !== undefined && ( +
+ {messageErrorModal} +
+ )} +
+
+
+ ); +} diff --git a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationComponent.tsx b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationComponent.tsx index 2481931..beef9dd 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationComponent.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationComponent.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { ODataValueContextOfIListOfWTemplateInfo, ODataValueOfIListOfTemplateFieldInfo, diff --git a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationProps.tsx b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationProps.tsx index 4999989..a7c1936 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationProps.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationProps.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { WebPartContext } from "@microsoft/sp-webpart-base"; import { IRepositoryApiClientExInternal } from "../../../repository-client/repository-client-types"; import { ProfileConfiguration } from "./ProfileConfigurationComponents"; diff --git a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/IManageConfigurationPageProps.ts b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/IManageConfigurationPageProps.ts index 856c955..fa7fc24 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/IManageConfigurationPageProps.ts +++ b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/IManageConfigurationPageProps.ts @@ -1,5 +1,8 @@ -import { WebPartContext } from '@microsoft/sp-webpart-base'; - -export interface IManageConfigurationPageProps { - context: WebPartContext; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from '@microsoft/sp-webpart-base'; + +export interface IManageConfigurationPageProps { + context: WebPartContext; +} diff --git a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/ManageConfigurationsPage.tsx b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/ManageConfigurationsPage.tsx index f3fa812..97461db 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/ManageConfigurationsPage.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/ManageConfigurationsPage/ManageConfigurationsPage.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import * as React from 'react'; import { useEffect, useState } from 'react'; import { NavLink } from 'react-router-dom'; diff --git a/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/IManageMappingsPageProps.ts b/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/IManageMappingsPageProps.ts index 24ff1b8..c89c763 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/IManageMappingsPageProps.ts +++ b/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/IManageMappingsPageProps.ts @@ -1,8 +1,11 @@ -import { WebPartContext } from '@microsoft/sp-webpart-base'; -import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; - -export interface IManageMappingsPageProps { - context: WebPartContext; - repoClient: IRepositoryApiClientExInternal; - isLoggedIn: boolean; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from '@microsoft/sp-webpart-base'; +import { IRepositoryApiClientExInternal } from '../../../../repository-client/repository-client-types'; + +export interface IManageMappingsPageProps { + context: WebPartContext; + repoClient: IRepositoryApiClientExInternal; + isLoggedIn: boolean; +} diff --git a/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/ManageMappingsPage.tsx b/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/ManageMappingsPage.tsx index e6c1767..494734f 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/ManageMappingsPage.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/ManageMappingsPage/ManageMappingsPage.tsx @@ -1,721 +1,724 @@ -import * as React from 'react'; -import { SPHttpClient, ISPHttpClientOptions } from '@microsoft/sp-http'; -import { - DeleteModal, - ProfileConfiguration, -} from '../ProfileConfigurationComponents'; -import { ChangeEvent, useState } from 'react'; -import { IManageMappingsPageProps } from './IManageMappingsPageProps'; -import { IListItem } from '../IListItem'; -import { - LASERFICHE_ADMIN_CONFIGURATION_NAME, - MANAGE_CONFIGURATIONS, - MANAGE_MAPPING, -} from '../../../constants'; -import { getSPListURL } from '../../../../Utils/Funcs'; -import { ProfileMappingConfiguration } from '../../../../Utils/Types'; -import styles from './../LaserficheAdminConfiguration.module.scss'; -require('../../../../Assets/CSS/bootstrap.min.css'); -require('../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); - -interface SPContentType { - ID: string; - Name: string; - Description: string; -} - -const sharepointValidationMapping = - 'Please select a content type from the SharePoint Content Type drop down'; -const laserficheValidationMapping = - 'Please select a content type from the Laserfiche Profile dropdown'; -const validationOf = 'Already Mapping exists for this SharePoint content type'; - -export default function ManageMappingsPage( - props: IManageMappingsPageProps -): JSX.Element { - const [mappingRows, setMappingRows] = useState([]); - const [sharePointContentTypes, setSharePointContentTypes] = useState< - string[] - >([]); - const [laserficheContentTypes, setLaserficheContentTypes] = useState< - string[] - >([]); - const [deleteModal, setDeleteModal] = useState(undefined); - const [validationMessage, setValidationMessage] = useState(undefined); - - React.useEffect(() => { - void getAllMappingsAsync(); - }, [props.repoClient]); - - async function getAllMappingsAsync(): Promise { - try { - await getAllSharePointContentTypesAsync(); - await getAllLaserficheContentTypesAsync(); - const results: { id: string; mappings: ProfileMappingConfiguration[] } = - await getManageMappingsAsync(); - if (results?.mappings.length > 0) { - setMappingRows(mappingRows.concat(results.mappings)); - } - } catch (err) { - console.error(`Error getting mappings: ${err.message}`); - } - } - - async function getAllLaserficheContentTypesAsync(): Promise { - const array: string[] = []; - const results: { id: string; configs: ProfileConfiguration[] } = - await getManageConfigurationsAsync(); - if (results?.configs.length > 0) { - const configs = results.configs; - for (let i = 0; i < configs.length; i++) { - array.push(configs[i].ConfigurationName); - } - setLaserficheContentTypes(array); - } - } - - async function getManageConfigurationsAsync(): Promise<{ - id: string; - configs: ProfileConfiguration[]; - }> { - const array: IListItem[] = []; - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_CONFIGURATIONS}'`; - const res = await fetch(restApiUrl, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }); - const results = await res.json(); - if (results.value.length > 0) { - for (let i = 0; i < results.value.length; i++) { - array.push(results.value[i]); - } - return { id: array[0].Id, configs: JSON.parse(array[0].JsonValue) }; - } else { - return null; - } - } - - async function getAllSharePointContentTypesAsync(): Promise { - const restApiUrl = - props.context.pageContext.web.absoluteUrl + '/_api/web/contenttypes'; - const res = await fetch(restApiUrl, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }); - const results = await res.json(); - const array: string[] = results.value.map( - (contentType: SPContentType) => contentType.Name - ); - array.sort((a, b) => (a > b ? 1 : -1)); - setSharePointContentTypes(array); - } - - async function createNewMappingAsync( - idx: number, - rows: ProfileMappingConfiguration[] - ): Promise { - try { - setValidationMessage(undefined); - if (rows[idx].SharePointContentType === 'Select') { - setValidationMessage(sharepointValidationMapping); - } else if (rows[idx].LaserficheContentType === 'Select') { - setValidationMessage(laserficheValidationMapping); - } else { - const existingMappings: { - id: string; - mappings: ProfileMappingConfiguration[]; - } = await getManageMappingsAsync(); - if (existingMappings) { - if (existingMappings?.mappings.length > 0) { - const mappingExists = existingMappings.mappings.find( - (mapping) => mapping.id === rows[idx].id - ); - if (mappingExists !== undefined) { - await updateExistingMappingAsync( - existingMappings.mappings, - rows, - idx, - existingMappings.id - ); - } else { - await addNewInExistingMappingAsync( - existingMappings.mappings, - rows, - idx, - existingMappings.id - ); - } - } else { - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items(${existingMappings.id})`; - const row = [...mappingRows]; - const newjsonValue = [ - { - id: row[idx].id, - SharePointContentType: row[idx].SharePointContentType, - LaserficheContentType: row[idx].LaserficheContentType, - toggle: true, - }, - ]; - const jsonObject = JSON.stringify(newjsonValue); - const body: string = JSON.stringify({ - Title: MANAGE_MAPPING, - JsonValue: jsonObject, - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - 'IF-MATCH': '*', - 'X-HTTP-Method': 'MERGE', - }, - body: body, - }; - await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - rows[idx].toggle = !rows[idx].toggle; - setMappingRows(rows); - } - } else { - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items`; - const newRow = [...mappingRows]; - const jsonValues = [ - { - id: newRow[idx].id, - SharePointContentType: newRow[idx].SharePointContentType, - LaserficheContentType: newRow[idx].LaserficheContentType, - toggle: true, - }, - ]; - const jsonObject = JSON.stringify(jsonValues); - const body: string = JSON.stringify({ - Title: MANAGE_MAPPING, - JsonValue: jsonObject, - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - }, - body: body, - }; - await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - rows[idx].toggle = !rows[idx].toggle; - setMappingRows(rows); - } - } - } catch (err) { - setValidationMessage(`Error creating mapping: ${err.message}`); - } - } - - async function addNewInExistingMappingAsync( - jsonValue: ProfileMappingConfiguration[], - rows: ProfileMappingConfiguration[], - idx: number, - itemId: string - ): Promise { - let exitEntry = false; - for (let i = 0; i < jsonValue.length; i++) { - if ( - jsonValue[i].SharePointContentType === rows[idx].SharePointContentType - ) { - exitEntry = true; - break; - } - } - if (!exitEntry) { - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items(${itemId})`; - const newJsonValue = [ - ...jsonValue, - { - id: rows[idx].id, - SharePointContentType: rows[idx].SharePointContentType, - LaserficheContentType: rows[idx].LaserficheContentType, - toggle: true, - }, - ]; - const jsonObject = JSON.stringify(newJsonValue); - const body: string = JSON.stringify({ - Title: MANAGE_MAPPING, - JsonValue: jsonObject, - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - 'IF-MATCH': '*', - 'X-HTTP-Method': 'MERGE', - }, - body: body, - }; - await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - rows[idx].toggle = !rows[idx].toggle; - setMappingRows(rows); - if (jsonValue.length + 1 === rows.length) { - setValidationMessage(undefined); - } - } else { - setValidationMessage(validationOf); - } - } - - async function updateExistingMappingAsync( - jsonValue: ProfileMappingConfiguration[], - rows: ProfileMappingConfiguration[], - idx: number, - itemId: string - ): Promise { - const spContentTypeMatch = jsonValue.find( - (mapping) => - mapping.SharePointContentType === rows[idx].SharePointContentType - ); - if (!spContentTypeMatch || spContentTypeMatch.id === rows[idx].id) { - const matchingId = jsonValue.findIndex( - (mapping) => mapping.id === rows[idx].id - ); - jsonValue[matchingId] = { ...rows[idx] }; - rows[idx].toggle = !rows[idx].toggle; - jsonValue[matchingId].toggle = rows[idx].toggle; - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items(${itemId})`; - const newJsonValue = [...jsonValue]; - const jsonObject = JSON.stringify(newJsonValue); - const body: string = JSON.stringify({ - Title: MANAGE_MAPPING, - JsonValue: jsonObject, - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - 'IF-MATCH': '*', - 'X-HTTP-Method': 'MERGE', - }, - body: body, - }; - await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - setMappingRows(rows); - if ( - rows.some( - (item: ProfileMappingConfiguration) => - item.SharePointContentType === 'Select' - ) - ) { - setValidationMessage(sharepointValidationMapping); - } else if ( - rows.some( - (item: ProfileMappingConfiguration) => - item.LaserficheContentType === 'Select' - ) - ) { - setValidationMessage(laserficheValidationMapping); - } else { - setValidationMessage(undefined); - } - } else { - setValidationMessage(validationOf); - } - } - - async function deleteMappingAsync( - rows: ProfileMappingConfiguration[], - idx: number - ): Promise { - try { - const results: { id: string; mappings: ProfileMappingConfiguration[] } = - await getManageMappingsAsync(); - if (results) { - const itemId = results.id; - const mappings = results.mappings; - const matchingMappingIndex = mappings.findIndex( - (mapping) => mapping.id === rows[idx].id - ); - if (matchingMappingIndex > -1) { - mappings.splice(matchingMappingIndex, 1); - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/items(${itemId})`; - const newMappings = [...mappings]; - const jsonObject = JSON.stringify(newMappings); - const body: string = JSON.stringify({ - Title: MANAGE_MAPPING, - JsonValue: jsonObject, - }); - const options: ISPHttpClientOptions = { - headers: { - Accept: 'application/json;odata=nometadata', - 'content-type': 'application/json;odata=nometadata', - 'odata-version': '', - 'IF-MATCH': '*', - 'X-HTTP-Method': 'MERGE', - }, - body: body, - }; - await props.context.spHttpClient.post( - restApiUrl, - SPHttpClient.configurations.v1, - options - ); - const existingSPContentType = newMappings.find( - (mapping) => - mapping.SharePointContentType === rows[idx].SharePointContentType - ); - if (!existingSPContentType) { - setValidationMessage(undefined); - } else { - setValidationMessage(validationOf); - } - } else { - if (mappings.length + 1 === rows.length) { - setValidationMessage(undefined); - } else { - const selectSPContentType = mappings.find( - (mapping) => mapping.SharePointContentType === 'Select' - ); - if (selectSPContentType) { - setValidationMessage(sharepointValidationMapping); - } else { - const selectLfContentType = mappings.find( - (mapping) => mapping.LaserficheContentType === 'Select' - ); - if (selectLfContentType) { - setValidationMessage(laserficheValidationMapping); - } - } - } - } - } - } catch (err) { - setValidationMessage(`Error deleting mapping: ${err.message}`); - } - } - - async function getManageMappingsAsync(): Promise<{ - id: string; - mappings: ProfileMappingConfiguration[]; - }> { - const array: IListItem[] = []; - const restApiUrl = `${getSPListURL( - props.context, - LASERFICHE_ADMIN_CONFIGURATION_NAME - )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_MAPPING}'`; - const res = await fetch(restApiUrl, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }); - const results = await res.json(); - if (results.value.length > 0) { - for (let i = 0; i < results.value.length; i++) { - array.push(results.value[i]); - } - return { id: array[0].Id, mappings: JSON.parse(array[0].JsonValue) }; - } else { - return undefined; - } - } - - const addNewMapping: () => void = () => { - const id = (+new Date() + Math.floor(Math.random() * 999999)).toString(36); - const item = { - id, - SharePointContentType: 'Select', - LaserficheContentType: 'Select', - toggle: false, - }; - setMappingRows([...mappingRows, item]); - }; - - const removeSpecificMapping: (idx: number) => void = (idx: number) => { - const rows = [...mappingRows]; - const delModal = ( - removeRowAsync(idx)} - configurationName={rows[idx].SharePointContentType} - /> - ); - setDeleteModal(delModal); - }; - - async function removeRowAsync(id: number): Promise { - const rows = [...mappingRows]; - const deleteRows = [...mappingRows]; - rows.splice(id, 1); - setMappingRows(rows); - await deleteMappingAsync(deleteRows, id); - setDeleteModal(undefined); - } - - const editSpecificMapping: (idx: number) => void = (idx: number) => { - const rows = [...mappingRows]; - rows[idx].toggle = !rows[idx].toggle; - setMappingRows(rows); - }; - - const saveSpecificMappingAsync: (idx: number) => Promise = async ( - idx: number - ) => { - const rows = [...mappingRows]; - await createNewMappingAsync(idx, rows); - }; - - const handleChange: ( - event: ChangeEvent, - idx: number - ) => void = (event: ChangeEvent, idx: number) => { - const item = { - id: event.target.id, - name: event.target.name, - value: event.target.value, - }; - const newRows = [...mappingRows]; - if (item.name === 'SharePointContentType') { - newRows[idx].SharePointContentType = item.value; - } else if (item.name === 'LaserficheContentType') { - newRows[idx].LaserficheContentType = item.value; - } - setMappingRows(newRows); - }; - - function closeModalUp(): void { - setDeleteModal(undefined); - } - - const resetAsync: () => Promise = async () => { - try { - setDeleteModal(undefined); - await getAllSharePointContentTypesAsync(); - await getAllLaserficheContentTypesAsync(); - const results: { id: string; mappings: ProfileMappingConfiguration[] } = - await getManageMappingsAsync(); - if (results?.mappings.length > 0) { - setMappingRows(results.mappings); - } - setValidationMessage(undefined); - } catch (err) { - setValidationMessage(err.message); - } - }; - - const sharePointContentTypesDisplay = sharePointContentTypes.map( - (contentType) => ( - - ) - ); - const lfContentTypesDisplay = laserficheContentTypes.map((contentType) => ( - - )); - const renderTableData = mappingRows.map((item, index) => { - if (item.toggle) { - return ( - - - - - - - - -
- - -
- - - ); - } else { - return ( - - - - - - - - -
- - -
- - - ); - } - }); - const viewSharePointContentTypes = - props.context.pageContext.web.absoluteUrl + '/_layouts/15/mngctype.aspx'; - - return ( - <> -
-
- -
- - - - - - - - - {renderTableData} -
SharePoint Content TypeLaserfiche ProfileAction
-
- - {validationMessage && ( -
- {validationMessage} -
- )} -
- - -
-
-
- {deleteModal !== undefined && ( -
- {deleteModal} -
- )} - - ); -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import { SPHttpClient, ISPHttpClientOptions } from '@microsoft/sp-http'; +import { + DeleteModal, + ProfileConfiguration, +} from '../ProfileConfigurationComponents'; +import { ChangeEvent, useState } from 'react'; +import { IManageMappingsPageProps } from './IManageMappingsPageProps'; +import { IListItem } from '../IListItem'; +import { + LASERFICHE_ADMIN_CONFIGURATION_NAME, + MANAGE_CONFIGURATIONS, + MANAGE_MAPPING, +} from '../../../constants'; +import { getSPListURL } from '../../../../Utils/Funcs'; +import { ProfileMappingConfiguration } from '../../../../Utils/Types'; +import styles from './../LaserficheAdminConfiguration.module.scss'; +require('../../../../Assets/CSS/bootstrap.min.css'); +require('../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'); + +interface SPContentType { + ID: string; + Name: string; + Description: string; +} + +const sharepointValidationMapping = + 'Please select a content type from the SharePoint Content Type drop down'; +const laserficheValidationMapping = + 'Please select a content type from the Laserfiche Profile dropdown'; +const validationOf = 'Already Mapping exists for this SharePoint content type'; + +export default function ManageMappingsPage( + props: IManageMappingsPageProps +): JSX.Element { + const [mappingRows, setMappingRows] = useState([]); + const [sharePointContentTypes, setSharePointContentTypes] = useState< + string[] + >([]); + const [laserficheContentTypes, setLaserficheContentTypes] = useState< + string[] + >([]); + const [deleteModal, setDeleteModal] = useState(undefined); + const [validationMessage, setValidationMessage] = useState(undefined); + + React.useEffect(() => { + void getAllMappingsAsync(); + }, [props.repoClient]); + + async function getAllMappingsAsync(): Promise { + try { + await getAllSharePointContentTypesAsync(); + await getAllLaserficheContentTypesAsync(); + const results: { id: string; mappings: ProfileMappingConfiguration[] } = + await getManageMappingsAsync(); + if (results?.mappings.length > 0) { + setMappingRows(mappingRows.concat(results.mappings)); + } + } catch (err) { + console.error(`Error getting mappings: ${err.message}`); + } + } + + async function getAllLaserficheContentTypesAsync(): Promise { + const array: string[] = []; + const results: { id: string; configs: ProfileConfiguration[] } = + await getManageConfigurationsAsync(); + if (results?.configs.length > 0) { + const configs = results.configs; + for (let i = 0; i < configs.length; i++) { + array.push(configs[i].ConfigurationName); + } + setLaserficheContentTypes(array); + } + } + + async function getManageConfigurationsAsync(): Promise<{ + id: string; + configs: ProfileConfiguration[]; + }> { + const array: IListItem[] = []; + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_CONFIGURATIONS}'`; + const res = await fetch(restApiUrl, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const results = await res.json(); + if (results.value.length > 0) { + for (let i = 0; i < results.value.length; i++) { + array.push(results.value[i]); + } + return { id: array[0].Id, configs: JSON.parse(array[0].JsonValue) }; + } else { + return null; + } + } + + async function getAllSharePointContentTypesAsync(): Promise { + const restApiUrl = + props.context.pageContext.web.absoluteUrl + '/_api/web/contenttypes'; + const res = await fetch(restApiUrl, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const results = await res.json(); + const array: string[] = results.value.map( + (contentType: SPContentType) => contentType.Name + ); + array.sort((a, b) => (a > b ? 1 : -1)); + setSharePointContentTypes(array); + } + + async function createNewMappingAsync( + idx: number, + rows: ProfileMappingConfiguration[] + ): Promise { + try { + setValidationMessage(undefined); + if (rows[idx].SharePointContentType === 'Select') { + setValidationMessage(sharepointValidationMapping); + } else if (rows[idx].LaserficheContentType === 'Select') { + setValidationMessage(laserficheValidationMapping); + } else { + const existingMappings: { + id: string; + mappings: ProfileMappingConfiguration[]; + } = await getManageMappingsAsync(); + if (existingMappings) { + if (existingMappings?.mappings.length > 0) { + const mappingExists = existingMappings.mappings.find( + (mapping) => mapping.id === rows[idx].id + ); + if (mappingExists !== undefined) { + await updateExistingMappingAsync( + existingMappings.mappings, + rows, + idx, + existingMappings.id + ); + } else { + await addNewInExistingMappingAsync( + existingMappings.mappings, + rows, + idx, + existingMappings.id + ); + } + } else { + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items(${existingMappings.id})`; + const row = [...mappingRows]; + const newjsonValue = [ + { + id: row[idx].id, + SharePointContentType: row[idx].SharePointContentType, + LaserficheContentType: row[idx].LaserficheContentType, + toggle: true, + }, + ]; + const jsonObject = JSON.stringify(newjsonValue); + const body: string = JSON.stringify({ + Title: MANAGE_MAPPING, + JsonValue: jsonObject, + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + 'IF-MATCH': '*', + 'X-HTTP-Method': 'MERGE', + }, + body: body, + }; + await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + rows[idx].toggle = !rows[idx].toggle; + setMappingRows(rows); + } + } else { + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items`; + const newRow = [...mappingRows]; + const jsonValues = [ + { + id: newRow[idx].id, + SharePointContentType: newRow[idx].SharePointContentType, + LaserficheContentType: newRow[idx].LaserficheContentType, + toggle: true, + }, + ]; + const jsonObject = JSON.stringify(jsonValues); + const body: string = JSON.stringify({ + Title: MANAGE_MAPPING, + JsonValue: jsonObject, + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + }, + body: body, + }; + await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + rows[idx].toggle = !rows[idx].toggle; + setMappingRows(rows); + } + } + } catch (err) { + setValidationMessage(`Error creating mapping: ${err.message}`); + } + } + + async function addNewInExistingMappingAsync( + jsonValue: ProfileMappingConfiguration[], + rows: ProfileMappingConfiguration[], + idx: number, + itemId: string + ): Promise { + let exitEntry = false; + for (let i = 0; i < jsonValue.length; i++) { + if ( + jsonValue[i].SharePointContentType === rows[idx].SharePointContentType + ) { + exitEntry = true; + break; + } + } + if (!exitEntry) { + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items(${itemId})`; + const newJsonValue = [ + ...jsonValue, + { + id: rows[idx].id, + SharePointContentType: rows[idx].SharePointContentType, + LaserficheContentType: rows[idx].LaserficheContentType, + toggle: true, + }, + ]; + const jsonObject = JSON.stringify(newJsonValue); + const body: string = JSON.stringify({ + Title: MANAGE_MAPPING, + JsonValue: jsonObject, + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + 'IF-MATCH': '*', + 'X-HTTP-Method': 'MERGE', + }, + body: body, + }; + await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + rows[idx].toggle = !rows[idx].toggle; + setMappingRows(rows); + if (jsonValue.length + 1 === rows.length) { + setValidationMessage(undefined); + } + } else { + setValidationMessage(validationOf); + } + } + + async function updateExistingMappingAsync( + jsonValue: ProfileMappingConfiguration[], + rows: ProfileMappingConfiguration[], + idx: number, + itemId: string + ): Promise { + const spContentTypeMatch = jsonValue.find( + (mapping) => + mapping.SharePointContentType === rows[idx].SharePointContentType + ); + if (!spContentTypeMatch || spContentTypeMatch.id === rows[idx].id) { + const matchingId = jsonValue.findIndex( + (mapping) => mapping.id === rows[idx].id + ); + jsonValue[matchingId] = { ...rows[idx] }; + rows[idx].toggle = !rows[idx].toggle; + jsonValue[matchingId].toggle = rows[idx].toggle; + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items(${itemId})`; + const newJsonValue = [...jsonValue]; + const jsonObject = JSON.stringify(newJsonValue); + const body: string = JSON.stringify({ + Title: MANAGE_MAPPING, + JsonValue: jsonObject, + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + 'IF-MATCH': '*', + 'X-HTTP-Method': 'MERGE', + }, + body: body, + }; + await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + setMappingRows(rows); + if ( + rows.some( + (item: ProfileMappingConfiguration) => + item.SharePointContentType === 'Select' + ) + ) { + setValidationMessage(sharepointValidationMapping); + } else if ( + rows.some( + (item: ProfileMappingConfiguration) => + item.LaserficheContentType === 'Select' + ) + ) { + setValidationMessage(laserficheValidationMapping); + } else { + setValidationMessage(undefined); + } + } else { + setValidationMessage(validationOf); + } + } + + async function deleteMappingAsync( + rows: ProfileMappingConfiguration[], + idx: number + ): Promise { + try { + const results: { id: string; mappings: ProfileMappingConfiguration[] } = + await getManageMappingsAsync(); + if (results) { + const itemId = results.id; + const mappings = results.mappings; + const matchingMappingIndex = mappings.findIndex( + (mapping) => mapping.id === rows[idx].id + ); + if (matchingMappingIndex > -1) { + mappings.splice(matchingMappingIndex, 1); + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/items(${itemId})`; + const newMappings = [...mappings]; + const jsonObject = JSON.stringify(newMappings); + const body: string = JSON.stringify({ + Title: MANAGE_MAPPING, + JsonValue: jsonObject, + }); + const options: ISPHttpClientOptions = { + headers: { + Accept: 'application/json;odata=nometadata', + 'content-type': 'application/json;odata=nometadata', + 'odata-version': '', + 'IF-MATCH': '*', + 'X-HTTP-Method': 'MERGE', + }, + body: body, + }; + await props.context.spHttpClient.post( + restApiUrl, + SPHttpClient.configurations.v1, + options + ); + const existingSPContentType = newMappings.find( + (mapping) => + mapping.SharePointContentType === rows[idx].SharePointContentType + ); + if (!existingSPContentType) { + setValidationMessage(undefined); + } else { + setValidationMessage(validationOf); + } + } else { + if (mappings.length + 1 === rows.length) { + setValidationMessage(undefined); + } else { + const selectSPContentType = mappings.find( + (mapping) => mapping.SharePointContentType === 'Select' + ); + if (selectSPContentType) { + setValidationMessage(sharepointValidationMapping); + } else { + const selectLfContentType = mappings.find( + (mapping) => mapping.LaserficheContentType === 'Select' + ); + if (selectLfContentType) { + setValidationMessage(laserficheValidationMapping); + } + } + } + } + } + } catch (err) { + setValidationMessage(`Error deleting mapping: ${err.message}`); + } + } + + async function getManageMappingsAsync(): Promise<{ + id: string; + mappings: ProfileMappingConfiguration[]; + }> { + const array: IListItem[] = []; + const restApiUrl = `${getSPListURL( + props.context, + LASERFICHE_ADMIN_CONFIGURATION_NAME + )}/Items?$select=Id,Title,JsonValue&$filter=Title eq '${MANAGE_MAPPING}'`; + const res = await fetch(restApiUrl, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const results = await res.json(); + if (results.value.length > 0) { + for (let i = 0; i < results.value.length; i++) { + array.push(results.value[i]); + } + return { id: array[0].Id, mappings: JSON.parse(array[0].JsonValue) }; + } else { + return undefined; + } + } + + const addNewMapping: () => void = () => { + const id = (+new Date() + Math.floor(Math.random() * 999999)).toString(36); + const item = { + id, + SharePointContentType: 'Select', + LaserficheContentType: 'Select', + toggle: false, + }; + setMappingRows([...mappingRows, item]); + }; + + const removeSpecificMapping: (idx: number) => void = (idx: number) => { + const rows = [...mappingRows]; + const delModal = ( + removeRowAsync(idx)} + configurationName={rows[idx].SharePointContentType} + /> + ); + setDeleteModal(delModal); + }; + + async function removeRowAsync(id: number): Promise { + const rows = [...mappingRows]; + const deleteRows = [...mappingRows]; + rows.splice(id, 1); + setMappingRows(rows); + await deleteMappingAsync(deleteRows, id); + setDeleteModal(undefined); + } + + const editSpecificMapping: (idx: number) => void = (idx: number) => { + const rows = [...mappingRows]; + rows[idx].toggle = !rows[idx].toggle; + setMappingRows(rows); + }; + + const saveSpecificMappingAsync: (idx: number) => Promise = async ( + idx: number + ) => { + const rows = [...mappingRows]; + await createNewMappingAsync(idx, rows); + }; + + const handleChange: ( + event: ChangeEvent, + idx: number + ) => void = (event: ChangeEvent, idx: number) => { + const item = { + id: event.target.id, + name: event.target.name, + value: event.target.value, + }; + const newRows = [...mappingRows]; + if (item.name === 'SharePointContentType') { + newRows[idx].SharePointContentType = item.value; + } else if (item.name === 'LaserficheContentType') { + newRows[idx].LaserficheContentType = item.value; + } + setMappingRows(newRows); + }; + + function closeModalUp(): void { + setDeleteModal(undefined); + } + + const resetAsync: () => Promise = async () => { + try { + setDeleteModal(undefined); + await getAllSharePointContentTypesAsync(); + await getAllLaserficheContentTypesAsync(); + const results: { id: string; mappings: ProfileMappingConfiguration[] } = + await getManageMappingsAsync(); + if (results?.mappings.length > 0) { + setMappingRows(results.mappings); + } + setValidationMessage(undefined); + } catch (err) { + setValidationMessage(err.message); + } + }; + + const sharePointContentTypesDisplay = sharePointContentTypes.map( + (contentType) => ( + + ) + ); + const lfContentTypesDisplay = laserficheContentTypes.map((contentType) => ( + + )); + const renderTableData = mappingRows.map((item, index) => { + if (item.toggle) { + return ( + + + + + + + + +
+ + +
+ + + ); + } else { + return ( + + + + + + + + +
+ + +
+ + + ); + } + }); + const viewSharePointContentTypes = + props.context.pageContext.web.absoluteUrl + '/_layouts/15/mngctype.aspx'; + + return ( + <> +
+
+ +
+ + + + + + + + + {renderTableData} +
SharePoint Content TypeLaserfiche ProfileAction
+
+ + {validationMessage && ( +
+ {validationMessage} +
+ )} +
+ + +
+
+
+ {deleteModal !== undefined && ( +
+ {deleteModal} +
+ )} + + ); +} diff --git a/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx b/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx index 1e0c873..e7edcc6 100644 --- a/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx +++ b/src/webparts/laserficheAdminConfiguration/components/ProfileConfigurationComponents.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import { NgElement, WithProperties } from '@angular/elements'; import { EntryType, diff --git a/src/webparts/laserficheAdminConfiguration/loc/en-us.js b/src/webparts/laserficheAdminConfiguration/loc/en-us.js index 0ef63ef..b3bdf4d 100644 --- a/src/webparts/laserficheAdminConfiguration/loc/en-us.js +++ b/src/webparts/laserficheAdminConfiguration/loc/en-us.js @@ -1,6 +1,9 @@ -define([], function() { - return { - "PropertyPaneDescription": "", - "BasicGroupName": "Laserfiche Admin WebPart Properties", - } -}); \ No newline at end of file +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +define([], function() { + return { + "PropertyPaneDescription": "", + "BasicGroupName": "Laserfiche Admin WebPart Properties", + } +}); diff --git a/src/webparts/laserficheAdminConfiguration/loc/mystrings.d.ts b/src/webparts/laserficheAdminConfiguration/loc/mystrings.d.ts index 843b15a..85c8fb1 100644 --- a/src/webparts/laserficheAdminConfiguration/loc/mystrings.d.ts +++ b/src/webparts/laserficheAdminConfiguration/loc/mystrings.d.ts @@ -1,9 +1,12 @@ -declare interface ILaserficheAdminConfigurationWebPartStrings { - PropertyPaneDescription: string; - BasicGroupName: string; -} - -declare module 'LaserficheAdminConfigurationWebPartStrings' { - const strings: ILaserficheAdminConfigurationWebPartStrings; - export = strings; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +declare interface ILaserficheAdminConfigurationWebPartStrings { + PropertyPaneDescription: string; + BasicGroupName: string; +} + +declare module 'LaserficheAdminConfigurationWebPartStrings' { + const strings: ILaserficheAdminConfigurationWebPartStrings; + export = strings; +} diff --git a/src/webparts/sendToLaserficheLoginComponent/SendToLaserficheLoginComponentWebPart.ts b/src/webparts/sendToLaserficheLoginComponent/SendToLaserficheLoginComponentWebPart.ts index 2a9af29..74dc647 100644 --- a/src/webparts/sendToLaserficheLoginComponent/SendToLaserficheLoginComponentWebPart.ts +++ b/src/webparts/sendToLaserficheLoginComponent/SendToLaserficheLoginComponentWebPart.ts @@ -1,29 +1,32 @@ -import * as React from 'react'; -import * as ReactDom from 'react-dom'; -import { Version } from '@microsoft/sp-core-library'; -import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; - -import SendToLaserficheLoginComponent from './components/SendToLaserficheLoginComponent'; - - -export default class SendToLaserficheLoginComponentWebPart extends BaseClientSideWebPart<{}> { - public render(): void { - const element: React.ReactElement = React.createElement( - SendToLaserficheLoginComponent, - { - context: this.context, - } - ); - - ReactDom.render(element, this.domElement); - } - - protected onDispose(): void { - ReactDom.unmountComponentAtNode(this.domElement); - } - - protected get dataVersion(): Version { - return Version.parse('1.0'); - } - -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import * as React from 'react'; +import * as ReactDom from 'react-dom'; +import { Version } from '@microsoft/sp-core-library'; +import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base'; + +import SendToLaserficheLoginComponent from './components/SendToLaserficheLoginComponent'; + + +export default class SendToLaserficheLoginComponentWebPart extends BaseClientSideWebPart<{}> { + public render(): void { + const element: React.ReactElement = React.createElement( + SendToLaserficheLoginComponent, + { + context: this.context, + } + ); + + ReactDom.render(element, this.domElement); + } + + protected onDispose(): void { + ReactDom.unmountComponentAtNode(this.domElement); + } + + protected get dataVersion(): Version { + return Version.parse('1.0'); + } + +} diff --git a/src/webparts/sendToLaserficheLoginComponent/components/ISendToLaserficheLoginComponentProps.ts b/src/webparts/sendToLaserficheLoginComponent/components/ISendToLaserficheLoginComponentProps.ts index f458e60..733680f 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/ISendToLaserficheLoginComponentProps.ts +++ b/src/webparts/sendToLaserficheLoginComponent/components/ISendToLaserficheLoginComponentProps.ts @@ -1,5 +1,8 @@ -import { WebPartContext } from "@microsoft/sp-webpart-base"; - -export interface ISendToLaserficheLoginComponentProps { - context: WebPartContext; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +import { WebPartContext } from "@microsoft/sp-webpart-base"; + +export interface ISendToLaserficheLoginComponentProps { + context: WebPartContext; +} diff --git a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx index c77502c..afa0c76 100644 --- a/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx +++ b/src/webparts/sendToLaserficheLoginComponent/components/SendToLaserficheLoginComponent.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + import * as React from 'react'; import { SPComponentLoader } from '@microsoft/sp-loader'; import { Navigation } from 'spfx-navigation'; diff --git a/src/webparts/sendToLaserficheLoginComponent/loc/en-us.js b/src/webparts/sendToLaserficheLoginComponent/loc/en-us.js index 8861946..0d2bcff 100644 --- a/src/webparts/sendToLaserficheLoginComponent/loc/en-us.js +++ b/src/webparts/sendToLaserficheLoginComponent/loc/en-us.js @@ -1,6 +1,9 @@ -define([], function() { - return { - "PropertyPaneDescription": "", - "BasicGroupName": "Save To Laserfiche Login Component", - } -}); \ No newline at end of file +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +define([], function() { + return { + "PropertyPaneDescription": "", + "BasicGroupName": "Save To Laserfiche Login Component", + } +}); diff --git a/src/webparts/sendToLaserficheLoginComponent/loc/mystrings.d.ts b/src/webparts/sendToLaserficheLoginComponent/loc/mystrings.d.ts index 3ac6deb..a67e424 100644 --- a/src/webparts/sendToLaserficheLoginComponent/loc/mystrings.d.ts +++ b/src/webparts/sendToLaserficheLoginComponent/loc/mystrings.d.ts @@ -1,9 +1,12 @@ -declare interface ISendToLaserficheLoginComponentWebPartStrings { - PropertyPaneDescription: string; - BasicGroupName: string; -} - -declare module 'SendToLaserficheLoginComponentWebPartStrings' { - const strings: ISendToLaserficheLoginComponentWebPartStrings; - export = strings; -} +// Copyright (c) Laserfiche. +// Licensed under the MIT License. See LICENSE.md in the project root for license information. + +declare interface ISendToLaserficheLoginComponentWebPartStrings { + PropertyPaneDescription: string; + BasicGroupName: string; +} + +declare module 'SendToLaserficheLoginComponentWebPartStrings' { + const strings: ISendToLaserficheLoginComponentWebPartStrings; + export = strings; +} diff --git a/testing/test_plan.md b/testing/test_plan.md index b743843..d1f5d79 100644 --- a/testing/test_plan.md +++ b/testing/test_plan.md @@ -1,405 +1,408 @@ -# Test Plan for Laserfiche SharePoint Online Integration - -## Objective - -Verify that changes made to the Laserfiche SharePoint Online Integration do not disrupt -existing functionality in the product. This plan should be executed prior to each new -release, and no changes should be included in the release until they have been tested. As -new functionality is added to the integration, new tests should be added to the plan -to ensure adequate coverage. - -## Test Cases - -- [Installation](#installation) -- [Site Configuration](#site-configuration) -- [Admin Access Rights](#admin-access-rights) -- [Profiles](#profiles) -- [Save to Laserfiche and Profile Mapping](#save-to-laserfiche-and-profile-mapping-tab) -- [Repository Explorer](#repository-explorer) - -### **Installation** - -#### **Use Documentation to Add the Integration to your Tenant App Catalog** - -Steps: - -1. Follow the instructions in the [Adding App to Organization Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/adding-app-organization.html) - -Expected Results: - -- Instructions in documentation are clear and effective -- `Laserfiche SharePoint Online Integration` is available in your tenant app catalog - -#### **Use Documentation to Add the Integration to your SharePoint Site** - -Steps: - -1. Follow steps 1-5 in the [Adding App to SharePoint Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/adding-app-to-sp-site.html) - -Expected Results: - -- Instructions in documentation are clear and effective -- `Laserfiche SharePoint Online Integration` is available in your SharePoint Site site contents - -### Site Configuration - -Prerequisites: - -- Follow the [Installation](#installation) steps successfully - -#### Use Documentation to set up Laserfiche Sign In Page - -Steps: - -1. Follow the instructions for Laserfiche Sign in page in the [Add Add to SP Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/add-app-to-sp-site) - -Expected Results: - -- Instructions in documentation are clear and effective -- You have a page in your site called LaserficheSignIn that contains the Laserfiche Sign In Web Part - -#### Use Documentation to set up Laserfiche Repository Explorer - -Steps: - - -1. Follow the instructions for the Repository Explorer page in the [Add Add to SP Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/add-app-to-sp-site) - -Expected Results: - -- Instructions in documentation are clear and effective -- You have a page in your site that contains the Laserfiche Repository Explorer Web Part - -#### Use Documentation to set up Laserfiche Admin Configuration - -Steps: - -1. Follow the instructions for Admin Configuration page in the [Add Add to SP Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/add-app-to-sp-site) - -Expected Results: - -- Instructions in documentation are clear and effective -- You have a page in your site that contains the Laserfiche Administrator Configuration Web Part - -#### Use Documentation to register app in dev console - -Steps: - -1. Follow the instructions for registering application in the [Register App in Laserfiche Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/register-app-in-laserfiche.html) - -Expected Results: - -- Verify manifest is valid (i.e. SPA, correct clientId, etc.) -- App is registered successfully in Laserfiche dev console -- You can sign in on all three pages you created above - -### Admin Access Rights - -Prerequisites: - -- Follow the [Installation](#installation) and [Site Configuration](#site-configuration) steps successfully -- You must NOT BE a site owner of the site containing that page. - -#### Test Restricted Access to Web Part - -Steps: -1. Attempt to open the admin configuration web part on the protected page. - - Expected Results: You should not be able to do any configuring, and there should be an error message explaining that you don't have the necessary rights. - - -### Profiles -Prerequisites: - -- Follow the [Installation](#installation) and [Site Configuration](#site-configuration) steps successfully -- You must BE a site owner of the site containing that page. -#### Create standard profile -Steps: -1. Go to the Profiles tab and click the `Add Profile` button. -1. Name the Profile `Example Profile Name`, do not select a template, select a folder you have access to save into, and choose `Leave a copy of the file in SharePoint` for the `After import` behavior. Click the Save button. - - Expected Results: You should see a success dialog, and then get returned to the `Profiles Tab`, where the new profile should be visible. - - -#### Test Profile Error Handling -Steps: -1. Go to the Profiles tab and click the `Add Profile` button. -1. Name the Profile `Bad Profile`, select a folder of your choice as the destination folder, and select a template containing a Date field. In the Mapping section, Click `Add Field`, and choose `Actual Work` for the SharePoint Column and the Date field for the Laserfiche Field. - - Expected Results: - - Warning/error that the data types don't match. - - Profile is not saved. -1. Delete the SP Column/LF field pair. - - Expected Results: - - Profile can be saved (button not disabled) -1. Save the Profile -1. Add a New Profile, and name it `Bad Profile` as well. Attempt to Save. - - Expected Results: - - The Profile should not be added. - - The page should not indicate that the profile was added - - The page should explain that the profile was not added because a profile with that name already exists. -1. Delete the profile named `Bad Profile`. -#### Test Edit Profile - -Steps: -1. Click the pencil button to edit a profile and add some compatible metadata mappings like a text type for the SharePoint Column and a String type for the Laserfiche Field, for example. Click Save. - - Expected Results: - - The page should indicate that the profile was saved. - - If you click edit again, you should see the changes that you originally made - -#### Test 'after import' configuration - -Steps: -1. Create a Profile named `Duplicate in Laserfiche` that saves to a folder of your choice and leaves a copy of the file in SharePoint after import. -1. Create a Profile named `Replace with Link` that saves to the same folder and Replaces SharePoint file with a link after import. -1. Create a Profile named `Delete From SharePoint` that saves to the same folder and Deletes SharePoint file after import. - -Expected Results: - - Those three profiles exist - -#### Test metadata configuration -Steps: -1. Create a Profile named `number metadata` that saves to a folder of your choice and leaves a copy of the file in SharePoint after import. Assign a template that has a required short integer field in Laserfiche, and map the SharePoint Column `Actual Work` to the required short integer field. -1. Save the Profile. - -Expected Results: -- Profile appears. - - -### Save to Laserfiche and Profile Mapping Tab - -Prerequisites: - -- Follow the [Profiles](#profiles) Tests successfully -- Laserfiche Sign In Page must already exist -- Laserfiche Admin Configuration Page must already exist -#### Test Default Profile with No Content Type -Steps: -1. Inside the SharePoint site's `Documents` tab, remove the column displaying `Content Type`. -1. In the Profile Mapping Tab, associate the `[Default]` SharePoint Content Type with the `Example Profile Name` Laserfiche Profile. Remember to save the mapping. Make sure no other mappings exist. -1. Attempt to save a file to Laserfiche inside the Documents tab. - -Expected Results -- The file is saved according to the Default Profile - -#### Test with No Default Profile and with No Content Type -Steps: -1. Inside the SharePoint site's `Documents` tab, remove the column displaying `Content Type` if it exists. -1. In the Profile Mapping Tab, associate the `[Default]` SharePoint Content Type with the `Example Profile Name` Laserfiche Profile. Remember to save the mapping. Make sure no other mappings exist. -1. Attempt to save a file to Laserfiche inside the Documents tab. - -Expected Results -- The file is not saved -- An error message explains that the file is not saved because there is no default mapping -#### Test Default Profile -Steps: -1. Add `Content Type` as a column in the Documents tab if it doesn't already exist. -1. In the Profile Mapping Tab, associate the `[Default]` SharePoint Content Type with the `Example Profile Name` Laserfiche Profile. Remember to Save the mapping. -1. Eliminate all other mappings -1. Save a document from the Documents Tab of the SharePoint site to Laserfiche - -Expected Results: - - The file should save in the destination folder you configured in the Default Profile. - -#### Test Saving already saved document -Prerequisites: - - execute the `Test Default Profile` test -Steps: - - Save the same document to Laserfiche as in the Test Default Profile Test -Expected Results: You should get a warning that an entry with the same name already exists, and that Laserfiche will rename the new documents. If you continue, and open the file in Laserfiche, the document should be renamed. -#### Test No Default Profile Save -Steps: -1. Remove all SharePoint Content Type -> Laserfiche Profile Mappings -1. Attempt to save a Document from the documents tab - -Expected Result: - - Document does not save - - Error that requests a default mapping or a mapping for the relevant content type - -#### Test Save when a required field doesn't exist -Steps: -1. Add SharePoint Column `Actual Work` to SharePoint Library -1. Make sure that `Actual Work` has no value for a specific document -1. Set the Default mapping to `number metadata`, and save. There should be no other mappings -1. Attempt to save the specific document to Laserfiche - -Expected Results: - - The document does not save - - Error message that says that Actual Work doesn't have a value. -#### Test metadata constraint failed case -Steps: -1. Add SharePoint Column "Actual Work" to SharePoint Library -1. Add value for "Actual Work" for a specific document to be a number of 65,000. -1. Set the Default mapping to `number metadata`, and save. -1. Attempt to save the specific document to Laserfiche - -Expected Results: - - The document should save, BUT - - There should be a warning that says the metadata didn't save. - -#### Test specific mapping overrides default -Steps: -1. Remove all Profile Mappings -1. Add a mapping from `[Default]` to `Example Profile Name` -1. Add a mapping from `Document` to `number metadata` -1. Choose a Document in SharePoint -1. Update the `Actual Work` column of the document to have a value of 5 -1. Attempt to save the document to Laserfiche - -Expected Results: - - The document should successfully save - - The document's number field should have a value of 5 in Laserfiche Web Client. -#### Test replace with URL action -Steps: -1. Edit the mapping from `Document` so that it points to `Replace with Link` -1. Attempt to save a Document to Laserfiche - -Expected Results: - - The document should successfully appear in Laserfiche - - In SharePoint, the document should be replaced with a link - - Link should actually link to the document in LF - -#### Test delete after save to Laserfiche -Steps: -1. Edit the mapping from `Document` so that it points to `Delete From SharePoint` -1. Attempt to save a Document to Laserfiche - -Expected Results: - - The document should exist in Laserfiche and no longer exist in SharePoint - -#### Test saving .url files to Laserfiche -Steps: -1. Attempt to save a .url file to Laserfiche - -Expected Result: - - You should be told that you can't save a .url file to Laserfiche. - -#### Test Mapping Content Types to multiple Profiles -Steps: -1. In addition to the existing `[Default]` -> `Example Profile Name` mapping, add a mapping from `[Default]` to `Replace with Link`. -1. Click Save - -Expected Results - - The new mapping should not save - - You should see an error message saying a mapping already exists for that content type - -### Repository Explorer - -Prerequisites: - -- Follow the [Installation](#installation) and [Site Configuration](#site-configuration) steps successfully - -#### Test login - -Steps: - -1. Click `Sign in` button - - Expected results: You are led through the OAuth flow via a popup window, you return to repository explorer page, and button says `Sign Out`. - -#### Test Open button - -Steps: - -1. Open repository explorer to the root folder -1. Without selecting an entry, click the Open button. - - Expected result: Open root folder in Laserfiche in a new tab -1. Return to repository explorer and select (single-click) a folder inside -1. Click open button - - Expected result: Open the selected folder in Laserfiche in a new tab -1. Return to repository explorer and select (single-click) a document inside -1. Click the open button - - Expected result: Open the selected document in Laserfiche in a new tab - -#### Test import file button - -Steps: - -1. Navigate to a folder that you have access to create documents in -1. Have no folder/document selected -1. Click the import file button -1. Click import without uploading file - - Expected behavior: Error message stating please select a file to upload -1. Upload test file using browse button -1. Add no metadata -1. Click ok - - Expected behavior: Dialog closes -1. Use refresh button to refresh open folder - - Expected behavior: File exists in currently opened folder -1. Back in repository explorer, single-click a folder -1. Click the import file button -1. Upload test file using browse button -1. Add no metadata -1. Click ok - - Expected behavior: Dialog closes -1. Use refresh button to refresh open folder - - Expected behavior: File exists in currently opened folder (not the one selected) -1. Back in the repository explorer, single-click a file -1. Click the import file button -1. Upload test file using browse button -1. Add no metadata -1. Click ok - - Expected behavior: Dialog closes -1. Use refresh button to refresh open folder - - Expected behavior: File exists in currently opened folder (does not replace file) -1. Back in repository explorer, click the import file button -1. Upload test file using browse button -1. Add template -1. Make an error in the metadata (e.g., required field empty) -1. Attempt to upload file - - Expected behavior: File not uploaded, metadata component shows relevant errors if not already shown -1. Add valid metadata -1. Click ok - - Expected behavior: Dialog closes -1. Use refresh button to refresh open folder - - Expected behavior: File exists in currently opened folder -1. Double-click recently imported file - - Expected behavior: Metadata specified was successfully set -1. Back in repository explorer, click the import file button -1. Upload test file using browse button -1. Rename file to be same as existing document -1. Click ok - - Expected behavior: Dialog closes -1. Use refresh button to refresh open folder - - Expected behavior: File was uploaded, but has been automatically renamed - -#### Test Create folder button - -Test delete after save action - -1. Navigate to a folder where you have permissions to create entries -1. Use create folder button -1. Create folder with valid name - - Expected Results: Dialog closes -1. Use refresh button - - Expected results: New folder exists in currently open folder -1. Use create folder button -1. Attempt to create with no name - - Expected results: Dialog remains open, error specifies to provide a folder name -1. Close dialog -1. Use create folder button -1. Use name with the invalid character `\`. -1. Attempt to create folder - - Expected results: Dialog remains open, error specifies to provide a valid folder name -1. Use create folder button. -1. Use name with alphanumeric and with some of the valid special characters `!@#$%^&*()`. -1. Attempt to create folder. -1. Use refresh button - - Expected results: New folder exists in currently open folder with special characters in the name. -1. Use create folder button -1. Use name that already exists in folder -1. Attempt to create - - Expected Results: Dialog remains open, receive error that object already exists -1. Select (single-click) a folder in the repository explorer -1. Use create folder button -1. Create folder with valid, unique name - - Expected Results: Dialog closes -1. Use refresh button - - Expected results: New folder exists in currently open folder - -#### Test refresh button - -Steps: - -1. Open specific folder in repository explorer -1. Open same folder in Web Client in a new tab -1. Create folder in Web Client in that folder -1. Return to repository explorer tab -1. Click refresh button - - Expected behavior: Folder that was created in Web Client will now exist in the repository explorer + + +# Test Plan for Laserfiche SharePoint Online Integration + +## Objective + +Verify that changes made to the Laserfiche SharePoint Online Integration do not disrupt +existing functionality in the product. This plan should be executed prior to each new +release, and no changes should be included in the release until they have been tested. As +new functionality is added to the integration, new tests should be added to the plan +to ensure adequate coverage. + +## Test Cases + +- [Installation](#installation) +- [Site Configuration](#site-configuration) +- [Admin Access Rights](#admin-access-rights) +- [Profiles](#profiles) +- [Save to Laserfiche and Profile Mapping](#save-to-laserfiche-and-profile-mapping-tab) +- [Repository Explorer](#repository-explorer) + +### **Installation** + +#### **Use Documentation to Add the Integration to your Tenant App Catalog** + +Steps: + +1. Follow the instructions in the [Adding App to Organization Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/adding-app-organization.html) + +Expected Results: + +- Instructions in documentation are clear and effective +- `Laserfiche SharePoint Online Integration` is available in your tenant app catalog + +#### **Use Documentation to Add the Integration to your SharePoint Site** + +Steps: + +1. Follow steps 1-5 in the [Adding App to SharePoint Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/adding-app-to-sp-site.html) + +Expected Results: + +- Instructions in documentation are clear and effective +- `Laserfiche SharePoint Online Integration` is available in your SharePoint Site site contents + +### Site Configuration + +Prerequisites: + +- Follow the [Installation](#installation) steps successfully + +#### Use Documentation to set up Laserfiche Sign In Page + +Steps: + +1. Follow the instructions for Laserfiche Sign in page in the [Add Add to SP Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/add-app-to-sp-site) + +Expected Results: + +- Instructions in documentation are clear and effective +- You have a page in your site called LaserficheSignIn that contains the Laserfiche Sign In Web Part + +#### Use Documentation to set up Laserfiche Repository Explorer + +Steps: + + +1. Follow the instructions for the Repository Explorer page in the [Add Add to SP Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/add-app-to-sp-site) + +Expected Results: + +- Instructions in documentation are clear and effective +- You have a page in your site that contains the Laserfiche Repository Explorer Web Part + +#### Use Documentation to set up Laserfiche Admin Configuration + +Steps: + +1. Follow the instructions for Admin Configuration page in the [Add Add to SP Site Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/add-app-to-sp-site) + +Expected Results: + +- Instructions in documentation are clear and effective +- You have a page in your site that contains the Laserfiche Administrator Configuration Web Part + +#### Use Documentation to register app in dev console + +Steps: + +1. Follow the instructions for registering application in the [Register App in Laserfiche Documentation](https://laserfiche.github.io/laserfiche-sharepoint-integration/docs/admin-documentation/register-app-in-laserfiche.html) + +Expected Results: + +- Verify manifest is valid (i.e. SPA, correct clientId, etc.) +- App is registered successfully in Laserfiche dev console +- You can sign in on all three pages you created above + +### Admin Access Rights + +Prerequisites: + +- Follow the [Installation](#installation) and [Site Configuration](#site-configuration) steps successfully +- You must NOT BE a site owner of the site containing that page. + +#### Test Restricted Access to Web Part + +Steps: +1. Attempt to open the admin configuration web part on the protected page. + - Expected Results: You should not be able to do any configuring, and there should be an error message explaining that you don't have the necessary rights. + + +### Profiles +Prerequisites: + +- Follow the [Installation](#installation) and [Site Configuration](#site-configuration) steps successfully +- You must BE a site owner of the site containing that page. +#### Create standard profile +Steps: +1. Go to the Profiles tab and click the `Add Profile` button. +1. Name the Profile `Example Profile Name`, do not select a template, select a folder you have access to save into, and choose `Leave a copy of the file in SharePoint` for the `After import` behavior. Click the Save button. + - Expected Results: You should see a success dialog, and then get returned to the `Profiles Tab`, where the new profile should be visible. + + +#### Test Profile Error Handling +Steps: +1. Go to the Profiles tab and click the `Add Profile` button. +1. Name the Profile `Bad Profile`, select a folder of your choice as the destination folder, and select a template containing a Date field. In the Mapping section, Click `Add Field`, and choose `Actual Work` for the SharePoint Column and the Date field for the Laserfiche Field. + - Expected Results: + - Warning/error that the data types don't match. + - Profile is not saved. +1. Delete the SP Column/LF field pair. + - Expected Results: + - Profile can be saved (button not disabled) +1. Save the Profile +1. Add a New Profile, and name it `Bad Profile` as well. Attempt to Save. + - Expected Results: + - The Profile should not be added. + - The page should not indicate that the profile was added + - The page should explain that the profile was not added because a profile with that name already exists. +1. Delete the profile named `Bad Profile`. +#### Test Edit Profile + +Steps: +1. Click the pencil button to edit a profile and add some compatible metadata mappings like a text type for the SharePoint Column and a String type for the Laserfiche Field, for example. Click Save. + - Expected Results: + - The page should indicate that the profile was saved. + - If you click edit again, you should see the changes that you originally made + +#### Test 'after import' configuration + +Steps: +1. Create a Profile named `Duplicate in Laserfiche` that saves to a folder of your choice and leaves a copy of the file in SharePoint after import. +1. Create a Profile named `Replace with Link` that saves to the same folder and Replaces SharePoint file with a link after import. +1. Create a Profile named `Delete From SharePoint` that saves to the same folder and Deletes SharePoint file after import. + +Expected Results: + - Those three profiles exist + +#### Test metadata configuration +Steps: +1. Create a Profile named `number metadata` that saves to a folder of your choice and leaves a copy of the file in SharePoint after import. Assign a template that has a required short integer field in Laserfiche, and map the SharePoint Column `Actual Work` to the required short integer field. +1. Save the Profile. + +Expected Results: +- Profile appears. + + +### Save to Laserfiche and Profile Mapping Tab + +Prerequisites: + +- Follow the [Profiles](#profiles) Tests successfully +- Laserfiche Sign In Page must already exist +- Laserfiche Admin Configuration Page must already exist +#### Test Default Profile with No Content Type +Steps: +1. Inside the SharePoint site's `Documents` tab, remove the column displaying `Content Type`. +1. In the Profile Mapping Tab, associate the `[Default]` SharePoint Content Type with the `Example Profile Name` Laserfiche Profile. Remember to save the mapping. Make sure no other mappings exist. +1. Attempt to save a file to Laserfiche inside the Documents tab. + +Expected Results +- The file is saved according to the Default Profile + +#### Test with No Default Profile and with No Content Type +Steps: +1. Inside the SharePoint site's `Documents` tab, remove the column displaying `Content Type` if it exists. +1. In the Profile Mapping Tab, associate the `[Default]` SharePoint Content Type with the `Example Profile Name` Laserfiche Profile. Remember to save the mapping. Make sure no other mappings exist. +1. Attempt to save a file to Laserfiche inside the Documents tab. + +Expected Results +- The file is not saved +- An error message explains that the file is not saved because there is no default mapping +#### Test Default Profile +Steps: +1. Add `Content Type` as a column in the Documents tab if it doesn't already exist. +1. In the Profile Mapping Tab, associate the `[Default]` SharePoint Content Type with the `Example Profile Name` Laserfiche Profile. Remember to Save the mapping. +1. Eliminate all other mappings +1. Save a document from the Documents Tab of the SharePoint site to Laserfiche + +Expected Results: + - The file should save in the destination folder you configured in the Default Profile. + +#### Test Saving already saved document +Prerequisites: + - execute the `Test Default Profile` test +Steps: + - Save the same document to Laserfiche as in the Test Default Profile Test +Expected Results: You should get a warning that an entry with the same name already exists, and that Laserfiche will rename the new documents. If you continue, and open the file in Laserfiche, the document should be renamed. +#### Test No Default Profile Save +Steps: +1. Remove all SharePoint Content Type -> Laserfiche Profile Mappings +1. Attempt to save a Document from the documents tab + +Expected Result: + - Document does not save + - Error that requests a default mapping or a mapping for the relevant content type + +#### Test Save when a required field doesn't exist +Steps: +1. Add SharePoint Column `Actual Work` to SharePoint Library +1. Make sure that `Actual Work` has no value for a specific document +1. Set the Default mapping to `number metadata`, and save. There should be no other mappings +1. Attempt to save the specific document to Laserfiche + +Expected Results: + - The document does not save + - Error message that says that Actual Work doesn't have a value. +#### Test metadata constraint failed case +Steps: +1. Add SharePoint Column "Actual Work" to SharePoint Library +1. Add value for "Actual Work" for a specific document to be a number of 65,000. +1. Set the Default mapping to `number metadata`, and save. +1. Attempt to save the specific document to Laserfiche + +Expected Results: + - The document should save, BUT + - There should be a warning that says the metadata didn't save. + +#### Test specific mapping overrides default +Steps: +1. Remove all Profile Mappings +1. Add a mapping from `[Default]` to `Example Profile Name` +1. Add a mapping from `Document` to `number metadata` +1. Choose a Document in SharePoint +1. Update the `Actual Work` column of the document to have a value of 5 +1. Attempt to save the document to Laserfiche + +Expected Results: + - The document should successfully save + - The document's number field should have a value of 5 in Laserfiche Web Client. +#### Test replace with URL action +Steps: +1. Edit the mapping from `Document` so that it points to `Replace with Link` +1. Attempt to save a Document to Laserfiche + +Expected Results: + - The document should successfully appear in Laserfiche + - In SharePoint, the document should be replaced with a link + - Link should actually link to the document in LF + +#### Test delete after save to Laserfiche +Steps: +1. Edit the mapping from `Document` so that it points to `Delete From SharePoint` +1. Attempt to save a Document to Laserfiche + +Expected Results: + - The document should exist in Laserfiche and no longer exist in SharePoint + +#### Test saving .url files to Laserfiche +Steps: +1. Attempt to save a .url file to Laserfiche + +Expected Result: + - You should be told that you can't save a .url file to Laserfiche. + +#### Test Mapping Content Types to multiple Profiles +Steps: +1. In addition to the existing `[Default]` -> `Example Profile Name` mapping, add a mapping from `[Default]` to `Replace with Link`. +1. Click Save + +Expected Results + - The new mapping should not save + - You should see an error message saying a mapping already exists for that content type + +### Repository Explorer + +Prerequisites: + +- Follow the [Installation](#installation) and [Site Configuration](#site-configuration) steps successfully + +#### Test login + +Steps: + +1. Click `Sign in` button + - Expected results: You are led through the OAuth flow via a popup window, you return to repository explorer page, and button says `Sign Out`. + +#### Test Open button + +Steps: + +1. Open repository explorer to the root folder +1. Without selecting an entry, click the Open button. + - Expected result: Open root folder in Laserfiche in a new tab +1. Return to repository explorer and select (single-click) a folder inside +1. Click open button + - Expected result: Open the selected folder in Laserfiche in a new tab +1. Return to repository explorer and select (single-click) a document inside +1. Click the open button + - Expected result: Open the selected document in Laserfiche in a new tab + +#### Test import file button + +Steps: + +1. Navigate to a folder that you have access to create documents in +1. Have no folder/document selected +1. Click the import file button +1. Click import without uploading file + - Expected behavior: Error message stating please select a file to upload +1. Upload test file using browse button +1. Add no metadata +1. Click ok + - Expected behavior: Dialog closes +1. Use refresh button to refresh open folder + - Expected behavior: File exists in currently opened folder +1. Back in repository explorer, single-click a folder +1. Click the import file button +1. Upload test file using browse button +1. Add no metadata +1. Click ok + - Expected behavior: Dialog closes +1. Use refresh button to refresh open folder + - Expected behavior: File exists in currently opened folder (not the one selected) +1. Back in the repository explorer, single-click a file +1. Click the import file button +1. Upload test file using browse button +1. Add no metadata +1. Click ok + - Expected behavior: Dialog closes +1. Use refresh button to refresh open folder + - Expected behavior: File exists in currently opened folder (does not replace file) +1. Back in repository explorer, click the import file button +1. Upload test file using browse button +1. Add template +1. Make an error in the metadata (e.g., required field empty) +1. Attempt to upload file + - Expected behavior: File not uploaded, metadata component shows relevant errors if not already shown +1. Add valid metadata +1. Click ok + - Expected behavior: Dialog closes +1. Use refresh button to refresh open folder + - Expected behavior: File exists in currently opened folder +1. Double-click recently imported file + - Expected behavior: Metadata specified was successfully set +1. Back in repository explorer, click the import file button +1. Upload test file using browse button +1. Rename file to be same as existing document +1. Click ok + - Expected behavior: Dialog closes +1. Use refresh button to refresh open folder + - Expected behavior: File was uploaded, but has been automatically renamed + +#### Test Create folder button + +Test delete after save action + +1. Navigate to a folder where you have permissions to create entries +1. Use create folder button +1. Create folder with valid name + - Expected Results: Dialog closes +1. Use refresh button + - Expected results: New folder exists in currently open folder +1. Use create folder button +1. Attempt to create with no name + - Expected results: Dialog remains open, error specifies to provide a folder name +1. Close dialog +1. Use create folder button +1. Use name with the invalid character `\`. +1. Attempt to create folder + - Expected results: Dialog remains open, error specifies to provide a valid folder name +1. Use create folder button. +1. Use name with alphanumeric and with some of the valid special characters `!@#$%^&*()`. +1. Attempt to create folder. +1. Use refresh button + - Expected results: New folder exists in currently open folder with special characters in the name. +1. Use create folder button +1. Use name that already exists in folder +1. Attempt to create + - Expected Results: Dialog remains open, receive error that object already exists +1. Select (single-click) a folder in the repository explorer +1. Use create folder button +1. Create folder with valid, unique name + - Expected Results: Dialog closes +1. Use refresh button + - Expected results: New folder exists in currently open folder + +#### Test refresh button + +Steps: + +1. Open specific folder in repository explorer +1. Open same folder in Web Client in a new tab +1. Create folder in Web Client in that folder +1. Return to repository explorer tab +1. Click refresh button + - Expected behavior: Folder that was created in Web Client will now exist in the repository explorer