Skip to content

Commit 08e9aaa

Browse files
authored
Merge pull request #1889 from a1mery/react-command-task-mgmt
New sample: React command task management
2 parents 41823c5 + a64e742 commit 08e9aaa

25 files changed

Lines changed: 20131 additions & 0 deletions
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
6+
# Dependency directories
7+
node_modules
8+
9+
# Build generated files
10+
dist
11+
lib
12+
lib-dts
13+
lib-commonjs
14+
lib-esm
15+
jest-output
16+
release
17+
solution
18+
temp
19+
*.sppkg
20+
.heft
21+
22+
# Coverage directory used by tools like istanbul
23+
coverage
24+
25+
# OSX
26+
.DS_Store
27+
28+
# Visual Studio files
29+
.ntvs_analysis.dat
30+
.vs
31+
bin
32+
obj
33+
34+
# Resx Generated Code
35+
*.resx.ts
36+
37+
.instructions
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Ignore everything by default
2+
**
3+
4+
# Use negative patterns to bring back the specific things we want to publish
5+
!/bin/**
6+
!/dist/**
7+
!/EULA/**
8+
!/lib/**
9+
!/lib-*/**
10+
!ThirdPartyNotice.txt
11+
12+
# Ignore certain files in the above folders
13+
/dist/*.stats.*
14+
/dist/**/*.map
15+
/lib/**/*.map
16+
/lib/**/*.test.*
17+
/lib/**/test/**
18+
/lib-*/**/*.map
19+
/lib-*/**/*.test.*
20+
/lib-*/**/test/**
21+
22+
# NOTE: These don't need to be specified, because NPM includes them automatically.
23+
#
24+
# package.json
25+
# README (and its variants)
26+
# CHANGELOG (and its variants)
27+
# LICENSE / LICENCE
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v22.14.0
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{"timestamp":"2026-05-29T20:57:27.917Z","kind":"session-started","cliVersion":"0.1.0-pre.3"}
2+
{"timestamp":"2026-05-29T20:57:28.481Z","kind":"template-rendered","templateName":"extension-listviewcommandset","templateVersion":"1.0.0","spfxVersion":"1.22.2","context":{"solution_name":"react-command-task-mgmt","libraryName":"react-command-task-mgmt","spfxVersion":"1.22.2","spfxVersionForBadgeUrl":"1.22.2","componentId":"0dd1fb3d-e3e3-47ad-b218-a0a5e275f7b1","featureId":"d13bddb9-911f-4767-9e43-b16cd7bb92f9","solutionId":"71f9db24-0d1d-4659-a232-abc9ad718491","componentAlias":"Approve action","componentName":"Approve action","componentDescription":"Approve action description"},"cliVersion":"0.1.0-pre.3"}
3+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":".eslintrc.js","outcome":"new"}
4+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":".gitignore","outcome":"new"}
5+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":".npmignore","outcome":"new"}
6+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":".vscode/launch.json","outcome":"new"}
7+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":".vscode/settings.json","outcome":"new"}
8+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":"README.md","outcome":"new"}
9+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":"config/config.json","outcome":"new"}
10+
{"timestamp":"2026-05-29T20:57:28.485Z","kind":"file-write","relativePath":"config/deploy-azure-storage.json","outcome":"new"}
11+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"config/package-solution.json","outcome":"new"}
12+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"config/rig.json","outcome":"new"}
13+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"config/sass.json","outcome":"new"}
14+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"config/serve.json","outcome":"new"}
15+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"config/typescript.json","outcome":"new"}
16+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"config/write-manifests.json","outcome":"new"}
17+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"package.json","outcome":"new"}
18+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"sharepoint/assets/ClientSideInstance.xml","outcome":"new"}
19+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"sharepoint/assets/elements.xml","outcome":"new"}
20+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"src/extensions/approveActionCommandSet/icons/cancel.svg","outcome":"new"}
21+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"src/extensions/approveActionCommandSet/icons/request.svg","outcome":"new"}
22+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"src/extensions/approveActionCommandSet/loc/en-us.js","outcome":"new"}
23+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"src/extensions/approveActionCommandSet/loc/approveActionCommandSetStrings.d.ts","outcome":"new"}
24+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"src/extensions/approveActionCommandSet/ApproveActionCommandSet.manifest.json","outcome":"new"}
25+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"src/extensions/approveActionCommandSet/ApproveActionCommandSet.ts","outcome":"new"}
26+
{"timestamp":"2026-05-29T20:57:28.486Z","kind":"file-write","relativePath":"tsconfig.json","outcome":"new"}
27+
{"timestamp":"2026-05-29T20:57:49.134Z","kind":"session-started","cliVersion":"0.1.0-pre.3"}
28+
{"timestamp":"2026-05-29T20:57:49.615Z","kind":"template-rendered","templateName":"extension-listviewcommandset","templateVersion":"1.0.0","spfxVersion":"1.22.2","context":{"solution_name":"react-command-task-mgmt","libraryName":"react-command-task-mgmt","spfxVersion":"1.22.2","spfxVersionForBadgeUrl":"1.22.2","componentId":"ce397a58-294d-4237-ac5d-b872562dac33","featureId":"748610e5-eac8-4c98-ac46-37226b1dffe0","solutionId":"fbc40120-151d-4082-8d29-5a39a008ff75","componentAlias":"Reject action","componentName":"Reject action","componentDescription":"Reject action description"},"cliVersion":"0.1.0-pre.3"}
29+
{"timestamp":"2026-05-29T20:57:49.628Z","kind":"file-write","relativePath":"src/extensions/rejectActionCommandSet/icons/cancel.svg","outcome":"new"}
30+
{"timestamp":"2026-05-29T20:57:49.629Z","kind":"file-write","relativePath":"src/extensions/rejectActionCommandSet/loc/en-us.js","outcome":"new"}
31+
{"timestamp":"2026-05-29T20:57:49.629Z","kind":"file-write","relativePath":"src/extensions/rejectActionCommandSet/loc/rejectActionCommandSetStrings.d.ts","outcome":"new"}
32+
{"timestamp":"2026-05-29T20:57:49.629Z","kind":"file-write","relativePath":"src/extensions/rejectActionCommandSet/RejectActionCommandSet.ts","outcome":"new"}
33+
{"timestamp":"2026-05-29T20:57:49.629Z","kind":"file-write","relativePath":"src/extensions/rejectActionCommandSet/icons/request.svg","outcome":"new"}
34+
{"timestamp":"2026-05-29T20:57:49.629Z","kind":"file-write","relativePath":"src/extensions/rejectActionCommandSet/RejectActionCommandSet.manifest.json","outcome":"new"}
35+
{"timestamp":"2026-05-29T20:57:49.631Z","kind":"file-write","relativePath":".eslintrc.js","outcome":"unchanged"}
36+
{"timestamp":"2026-05-29T20:57:49.631Z","kind":"file-write","relativePath":".npmignore","outcome":"unchanged"}
37+
{"timestamp":"2026-05-29T20:57:49.631Z","kind":"file-write","relativePath":".gitignore","outcome":"unchanged"}
38+
{"timestamp":"2026-05-29T20:57:49.631Z","kind":"file-write","relativePath":".vscode/settings.json","outcome":"unchanged"}
39+
{"timestamp":"2026-05-29T20:57:49.631Z","kind":"file-write","relativePath":"README.md","outcome":"preserved"}
40+
{"timestamp":"2026-05-29T20:57:49.635Z","kind":"file-write","relativePath":"config/config.json","outcome":"merged","mergeHelper":"config/config.json"}
41+
{"timestamp":"2026-05-29T20:57:49.635Z","kind":"file-write","relativePath":".vscode/launch.json","outcome":"unchanged"}
42+
{"timestamp":"2026-05-29T20:57:49.635Z","kind":"file-write","relativePath":"config/deploy-azure-storage.json","outcome":"preserved"}
43+
{"timestamp":"2026-05-29T20:57:49.636Z","kind":"file-write","relativePath":"config/package-solution.json","outcome":"merged","mergeHelper":"config/package-solution.json"}
44+
{"timestamp":"2026-05-29T20:57:49.637Z","kind":"file-write","relativePath":"config/sass.json","outcome":"unchanged"}
45+
{"timestamp":"2026-05-29T20:57:49.637Z","kind":"file-write","relativePath":"config/rig.json","outcome":"unchanged"}
46+
{"timestamp":"2026-05-29T20:57:49.638Z","kind":"file-write","relativePath":"config/serve.json","outcome":"merged","mergeHelper":"config/serve.json"}
47+
{"timestamp":"2026-05-29T20:57:49.638Z","kind":"file-write","relativePath":"config/typescript.json","outcome":"unchanged"}
48+
{"timestamp":"2026-05-29T20:57:49.638Z","kind":"file-write","relativePath":"config/write-manifests.json","outcome":"unchanged"}
49+
{"timestamp":"2026-05-29T20:57:49.638Z","kind":"file-write","relativePath":"package.json","outcome":"unchanged"}
50+
{"timestamp":"2026-05-29T20:57:49.638Z","kind":"file-write","relativePath":"sharepoint/assets/ClientSideInstance.xml","outcome":"preserved"}
51+
{"timestamp":"2026-05-29T20:57:49.638Z","kind":"file-write","relativePath":"sharepoint/assets/elements.xml","outcome":"preserved"}
52+
{"timestamp":"2026-05-29T20:57:49.638Z","kind":"file-write","relativePath":"tsconfig.json","outcome":"unchanged"}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Grouped ListView Command Set - Task Management
2+
3+
## Summary
4+
5+
This sample demonstrates the new **Grouping support for ListView Command Sets** introduced in **SPFx 1.23**. It adds a grouped **Status** command (with **Approve** and **Reject** sub-commands) to the SharePoint modern list view toolbar and context menu.
6+
7+
When one or more items are selected, the user can approve or reject the selected items in bulk. The extension updates the `Status` column for every selected item using **PnPjs** and refreshes the list view to surface the new values.
8+
9+
> Use case: Quickly triage a list of requests / tasks directly from the SharePoint list view without opening each item individually.
10+
11+
![Grouped command set in action](./assets/task-management.png)
12+
13+
## Compatibility
14+
15+
![SPFx 1.23.0](https://img.shields.io/badge/SPFx-1.23.0-green.svg)
16+
![Node.js v22.14+](https://img.shields.io/badge/Node.js-v22.14%2B-green.svg)
17+
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
18+
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
19+
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
20+
![Local Workbench Unsupported](https://img.shields.io/badge/Local%20Workbench-Unsupported-red.svg "Local workbench is no longer available as of SPFx 1.13 and above")
21+
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
22+
23+
## Applies to
24+
25+
- [SharePoint Framework](https://aka.ms/spfx)
26+
- [SharePoint Framework Extensions](https://learn.microsoft.com/sharepoint/dev/spfx/extensions/overview-extensions)
27+
- [Microsoft 365 tenant](https://learn.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant)
28+
29+
> Get your own free development tenant by subscribing to the [Microsoft 365 developer program](http://aka.ms/o365devprogram).
30+
31+
## Prerequisites
32+
33+
- Node.js **v22.14.0** or later (and below v23).
34+
- A SharePoint list that contains a single-line text or choice column named **`Status`** (the internal name must be `Status`).
35+
- Permissions to edit items on the target list.
36+
37+
## Contributors
38+
39+
- [Aimery Thomas](https://github.com/a1mery)
40+
41+
## Version history
42+
43+
| Version | Date | Comments |
44+
| ------- | ------------ | --------------- |
45+
| 1.0 | May 31, 2026 | Initial release |
46+
47+
## Minimal Path to Awesome
48+
49+
- Clone this repository
50+
- Ensure that you are at the solution folder
51+
- In the command-line run:
52+
- `npm install`
53+
- `npm start` (runs `heft start --clean`)
54+
55+
To package the solution for deployment:
56+
57+
- `npm run build` — produces a production `.sppkg` under `sharepoint/solution/`.
58+
59+
Other build commands can be listed using `heft --help`.
60+
61+
### Debug URL for testing
62+
63+
Append the following query string to a modern list page URL (replace the GUID with the value from `GroupingCommandSetCommandSet.manifest.json` if you regenerate it):
64+
65+
```url
66+
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"8a3f5c12-1d4e-4b2a-9c8f-3b1e5d6a7f90":{"location":"ClientSideExtension.ListViewCommandSet.CommandBar"}}
67+
```
68+
69+
## Features
70+
71+
This extension illustrates the following concepts:
72+
73+
- Using the **new SPFx 1.23 manifest** with `"type": "group"` items to declare grouped commands in a `ListViewCommandSet`.
74+
- Nesting commands under a group with the `"group": "<GROUP_ID>"` property (two levels: group → command).
75+
- Using **Heft** (Rushstack) as the build engine instead of Gulp.
76+
77+
### How grouping works
78+
79+
The manifest defines:
80+
81+
| Item ID | Type | Group | Purpose |
82+
| -------------- | ------- | -------------- | ------------------------------ |
83+
| `GROUP_STATUS` | group || Dropdown header named "Status" |
84+
| `CMD_APPROVE` | command | `GROUP_STATUS` | Sets `Status` to `Approved` |
85+
| `CMD_REJECT` | command | `GROUP_STATUS` | Sets `Status` to `Rejected` |
86+
87+
## References
88+
89+
- [Getting started with SharePoint Framework](https://learn.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant)
90+
- [Build your first ListView Command Set extension](https://learn.microsoft.com/sharepoint/dev/spfx/extensions/get-started/building-simple-cmdset-with-list-view)
91+
- [SPFx 1.23 release notes](https://learn.microsoft.com/sharepoint/dev/spfx/release-1.23)
92+
- [PnPjs documentation](https://pnp.github.io/pnpjs/)
93+
- [Heft Documentation](https://heft.rushstack.io/)
94+
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
95+
96+
## Disclaimer
97+
98+
**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.**
99+
100+
---
101+
102+
<img src="https://m365-visitor-stats.azurewebsites.net/sp-dev-fx-extensions/samples/react-command-task-mgmt" />
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
[
2+
{
3+
"name": "pnp-sp-dev-spfx-extensions-react-command-task-mgmt",
4+
"source": "pnp",
5+
"title": "Grouped ListView Command Set - Task Management",
6+
"shortDescription": "This sample demonstrates the new Grouping support for ListView Command Sets introduced in SPFx 1.23. It adds a grouped Status command (with Approve and Reject sub-commands) to the SharePoint modern list view toolbar and context menu.",
7+
"url": "https://github.com/pnp/sp-dev-fx-extensions/tree/main/samples/react-command-task-mgmt",
8+
"longDescription": [
9+
"This sample demonstrates the new Grouping support for ListView Command Sets introduced in SPFx 1.23. It adds a grouped Status command (with Approve and Reject sub-commands) to the SharePoint modern list view toolbar and context menu."
10+
],
11+
"creationDateTime": "2026-05-31",
12+
"updateDateTime": "2026-05-31",
13+
"products": [
14+
"SharePoint"
15+
],
16+
"metadata": [
17+
{
18+
"key": "CLIENT-SIDE-DEV",
19+
"value": "React"
20+
},
21+
{
22+
"key": "SPFX-VERSION",
23+
"value": "1.23.0"
24+
}
25+
],
26+
"tags": [],
27+
"categories": [
28+
"SPFX-APPLICATION-EXTENSION"
29+
],
30+
"thumbnails": [
31+
{
32+
"name": "task-management.png",
33+
"type": "image",
34+
"order": 100,
35+
"url": "https://github.com/pnp/sp-dev-fx-extensions/raw/main/samples/react-command-task-mgmt/assets/task-management.png",
36+
"alt": "Web Part Preview"
37+
}
38+
],
39+
"authors": [
40+
{
41+
"gitHubAccount": "a1mery",
42+
"pictureUrl": "https://github.com/a1mery.png",
43+
"name": "Aimery Thomas"
44+
}
45+
],
46+
"references": [
47+
{
48+
"name": "Overview of SharePoint Framework Extensions",
49+
"description": "You can use SharePoint Framework (SPFx) Extensions to extend the SharePoint user experience. With SPFx Extensions, you can customize more facets of the SharePoint experience, including notification areas, toolbars, and list data views. SPFx Extensions are available in all Microsoft 365 subscriptions for production usage.",
50+
"url": "https://learn.microsoft.com/sharepoint/dev/spfx/extensions/overview-extensions?WT.mc_id=m365-15741-cxa"
51+
},
52+
{
53+
"name": "Use page placeholders from Application Customizer",
54+
"description": "Application Customizers provide access to well-known locations on SharePoint pages that you can modify based on your business and functional requirements. For example, you can create dynamic header and footer experiences that render across all the pages in SharePoint Online.",
55+
"url": "https://learn.microsoft.com/sharepoint/dev/spfx/extensions/get-started/using-page-placeholder-with-extensions?WT.mc_id=m365-15741-cxa"
56+
}
57+
]
58+
}
59+
]
142 KB
Loading
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
3+
"version": "2.0",
4+
"bundles": {
5+
"grouping-command-set": {
6+
"components": [
7+
{
8+
"entrypoint": "./lib/extensions/groupingCommandSet/GroupingCommandSetCommandSet.js",
9+
"manifest": "./src/extensions/groupingCommandSet/GroupingCommandSetCommandSet.manifest.json"
10+
}
11+
]
12+
}
13+
},
14+
"externals": {},
15+
"localizedResources": {
16+
"GroupingCommandSetStrings": "lib/extensions/groupingCommandSet/loc/{locale}.js"
17+
}
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
3+
"workingDir": "./release/assets/",
4+
"account": "<!-- STORAGE ACCOUNT NAME -->",
5+
"container": "approve-action",
6+
"accessKey": "<!-- ACCESS KEY -->"
7+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
3+
"solution": {
4+
"name": "react-command-task-mgmt-client-side-solution",
5+
"id": "71f9db24-0d1d-4659-a232-abc9ad718491",
6+
"version": "1.0.0.0",
7+
"includeClientSideAssets": true,
8+
"skipFeatureDeployment": true,
9+
"isDomainIsolated": false,
10+
"developer": {
11+
"name": "",
12+
"websiteUrl": "",
13+
"privacyUrl": "",
14+
"termsOfUseUrl": "",
15+
"mpnId": "Undefined-1.23.0"
16+
},
17+
"metadata": {
18+
"shortDescription": {
19+
"default": "Grouped Status/Share command set sample"
20+
},
21+
"longDescription": {
22+
"default": "Demonstrates SPFx 1.23 grouping support for ListView Command Sets with Approve/Reject and Copy item link actions."
23+
},
24+
"screenshotPaths": [],
25+
"videoUrl": "",
26+
"categories": []
27+
},
28+
"features": [
29+
{
30+
"title": "Grouping Command Set - Deployment of grouped list view commands",
31+
"description": "Deploys the grouped Status/Share List View Command Set",
32+
"id": "b6c7d8e9-1a2b-3c4d-5e6f-7890abcdef12",
33+
"version": "1.0.0.0",
34+
"assets": {
35+
"elementManifests": [
36+
"elements.xml"
37+
],
38+
"elementFiles": [
39+
"ClientSideInstance.xml"
40+
]
41+
}
42+
}
43+
]
44+
},
45+
"paths": {
46+
"zippedPackage": "solution/react-command-task-mgmt.sppkg"
47+
}
48+
}

0 commit comments

Comments
 (0)