Skip to content

Commit ad29be7

Browse files
authored
Merge pull request #1524 from NicolasKheirallah/react-command-convert-to-pdf
2 parents 2e69f91 + 1dca899 commit ad29be7

33 files changed

Lines changed: 12425 additions & 8394 deletions
Lines changed: 55 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,87 @@
1-
# SharePoint PDF Converter
1+
# Save and convert as PDF by PnP
22

3-
![preview](./screenshot.gif "Preview")
3+
## Summary
4+
5+
A global list customizer which adds functionality to all document libraries in SharePoint Online to convert one or more documents in-place to PDF, or download one or more documents as a PDF. When selecting multiple documents for download they will be downloaded as a zip file. The converter uses built in API's of converting to PDF.
46

5-
A SharePoint Framework extension that brings powerful PDF conversion capabilities to your SharePoint Online document libraries. Convert documents to PDF, download files as PDF, preserve metadata, and more - all with a modern, responsive UI.
7+
![preview](./screenshot.gif "Preview")
68

79
## Compatibility
810

9-
![SPFx 1.20](https://img.shields.io/badge/spfx-1.20.0-green.svg)
10-
![Node.js LTS 18.x](https://img.shields.io/badge/Node.js-LTS%2018.x-green.svg)
11+
![SPFx 1.21.1](https://img.shields.io/badge/spfx-1.10.0-green.svg)
12+
![Node.js LTS 18.x | LTS 8.x](https://img.shields.io/badge/Node.js-LTS%206.x%20%7C%20LTS%208.x-green.svg)
1113
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-red.svg)
1214
![Workbench Hosted: Does not work with local workbench](https://img.shields.io/badge/Workbench-Hosted-yellow.svg "Does not work with local workbench")
1315

14-
## Key Features
15-
16-
### PDF Conversion
17-
- Convert documents to PDF with customizable quality settings (low, medium, high)
18-
- Support for multiple file formats: Word, Excel, PowerPoint, CSV, RTF, and more
19-
- Powered by Microsoft Graph API V3 for efficient processing
16+
## Applies to
2017

21-
### Advanced Options
22-
- **Batch Processing**: Convert multiple documents simultaneously
23-
- **Metadata Preservation**: Keep important document properties during conversion
24-
- **Custom Destinations**: Choose where to save your converted files
25-
- **Email Integration**: Send PDFs via email with custom subject lines
18+
* [SharePoint Framework Extensions](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/extensions/overview-extensions)
2619

27-
### Modern Experience
28-
- **Fluent UI Design**: Clean, modern interface following Microsoft design language
29-
- **Responsive Layout**: Works on desktop and mobile devices
30-
- **Dark/Light Mode**: Support for different visual preferences
31-
- **Accessibility**: Designed with accessibility in mind
32-
- **Multi-language Support**: English, French, Spanish, German included
20+
## Solution
3321

34-
## How It Works
22+
Solution|Author(s)
23+
--------|---------
24+
pnp-ext-pdf-convert| Mikael Svenson ([@mikaelsvenson](https://twitter.com/mikaelsvenson))
3525

36-
The extension adds two commands to your document library ribbon:
26+
## Version history
3727

38-
1. **Download as PDF**: Converts selected document(s) and downloads to your device
39-
2. **Convert to PDF**: Transforms document(s) to PDF and saves in SharePoint
28+
Version|Date|Comments
29+
-------|----|--------
30+
1.0| 2019| Initial release by Puzzlepart
31+
1.1| February 23, 2021| Moved and re-branded to PnP
32+
1.2| October 30, 2022| Upgrade SPFx to version 1.12.1
33+
1.3| October 21, 2024| Upgrade SPFx to version 1.20.1, rewrite it from scratch using Graph API and using the built in converter in Graph, moved to Fluent UI and alot more
34+
1.4| September 03 2025| Added batch operations, progress indicators, multi-language support (EN/FR/ES/DE), ZIP downloads, enhanced error handling
4035

41-
When triggered, a customizable options panel allows you to:
42-
- Set conversion quality
43-
- Enable/disable metadata preservation
44-
- Send email notifications
45-
- Select custom save locations
46-
47-
![Options Dialog](./options-dialog.png)
36+
## Disclaimer
4837

49-
## Quick Start Guide
38+
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
5039

51-
### Installation
40+
## Installing the solution
5241

53-
1. Download the [pnp-ext-pdf-convert.sppkg](./pnp-ext-pdf-convert.sppkg) file
54-
2. Upload to your tenant app catalog
55-
- URL: `https://<tenant>-admin.sharepoint.com/_layouts/15/online/ManageAppCatalog.aspx`
56-
- Requires SharePoint Administrator rights
57-
3. Trust the solution when prompted
58-
![Trust Solution](./screenshot-2.png)
59-
4. Navigate to any document library to begin using the commands
42+
- Upload and Deploy the file [pnp-ext-pdf-convert.sppkg](./pnp-ext-pdf-convert.sppkg) to your tenant app catalog. ![TrustSolution](./screenshot-2.png "Trust solution")
43+
* If created the tenant app catalog can be reached via `https://<tenant>-admin.sharepoint.com/_layouts/15/online/ManageAppCatalog.aspx`.
44+
* You need to be a SharePoint Administrator to upload this solution.
45+
- Navigate to a document library and select one or more files and you should see the PDF options in the document ribbon.
6046

61-
### Usage
47+
_Note: It may take a little while before it shows the first time after install._
6248

63-
1. Select one or more supported documents in a library
64-
2. Click either "Download as PDF" or "Convert to PDF" from the ribbon
65-
3. Configure your preferences in the options dialog
66-
4. Start the conversion
67-
5. View progress and results in the status dialog
49+
## Features
6850

69-
## Supported File Formats
51+
### 🔄 Batch Operations
52+
- **Multi-file Selection**: Select multiple documents using Ctrl+Click or Shift+Click
53+
- **Batch Download**: Download multiple files as PDFs in a single ZIP archive
54+
- **Batch Convert**: Convert multiple files to PDF and save them in the same library
55+
- **Smart Validation**: Automatically filters out unsupported file types
7056

71-
- **Word Documents**: doc, docx, rtf
72-
- **Excel Spreadsheets**: xls, xlsx, csv
73-
- **PowerPoint Presentations**: ppt, pptm, pptx, pps, ppsx, ppsxm, pot, potm, potx
74-
- **OpenDocument Formats**: odp, ods, odt
75-
- **Other**: html
57+
### 📊 Progress Tracking
58+
- **Real-time Progress Bar**: Visual progress indicator for batch operations
59+
- **File Status Updates**: See which file is currently being processed
60+
- **Success/Error Indicators**: Clear visual feedback for each file's conversion status
61+
- **Summary Reports**: Detailed completion reports with success and error counts
7662

77-
## Version History
63+
### 🌐 Multi-language Support
64+
- **English (en-us)**: Default language
65+
- **French (fr-fr)**: Français
66+
- **Spanish (es-es)**: Español
67+
- **German (de-de)**: Deutsch
68+
- **Dynamic UI**: Command titles update based on selection count
7869

79-
| Version | Date | Description |
80-
|---------|------|-------------|
81-
| 1.0 | 2019 | Initial release by Puzzlepart |
82-
| 1.1 | Feb 2021 | Re-branded to PnP |
83-
| 1.2 | Oct 2022 | Updated to SPFx 1.12.1 |
84-
| 1.3 | Oct 2024 | Complete rewrite with Graph API, SPFx 1.20.1, Fluent UI |
85-
| 1.4 | Mar 2025 | Feature-complete version with metadata preservation, multi-language support, email integration, and more |
70+
### 💾 Enhanced Downloads
71+
- **ZIP Archives**: Multiple files automatically packaged with timestamp
72+
- **Smart Naming**: Original filenames preserved with .pdf extension
73+
- **Error Recovery**: Failed conversions don't interrupt the batch process
8674

87-
## For Developers
75+
## Supported file formats
8876

89-
### Required Permissions
77+
csv, doc, docx, odp, ods, odt, pot, potm, potx, pps, ppsx, ppsxm, ppt, pptm, pptx, rtf, xls, xlsx, html
9078

91-
The extension requires these Microsoft Graph API permissions:
92-
- Files.ReadWrite
93-
- Sites.ReadWrite.All
94-
- Mail.Send (for email features)
79+
## Debug URL for testing
9580

96-
### Debug URL
81+
Here's a debug URL for testing around this sample.
9782

9883
```
9984
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&loadSPFX=true&customActions={"ea401ac9-3abc-4e27-b93b-09c9a0587ee9":{"location":"ClientSideExtension.ListViewCommandSet.CommandBar","properties":{}}}
10085
```
10186

102-
### Technical Implementation
103-
104-
- Utilizes SPFx Command Set Extensions
105-
- Leverages Microsoft Graph API for file operations
106-
- React components with Fluent UI
107-
- TypeScript for type safety
108-
- Responsive design principles
109-
110-
## Solution
111-
112-
| Solution | Author(s) |
113-
|----------|-----------|
114-
| pnp-ext-pdf-convert | Mikael Svenson ([@mikaelsvenson](https://twitter.com/mikaelsvenson)) |
115-
| pnp-ext-pdf-convert | Nicolas Kheirallah ([@NicolasKheirallah](https://twitter.com/NicolasKheirallah)) |
116-
117-
## Disclaimer
118-
119-
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
120-
121-
![](https://m365-visitor-stats.azurewebsites.net/sp-dev-fx-extensions/samples/react-command-convert-to-pdf)
87+
![](https://m365-visitor-stats.azurewebsites.net/sp-dev-fx-extensions/samples/react-command-convert-to-pdf)

samples/react-command-convert-to-pdf/assets/sample.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"A global list customizer which adds functionality to all document libraries in SharePoint Online to convert one or more documents in-place to PDF, or download one or more documents as a PDF. When selecting multiple documents for download they will be downloaded as a zip file. The converter uses built in API\u0027s of converting to PDF."
1010
],
1111
"creationDateTime": "2021-02-23",
12-
"updateDateTime": "2024-10-23",
12+
"updateDateTime": "2025-09-03",
1313
"products": [
1414
"SharePoint"
1515
],
@@ -20,7 +20,7 @@
2020
},
2121
{
2222
"key": "SPFX-VERSION",
23-
"value": "1.20.0"
23+
"value": "1.21.1"
2424
}
2525
],
2626
"tags": [],
@@ -42,6 +42,10 @@
4242
"pictureUrl": "https://github.com/wobba.png",
4343
"name": "Mikael Svenson",
4444
"twitter": "mikaelsvenson"
45+
},{
46+
"gitHubAccount": "NicolasKheirallah",
47+
"pictureUrl": "https://github.com/NicolasKheirallah.png",
48+
"name": "Nicolas Kheirallah"
4549
}
4650
],
4751
"references": [
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@echo off
2+
cls
3+
4+
REM Ensure we are in the correct directory
5+
pushd %~dp0
6+
7+
REM Clean the previous build artifacts
8+
echo Cleaning previous build artifacts...
9+
call gulp clean
10+
11+
REM Build the project in production mode
12+
echo Building the project...
13+
call gulp build --ship
14+
15+
REM Bundle the project resources for production
16+
echo Bundling the project resources...
17+
call gulp bundle --ship
18+
19+
REM Package the solution for deployment
20+
echo Packaging the solution...
21+
call gulp package-solution --ship
22+
23+
REM Open the solution folder in File Explorer
24+
echo Opening the solution folder...
25+
start "" explorer ".\sharepoint\solution\"
26+
27+
REM Return to the original directory
28+
popd

samples/react-command-convert-to-pdf/config/config.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
},
1414
"externals": {},
1515
"localizedResources": {
16-
"PdfExportCommandSetStrings": "lib/extensions/pdfExport/loc/{locale}.js",
17-
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
16+
"PdfExportCommandSetStrings": "lib/extensions/pdfExport/loc/{locale}.js"
1817
}
19-
}
18+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
3+
"deployCdnPath": "./release/assets/"
4+
}

samples/react-command-convert-to-pdf/config/package-solution.json

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
"solution": {
44
"name": "Save and convert as PDF by PnP",
55
"id": "06babd6f-e62f-41e8-87c9-6cb516203a2d",
6-
"version": "1.4.0.171",
6+
"version": "1.4.0.0",
77
"includeClientSideAssets": true,
88
"skipFeatureDeployment": true,
9-
"isDomainIsolated": false,
109
"webApiPermissionRequests": [
10+
{
11+
"resource": "Microsoft Graph",
12+
"scope": "Sites.Read.All"
13+
},
1114
{
1215
"resource": "Microsoft Graph",
1316
"scope": "Sites.ReadWrite.All"
@@ -17,31 +20,13 @@
1720
"scope": "Files.ReadWrite.All"
1821
}
1922
],
20-
"developer": {
21-
"name": "",
22-
"websiteUrl": "",
23-
"privacyUrl": "",
24-
"termsOfUseUrl": "",
25-
"mpnId": ""
26-
},
27-
"metadata": {
28-
"shortDescription": {
29-
"default": "Save and convert as PDF by PnP"
30-
},
31-
"longDescription": {
32-
"default": "Save and convert as PDF by PnP"
33-
},
34-
"screenshotPaths": [],
35-
"videoUrl": "",
36-
"categories": []
37-
},
3823
"features": [
3924
{
4025
"title": "Save and convert as PDF by PnP",
4126
"description": "Deploys a custom action to allow save and conversion of files as PDF from a library.",
4227
"id": "94d2d641-737d-44ff-9c4d-32ac54996478",
43-
"version": "1.4.0.0",
44-
"assets": {
28+
"version": "1.1.0.0",
29+
"assets": {
4530
"elementManifests": [
4631
"elements.xml",
4732
"ea401ac9-3abc-4e27-b93b-09c9a0587ee9.xml"

samples/react-command-convert-to-pdf/config/sass.json

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11
{
2-
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
2+
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
33
"port": 4321,
44
"https": true,
5-
"initialPage": "https://enter-your-SharePoint-site/_layouts/workbench.aspx"
5+
"serveConfigurations": {
6+
"default": {
7+
"pageUrl": "https://contoso.sharepoint.com/Shared%20Documents/Forms/AllItems.aspx",
8+
"customActions": {
9+
"ea401ac9-3abc-4e27-b93b-09c9a0587ee9": {
10+
"location": "ClientSideExtension.ListViewCommandSet",
11+
"properties": {}
12+
}
13+
}
14+
},
15+
"pdfExport": {
16+
"pageUrl": "https://contoso.sharepoint.com/Shared%20Documents/Forms/AllItems.aspx",
17+
"customActions": {
18+
"ea401ac9-3abc-4e27-b93b-09c9a0587ee9": {
19+
"location": "ClientSideExtension.ListViewCommandSet",
20+
"properties": {}
21+
}
22+
}
23+
}
24+
}
625
}

samples/react-command-convert-to-pdf/gulpfile.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,36 @@
11
'use strict';
22

3+
const gulp = require('gulp');
4+
const path = require('path');
35
const build = require('@microsoft/sp-build-web');
46

7+
const bundleAnalyzer = require('webpack-bundle-analyzer');
8+
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
9+
build.addSuppression(
10+
`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`
11+
);
12+
build.addSuppression(/error semicolon: Unnecessary semicolon$/);
13+
build.addSuppression(/error semicolon: Missing semicolon$/);
14+
build.addSuppression(/filename should end with module.sass or module.scss$/);
15+
build.addSuppression(/Warning/gi);
16+
17+
build.configureWebpack.mergeConfig({
18+
additionalConfiguration: (generatedConfiguration) => {
19+
const lastDirName = path.basename(__dirname);
20+
const dropPath = path.join(__dirname, 'temp', 'stats');
21+
generatedConfiguration.plugins.push(new bundleAnalyzer.BundleAnalyzerPlugin({
22+
openAnalyzer: false,
23+
analyzerMode: 'static',
24+
reportFilename: path.join(dropPath, `${lastDirName}.stats.html`),
25+
generateStatsFile: false,
26+
logLevel: 'error'
27+
}));
28+
29+
return generatedConfiguration;
30+
}
31+
});
32+
33+
534
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
635

736
var getTasks = build.rig.getTasks;
@@ -13,4 +42,7 @@ build.rig.getTasks = function () {
1342
return result;
1443
};
1544

16-
build.initialize(require('gulp'));
45+
46+
require("./spfx-versioning")(build);
47+
build.tslintCmd.enabled = false;
48+
build.initialize(require("gulp"));

0 commit comments

Comments
 (0)