mirror of
https://github.com/pnp/sp-dev-fx-webparts.git
synced 2025-02-09 06:25:01 +00:00
Merge branch 'pnp:main' into React-Calendar-recurrent-events-issue
This commit is contained in:
commit
195e67ec28
@ -37,6 +37,7 @@ Short summary on functionality and used technologies.
|
||||
> If using SPFx 1.12.1, update the SPFx and Node.js tags accordingly:
|
||||
> ![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
|
||||
> ![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
>
|
||||
> If using an older version of SPFx, update the SPFx and Node.js compatibility tag accordingly:
|
||||
> SPFx 1.11
|
||||
> ![SPFx 1.11](https://img.shields.io/badge/SPFx-1.11.0-green.svg)
|
||||
@ -47,12 +48,13 @@ Short summary on functionality and used technologies.
|
||||
> ![Node.js LTS 6.x | LTS 8.x](https://img.shields.io/badge/Node.js-LTS%206.x%20%7C%20LTS%208.x-green.svg)
|
||||
>
|
||||
> If you built this sample specifically for SharePoint 2016, or SharePoint 2019 support, update the SharePoint compatibility tag accordingly:
|
||||
> ![SharePoint 2019 | Online](https://img.shields.io/badge/SharePoint-2019%20%7C%20Online-yellow.svg)
|
||||
> ![SharePoint 2016 | 2019 | Online](https://img.shields.io/badge/SharePoint-2016%20%7C%202019%20%7C%20Online-green.svg)
|
||||
> ![Works with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Compatible-green.svg)
|
||||
> ![Work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Compatible-green.svg)
|
||||
> If you know your web part only works on the hosted workbench, you can use this for the workbench compatibility tag:
|
||||
> ![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "The solution requires access to XXX")
|
||||
> ![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
>
|
||||
>
|
||||
> If you specifically built and tested this web part to work with Teams, use this for the Teams compatibility tag:
|
||||
> ![Teams Yes: Designed for Microsoft Teams](https://img.shields.io/badge/Teams-Yes-green.svg "Designed for Microsoft Teams")
|
||||
> And if you know for sure that it is NOT compatible with Teams, use this:
|
||||
@ -126,6 +128,10 @@ This Web Part illustrates the following concepts on top of the SharePoint Framew
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/issues?q=label%3AYOUR-SOLUTION-NAME) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=label%3AYOUR-SOLUTION-NAME) and see what the community is saying.
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=YOUR-SOLUTION-NAME&authors=@YOURGITHUBUSERNAME&title=YOUR-SOLUTION-NAME%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=YOUR-SOLUTION-NAME&authors=@YOURGITHUBUSERNAME&title=YOUR-SOLUTION-NAME%20-%20).
|
||||
|
@ -47,6 +47,7 @@ Solution|Author(s)
|
||||
js-modern-calendar | Jeremy Coleman (MCP, PC Professional, Inc.)
|
||||
js-modern-calendar | Nanddeep Nachan ([@NanddeepNachan](twitter.com/NanddeepNachan))
|
||||
js-modern-calendar | Ravi Chandra ([Ravikadri](https://github.com/Ravikadri))
|
||||
js-modern-calendar | Peter Paul Kirschner ([@petkir_at](https://twitter.com/petkir_at))
|
||||
|
||||
## Version history
|
||||
|
||||
@ -55,6 +56,7 @@ Version|Date|Comments
|
||||
1.0.0.0|February 11, 2017|Initial release
|
||||
1.0.0.1|June 05, 2020|Updated the external CDN references to public CDN references
|
||||
1.0.2.0|February 9, 2021|Upgraded to SPFx 1.11 and fixed issues with missing dependencies
|
||||
1.0.3.0|October 28, 2021|fixed issues with Timezones. The Browser Timezone Settings are now used
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.6.0"
|
||||
"value": "1.11.0"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
@ -45,6 +45,13 @@
|
||||
"pictureUrl": "https://github.com/nanddeepn.png",
|
||||
"name": "Nanddeep Nachan",
|
||||
"twitter": "NanddeepNachan"
|
||||
},
|
||||
{
|
||||
"gitHubAccount": "petkir",
|
||||
"company": "Cubido Business Solutions GmbH",
|
||||
"pictureUrl": "https://github.com/petkir.png",
|
||||
"name": "Peter Paul Kirschner",
|
||||
"twitter": "petkir_at"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
|
@ -2,7 +2,7 @@
|
||||
"solution": {
|
||||
"name": "SPFx Modern Calendar",
|
||||
"id": "3d593a2f-73f1-486f-9dae-555c6f6b584d",
|
||||
"version": "1.0.2.0",
|
||||
"version": "1.0.3.0",
|
||||
"includeClientSideAssets": true,
|
||||
"developer": {
|
||||
"name": "",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "modern-calendar",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"engines": {
|
||||
|
@ -390,10 +390,12 @@ export default class ModernCalendarWebPart extends BaseClientSideWebPart<IModern
|
||||
|
||||
private _renderList(items: any[]): void {
|
||||
var calItems: EventObjectInput[] = items.map((list: any) => {
|
||||
const start = list[this.properties.start];
|
||||
const end = list[this.properties.end];
|
||||
return {
|
||||
title: list[this.properties.title],
|
||||
start: list[this.properties.start],
|
||||
end: list[this.properties.end],
|
||||
start: moment.utc(start,'YYYY-MM-DD HH:mm:ss').toDate(),
|
||||
end: moment.utc(end,'YYYY-MM-DD HH:mm:ss').toDate(),
|
||||
id: list["Id"],
|
||||
detail: list[this.properties.detail],
|
||||
};
|
||||
@ -405,9 +407,9 @@ export default class ModernCalendarWebPart extends BaseClientSideWebPart<IModern
|
||||
events: calItems,
|
||||
eventClick: (_event) => {
|
||||
var eventDetail =
|
||||
moment(_event["start"]).format("MM/DD/YYYY hh:mm") +
|
||||
" - " +
|
||||
moment(_event["end"]).format("MM/DD/YYYY hh:mm") +
|
||||
moment.utc(_event["start"]).local().format('YYYY-MM-DD hh:mm A') +
|
||||
" - " +
|
||||
moment.utc(_event["end"]).local().format('YYYY-MM-DD hh:mm A') +
|
||||
"<br>" +
|
||||
_event["detail"];
|
||||
swal2.default(_event.title, eventDetail, "info");
|
||||
|
@ -31,13 +31,15 @@
|
||||
![Select list and other properties from property panel for use with the Accordion](./assets/AccordionSettings4.png)
|
||||
![Completed properties.](./assets/AccordionSettings3.png)
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.10.0](https://img.shields.io/badge/version-1.10.0-green.svg)
|
||||
![Node.js LTS v10](https://img.shields.io/badge/Node.js-LTS%20v10-green.svg)
|
||||
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
|
||||
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![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")
|
||||
![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")
|
||||
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "The solution requires access to a hosted SharePoint list")
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
@ -86,6 +88,11 @@ Please create the list as described above
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/labels/react-accordion-dynamic-section) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=label%3Areact-accordion-dynamic-section) and see what the community is saying.
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-accordion-dynamic-section&authors=@mikezimm%20@jyasir%20@AriGunawan&title=react-accordion-dynamic-section%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-accordion-dynamic-section&authors=@mikezimm%20@jyasir%20@AriGunawan&title=react-accordion-dynamic-section%20-%20).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# react-at-a-glance
|
||||
# At a glance
|
||||
|
||||
## Summary
|
||||
|
||||
@ -7,7 +7,7 @@ This sample shows a web part to show the first few sentences of an article in a
|
||||
The idea is based of the *At a glance* section of a news in the BBC news app (beta).
|
||||
|
||||
### Highlights
|
||||
- Usage of `SPHttpClient` or `PnP JS`
|
||||
- Usage of `SPHttpClient` or `PnPjs`
|
||||
- Conditional property enabling
|
||||
- Usage of regex to get the sentences from article content
|
||||
- Usage of Carousel for mobile view
|
||||
@ -31,14 +31,16 @@ The idea is based of the *At a glance* section of a news in the BBC news app (be
|
||||
|
||||
![article-content-desktop](./assets/article-content-desktop.png)
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
|
||||
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
|
||||
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
|
||||
![Workbench Hosted: Does not work with local workbench](https://img.shields.io/badge/Workbench-Hosted-yellow.svg "Does not work with local workbench")
|
||||
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![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")
|
||||
![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")
|
||||
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "The solution requires access to a news page to work")
|
||||
![Hosted Workbench Partially](https://img.shields.io/badge/Hosted%20Workbench-Partially-yellow.svg "The solution needs to run on a news page to work")
|
||||
|
||||
## Applies to
|
||||
|
||||
@ -62,17 +64,18 @@ react-at-a-glance | [Anoop Tatti](https://github.com/anoopt) ([https://linktr.ee
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|September 07, 2021|Initial release
|
||||
1.1|October 20, 2021|Minor CSS changes
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
- Clone this repository
|
||||
- Ensure that you are at the solution folder
|
||||
- in the command-line run:
|
||||
- **npm install**
|
||||
- **gulp serve**
|
||||
- `npm install`
|
||||
- `gulp serve`
|
||||
- Open a news article
|
||||
- Add `?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js` to the URL
|
||||
- Add the `At a glance` web part to the page
|
||||
- Add the **At a glance** web part to the page
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
"The idea is based of the At a glance section of a news in the BBC news app."
|
||||
],
|
||||
"creationDateTime": "2021-09-07",
|
||||
"updateDateTime": "2021-09-07",
|
||||
"updateDateTime": "2021-10-20",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
|
@ -77,6 +77,10 @@ export default class NewsGlanceWebPart extends BaseClientSideWebPart<INewsGlance
|
||||
let element: any;
|
||||
|
||||
if (this.width < 400) {
|
||||
this.sentences = this.sentences.map(sentence => {
|
||||
return sentence.length > 100 ? `${sentence.slice(0, 100)}...` : sentence;
|
||||
});
|
||||
|
||||
element = React.createElement(
|
||||
NewsGlanceSmall,
|
||||
{
|
||||
|
@ -25,13 +25,12 @@
|
||||
}
|
||||
|
||||
.leftItem {
|
||||
max-width: 150px;
|
||||
object-fit: contain;
|
||||
align-self: flex-start;
|
||||
max-width: 200px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.rightItem {
|
||||
flex: 1 1 auto;
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.articleImage {
|
||||
|
@ -8,10 +8,8 @@
|
||||
|
||||
.carouselItem {
|
||||
background-color: $ms-color-themeDark;
|
||||
// display: flex;
|
||||
min-height: 150px;
|
||||
height: 98%;
|
||||
// justify-content: center;
|
||||
}
|
||||
|
||||
.carouselDotList {
|
||||
|
@ -140,6 +140,7 @@ Version|Date|Comments
|
||||
1.0.11|May 10, 2021|Optimized page refresh using local storage
|
||||
1.0.12|June 21, 2021|Fixes overlap with Year-view and the comment section by adding a vertical scrollbar.
|
||||
1.0.13|October 2, 2021|Fix to make sure Today is always visible and highlighted.
|
||||
1.0.14|October 16, 2021|Resolve unhandled exception that happens clicking on recurrent events
|
||||
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
@ -9,7 +9,7 @@
|
||||
"This Web Part allows you to manage events in a calendar. Uses a list of existing calendars on any website. The location and name of the list and the dates of the events to be displayed are defined in the properties of the web part."
|
||||
],
|
||||
"created": "2020-12-04",
|
||||
"modified": "2021-10-02",
|
||||
"modified": "2021-10-16",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
|
@ -369,6 +369,8 @@ export default class parseRecurrentEvent {
|
||||
}
|
||||
}
|
||||
if (e.fRecurrence === "1" && e.MasterSeriesItemID !== "") {
|
||||
e.EventDate = new Date(this.parseDate(e.EventDate, e.fAllDayEvent));
|
||||
e.EndDate = new Date(this.parseDate(e.EndDate, e.fAllDayEvent));
|
||||
const ni = this.cloneObj(e);
|
||||
er.push(ni);
|
||||
}
|
||||
|
@ -96,6 +96,10 @@ Version|Date|Comments
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/issues?q=label%3Areact-directory) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=label%3Areact-directory) and see what the community is saying.
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-directory&authors=@joaojmendes%20@petkir%20@sudharsank%20@Abderahman88&title=react-directory%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-directory&authors=@joaojmendes%20@petkir%20@sudharsank%20@Abderahman88&title=react-directory%20-%20).
|
||||
|
33
samples/react-document-links-accordion/.gitignore
vendored
Normal file
33
samples/react-document-links-accordion/.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
release
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Visual Studio files
|
||||
.ntvs_analysis.dat
|
||||
.vs
|
||||
bin
|
||||
obj
|
||||
|
||||
# Resx Generated Code
|
||||
*.resx.ts
|
||||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
12
samples/react-document-links-accordion/.yo-rc.json
Normal file
12
samples/react-document-links-accordion/.yo-rc.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.12.1",
|
||||
"libraryName": "react-menu-accordion",
|
||||
"libraryId": "f7134ff1-6e97-430c-9a73-5dc4902c75e3",
|
||||
"packageManager": "npm",
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
89
samples/react-document-links-accordion/README.md
Normal file
89
samples/react-document-links-accordion/README.md
Normal file
@ -0,0 +1,89 @@
|
||||
# Documents Links Accordion
|
||||
|
||||
## Summary
|
||||
|
||||
This web part allows user create a accordion with documents links grouped by any column of document library.
|
||||
When the user clicks on the header it dynamically load documents.
|
||||
|
||||
![documentsLinksAccordion](./assets/documentsLinksAccordion.gif)
|
||||
|
||||
## Screenshots
|
||||
|
||||
![documentsLinksAccordion](./assets/documentsLinksAccordion1.png)
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
|
||||
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![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")
|
||||
![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")
|
||||
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg)
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||
* [Office 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
||||
|
||||
## Web Part Properties
|
||||
|
||||
Property |Type|Required| comments
|
||||
--------------------|----|--------|----------
|
||||
Web part Title| Text| no|
|
||||
Select Document Library| dropdown|yes
|
||||
Select Field to Group By | dropdown|yes
|
||||
|
||||
|
||||
## Solution
|
||||
|
||||
The web part Use PnPjs library, Fluent-Ui-react components
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
React Documents Links Accordion |[João Mendes](https://github.com/joaojmendes) ([@joaojmendes](https://twitter.com/joaojmendes))
|
||||
|
||||
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0|October 10, 2021|Initial release
|
||||
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
- Clone this repository
|
||||
- Move to sample folder
|
||||
- in the command line run:
|
||||
- `npm install`
|
||||
- `gulp build`
|
||||
- `gulp bundle --ship`
|
||||
- `gulp package-solution --ship`
|
||||
- Add to AppCatalog and deploy
|
||||
|
||||
|
||||
## Disclaimer
|
||||
|
||||
**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.**
|
||||
|
||||
|
||||
## Help
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/labels/react-document-links-accordion) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=label%3Areact-document-links-accordion) and see what the community is saying.
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-document-links-accordion&authors=@joaojmendes%20@Ravikadri&title=react-document-links-accordion%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-document-links-accordion&authors=@joaojmendes%20@Ravikadri&title=react-document-links-accordion%20-%20).
|
||||
|
||||
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=suggestion.yml&sample=react-document-links-accordion&authors=@joaojmendes%20@Ravikadri&title=react-document-links-accordion%20-%20).
|
||||
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-documents-links-accordion" />
|
Binary file not shown.
After Width: | Height: | Size: 3.1 MiB |
Binary file not shown.
After Width: | Height: | Size: 460 KiB |
89
samples/react-document-links-accordion/assets/sample.json
Normal file
89
samples/react-document-links-accordion/assets/sample.json
Normal file
@ -0,0 +1,89 @@
|
||||
[
|
||||
{
|
||||
"name": "pnp-sp-dev-spfx-web-parts-react-document-links-accordion",
|
||||
"source": "pnp",
|
||||
"title": "Documents Links Accordion",
|
||||
"shortDescription": "This web part allows user create a accordion with documents links grouped by any column of document library.",
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-document-links-accordion",
|
||||
"longDescription": [
|
||||
"This web part allows user create a accordion with documents links grouped by any column of document library.",
|
||||
"When the user clicks on the header it dynamically load documents."
|
||||
],
|
||||
"creationDateTime": "2021-10-10",
|
||||
"updateDateTime": "2021-10-10",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
],
|
||||
"metadata": [
|
||||
{
|
||||
"key": "CLIENT-SIDE-DEV",
|
||||
"value": "React"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.12.1"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-FULLPAGEAPP",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-TEAMSTAB",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-TEAMSPERSONALAPP",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "REACT-HOOKS",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "PNPCONTROLS",
|
||||
"value": "PropertyFieldListPicker, PropertyFieldMessage, PropertyFieldSpinner, Placeholder, AccessibleAccordion"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
{
|
||||
"type": "image",
|
||||
"order": 100,
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-document-links-accordion/assets/documentsLinksAccordion.gif",
|
||||
"alt": "Web part in action"
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"order": 101,
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/blob/main/samples/react-document-links-accordion/assets/documentsLinksAccordion1.png",
|
||||
"alt": "Screen shot of web part"
|
||||
}
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"gitHubAccount": "joaojmendes",
|
||||
"company": "Storm Technology Ltd",
|
||||
"pictureUrl": "https://github.com/joaojmendes.png",
|
||||
"name": "Jo\u00E3o Mendes",
|
||||
"twitter": "joaojmendes"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"name": "Build your first SharePoint client-side web part",
|
||||
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
|
||||
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
|
||||
},
|
||||
{
|
||||
"name": "Supporting section backgrounds",
|
||||
"description": "Starting with SharePoint Framework v1.8, web parts can be made aware of any section backgrounds and use these colors to improve the appearance of a web part when hosted in a section with a different background.",
|
||||
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/supporting-section-backgrounds"
|
||||
},
|
||||
{
|
||||
"name": "Building Microsoft Teams Tabs using SharePoint Framework",
|
||||
"description": "Starting with SharePoint Framework v1.8, you can build tabs for Microsoft Teams with the SharePoint Framework tooling and use SharePoint as a host for your solutions. As part of the SharePoint Framework v1.10 you can also publish your solution as Microsoft Teams personal app.",
|
||||
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/integrate-with-teams-introduction"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
20
samples/react-document-links-accordion/config/config.json
Normal file
20
samples/react-document-links-accordion/config/config.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"documentslinksaccordion-web-part": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/DocumentsLinksAccordion/DocumentsLinksAccordionWebPart.js",
|
||||
"manifest": "./src/webparts/DocumentsLinksAccordion/DocumentsLinksAccordionWebPart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"DocumentsLinksAccordionWebPartStrings": "lib/webparts/DocumentsLinksAccordion/loc/{locale}.js",
|
||||
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js",
|
||||
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "./release/assets/"
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./release/assets/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-menu-accordion",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "react-documentslinks-accordion",
|
||||
"id": "f7134ff1-6e97-430c-9a73-5dc4902c75e3",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"websiteUrl": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"mpnId": ""
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-documentslinks-accordion.sppkg"
|
||||
}
|
||||
}
|
10
samples/react-document-links-accordion/config/serve.json
Normal file
10
samples/react-document-links-accordion/config/serve.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
16
samples/react-document-links-accordion/gulpfile.js
vendored
Normal file
16
samples/react-document-links-accordion/gulpfile.js
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
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.initialize(require('gulp'));
|
22503
samples/react-document-links-accordion/package-lock.json
generated
Normal file
22503
samples/react-document-links-accordion/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
samples/react-document-links-accordion/package.json
Normal file
37
samples/react-document-links-accordion/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "react-documentslinks-accordion",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.12.1",
|
||||
"@microsoft/sp-lodash-subset": "1.12.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.12.1",
|
||||
"@microsoft/sp-property-pane": "1.12.1",
|
||||
"@microsoft/sp-webpart-base": "1.12.1",
|
||||
"@pnp/spfx-controls-react": "^3.3.0",
|
||||
"@pnp/spfx-property-controls": "^3.2.0",
|
||||
"@uifabric/file-type-icons": "^7.8.1",
|
||||
"date-fns": "^2.25.0",
|
||||
"office-ui-fabric-react": "7.156.0",
|
||||
"react": "16.9.0",
|
||||
"react-dom": "16.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "16.9.36",
|
||||
"@types/react-dom": "16.9.8",
|
||||
"@microsoft/sp-build-web": "1.12.1",
|
||||
"@microsoft/sp-tslint-rules": "1.12.1",
|
||||
"@microsoft/sp-module-interfaces": "1.12.1",
|
||||
"@microsoft/sp-webpart-workbench": "1.12.1",
|
||||
"@microsoft/rush-stack-compiler-3.7": "0.2.3",
|
||||
"gulp": "~4.0.2",
|
||||
"ajv": "~5.2.2",
|
||||
"@types/webpack-env": "1.13.1"
|
||||
}
|
||||
}
|
160
samples/react-document-links-accordion/src/Utils/Utils.ts
Normal file
160
samples/react-document-links-accordion/src/Utils/Utils.ts
Normal file
@ -0,0 +1,160 @@
|
||||
import { SPComponentLoader } from "@microsoft/sp-loader";
|
||||
import { sp } from "@pnp/sp";
|
||||
import "@pnp/sp/webs";
|
||||
import "@pnp/sp/regional-settings/web";
|
||||
import { IRegionalSettingsInfo } from "@pnp/sp/regional-settings";
|
||||
|
||||
// get all the web's regional settings
|
||||
|
||||
const DEFAULT_PERSONA_IMG_HASH: string = "7ad602295f8386b7615b582d87bcc294";
|
||||
const DEFAULT_IMAGE_PLACEHOLDER_HASH: string = "4a48f26592f4e1498d7a478a4c48609c";
|
||||
const MD5_MODULE_ID: string = "8494e7d7-6b99-47b2-a741-59873e42f16f";
|
||||
const PROFILE_IMAGE_URL: string = "/_layouts/15/userphoto.aspx?size=M&accountname=";
|
||||
|
||||
/**
|
||||
* Gets user photo
|
||||
* @param userId
|
||||
* @returns user photo
|
||||
*/
|
||||
export const getUserPhoto = async (userId): Promise<string> => {
|
||||
const personaImgUrl = PROFILE_IMAGE_URL + userId;
|
||||
console.log(personaImgUrl);
|
||||
// tslint:disable-next-line: no-use-before-declare
|
||||
const url: string = await getImageBase64(personaImgUrl);
|
||||
// tslint:disable-next-line: no-use-before-declare
|
||||
const newHash = await getMd5HashForUrl(url);
|
||||
|
||||
if (newHash !== DEFAULT_PERSONA_IMG_HASH && newHash !== DEFAULT_IMAGE_PLACEHOLDER_HASH) {
|
||||
return "data:image/png;base64," + url;
|
||||
} else {
|
||||
return "undefined";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get MD5Hash for the image url to verify whether user has default image or custom image
|
||||
* @param url
|
||||
*/
|
||||
export const getMd5HashForUrl = async (url: string) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
// tslint:disable-next-line: no-use-before-declare
|
||||
const library: any = await loadSPComponentById(MD5_MODULE_ID);
|
||||
try {
|
||||
const md5Hash = library.Md5Hash;
|
||||
if (md5Hash) {
|
||||
const convertedHash = md5Hash(url);
|
||||
resolve(convertedHash);
|
||||
}
|
||||
} catch (error) {
|
||||
resolve(url);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Load SPFx component by id, SPComponentLoader is used to load the SPFx components
|
||||
* @param componentId - componentId, guid of the component library
|
||||
*/
|
||||
export const loadSPComponentById = async (componentId: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
SPComponentLoader.loadComponentById(componentId)
|
||||
.then((component: any) => {
|
||||
resolve(component);
|
||||
})
|
||||
.catch((error) => {});
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Gets image base64
|
||||
* @param pictureUrl
|
||||
* @returns image base64
|
||||
*/
|
||||
export const getImageBase64 = async (pictureUrl: string): Promise<string> => {
|
||||
console.log(pictureUrl);
|
||||
return new Promise((resolve, reject) => {
|
||||
let image = new Image();
|
||||
image.addEventListener("load", () => {
|
||||
let tempCanvas = document.createElement("canvas");
|
||||
(tempCanvas.width = image.width),
|
||||
(tempCanvas.height = image.height),
|
||||
tempCanvas.getContext("2d").drawImage(image, 0, 0);
|
||||
let base64Str;
|
||||
try {
|
||||
base64Str = tempCanvas.toDataURL("image/png");
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
base64Str = base64Str.replace(/^data:image\/png;base64,/, "");
|
||||
resolve(base64Str);
|
||||
});
|
||||
image.src = pictureUrl;
|
||||
});
|
||||
};
|
||||
|
||||
export const zeroPad = (num, places) => {
|
||||
var zero = places - num.toString().length + 1;
|
||||
return Array(+(zero > 0 && zero)).join("0") + num;
|
||||
};
|
||||
|
||||
export const getSiteRegionalSettings = async (): Promise<IRegionalSettingsInfo> => {
|
||||
try {
|
||||
const s = await sp.web.regionalSettings();
|
||||
return s;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const convertTimeTo12H = (
|
||||
_hour: number
|
||||
): Promise<{ hourInTimeFormat: string; current12HTimeFormat: string }> => {
|
||||
console.log("prm", _hour);
|
||||
return new Promise((resolve, rejected) => {
|
||||
let hourInTimeFormat: string = "";
|
||||
let current12HTimeFormat: string = "AM";
|
||||
if (_hour >= 0 && _hour <= 11) {
|
||||
if (_hour === 0) {
|
||||
hourInTimeFormat = "12";
|
||||
} else {
|
||||
hourInTimeFormat = _hour.toString();
|
||||
}
|
||||
current12HTimeFormat = "AM";
|
||||
} else {
|
||||
const _hour12h = _hour - 12;
|
||||
hourInTimeFormat = _hour12h === 0 ? "12" : _hour12h.toString();
|
||||
current12HTimeFormat = "PM";
|
||||
}
|
||||
resolve({ hourInTimeFormat, current12HTimeFormat });
|
||||
});
|
||||
};
|
||||
|
||||
export const convertTimeTo24h = (hour: number, current12HTimeFormat: string): Promise<string> => {
|
||||
return new Promise((resolve, rejected) => {
|
||||
let hourInTimeFormat: string = "";
|
||||
if (current12HTimeFormat === "PM") {
|
||||
if (hour >= 1 && hour <= 11) {
|
||||
if (hour === 12) {
|
||||
hourInTimeFormat = "12";
|
||||
}
|
||||
const _hour24h = hour + 12;
|
||||
hourInTimeFormat = _hour24h.toString();
|
||||
}
|
||||
} else {
|
||||
if (hour === 12) {
|
||||
hourInTimeFormat = "00";
|
||||
} else {
|
||||
hourInTimeFormat = hour.toString();
|
||||
}
|
||||
}
|
||||
resolve(hourInTimeFormat);
|
||||
});
|
||||
};
|
||||
|
||||
/* Check if string is valid date */
|
||||
export const checkIfValidDate = (str:string):boolean => {
|
||||
// Regular expression to check if string is valid date
|
||||
const regexExp = /(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})/gi;
|
||||
|
||||
return regexExp.test(str);
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
|
||||
import * as React from "react";
|
||||
import { WebPartContext } from "@microsoft/sp-webpart-base";
|
||||
import { MSGraphClient, AadTokenProvider } from "@microsoft/sp-http";
|
||||
import { IReadonlyTheme } from '@microsoft/sp-component-base';
|
||||
import { IRegionalSettingsInfo} from "@pnp/sp/regional-settings";
|
||||
|
||||
|
||||
export interface IAppContextProps {
|
||||
currentUser:string;
|
||||
msGraphClient:MSGraphClient;
|
||||
locale:string;
|
||||
themeVariant: IReadonlyTheme | undefined;
|
||||
}
|
||||
|
||||
export const AppContext = React.createContext<IAppContextProps>(undefined);
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"themePrimary": "#6264a7",
|
||||
"themeLighterAlt": "#f7f7fb",
|
||||
"themeLighter": "#e1e1f1",
|
||||
"themeLight": "#c8c9e4",
|
||||
"themeTertiary": "#989ac9",
|
||||
"themeSecondary": "#7173b0",
|
||||
"themeDarkAlt": "#585a95",
|
||||
"themeDark": "#4a4c7e",
|
||||
"themeDarker": "#37385d",
|
||||
"neutralLighterAlt": "#0b0b0b",
|
||||
"neutralLighter": "#151515",
|
||||
"neutralLight": "#252525",
|
||||
"neutralQuaternaryAlt": "#2f2f2f",
|
||||
"neutralQuaternary": "#373737",
|
||||
"neutralTertiaryAlt": "#595959",
|
||||
"neutralTertiary": "#c8c8c8",
|
||||
"neutralSecondary": "#d0d0d0",
|
||||
"neutralPrimaryAlt": "#dadada",
|
||||
"neutralPrimary": "#ffffff",
|
||||
"neutralDark": "#f4f4f4",
|
||||
"black": "#f8f8f8",
|
||||
"white": "#000000"
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"themePrimary": "#6264a7",
|
||||
"themeLighterAlt": "#f7f7fb",
|
||||
"themeLighter": "#e1e1f1",
|
||||
"themeLight": "#c8c9e4",
|
||||
"themeTertiary": "#989ac9",
|
||||
"themeSecondary": "#7173b0",
|
||||
"themeDarkAlt": "#585a95",
|
||||
"themeDark": "#4a4c7e",
|
||||
"themeDarker": "#37385d",
|
||||
"neutralLighterAlt": "#2d2c2c",
|
||||
"neutralLighter": "#2c2b2b",
|
||||
"neutralLight": "#2a2929",
|
||||
"neutralQuaternaryAlt": "#272626",
|
||||
"neutralQuaternary": "#252525",
|
||||
"neutralTertiaryAlt": "#242323",
|
||||
"neutralTertiary": "#c8c8c8",
|
||||
"neutralSecondary": "#d0d0d0",
|
||||
"neutralPrimaryAlt": "#dadada",
|
||||
"neutralPrimary": "#ffffff",
|
||||
"neutralDark": "#f4f4f4",
|
||||
"black": "#f8f8f8",
|
||||
"white": "#2d2c2c"
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"themePrimary": "#6264a7",
|
||||
"themeLighterAlt": "#f7f7fb",
|
||||
"themeLighter": "#e1e1f1",
|
||||
"themeLight": "#c8c9e4",
|
||||
"themeTertiary": "#989ac9",
|
||||
"themeSecondary": "#7173b0",
|
||||
"themeDarkAlt": "#585a95",
|
||||
"themeDark": "#4a4c7e",
|
||||
"themeDarker": "#37385d",
|
||||
"neutralLighterAlt": "#ecebe9",
|
||||
"neutralLighter": "#e8e7e6",
|
||||
"neutralLight": "#dedddc",
|
||||
"neutralQuaternaryAlt": "#cfcecd",
|
||||
"neutralQuaternary": "#c6c5c4",
|
||||
"neutralTertiaryAlt": "#bebdbc",
|
||||
"neutralTertiary": "#b5b4b2",
|
||||
"neutralSecondary": "#9d9c9a",
|
||||
"neutralPrimaryAlt": "#868482",
|
||||
"neutralPrimary": "#252423",
|
||||
"neutralDark": "#565453",
|
||||
"black": "#3e3d3b",
|
||||
"white": "#f3f2f1"
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
import { IDatePickerStrings } from 'office-ui-fabric-react/lib/DatePicker';
|
||||
export const DayPickerStrings: IDatePickerStrings = {
|
||||
months: [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
],
|
||||
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
||||
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
||||
shortDays: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
|
||||
goToToday: 'Go to today',
|
||||
prevMonthAriaLabel: 'Go to previous month',
|
||||
nextMonthAriaLabel: 'Go to next month',
|
||||
prevYearAriaLabel: 'Go to previous year',
|
||||
nextYearAriaLabel: 'Go to next year',
|
||||
closeButtonAriaLabel: 'Close date picker',
|
||||
monthPickerHeaderAriaLabel: '{0}, select to change the year',
|
||||
yearPickerHeaderAriaLabel: '{0}, select to change the month',
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
$default-background: #f3f2f1;
|
||||
$default-color: #252423;
|
||||
$default-button-background: #6264a7;
|
||||
$default-Button-color: #f3f2f1;
|
||||
|
||||
// dark theme
|
||||
$dark-background: #2d2c2c;
|
||||
$dark-color: #ffffff;
|
||||
$dark-button-background: #6264a7;
|
||||
$dark-button-color: #2d2c2c;
|
||||
|
||||
// contrast theme
|
||||
$contrast-background: #000000;
|
||||
$contrast-color: #ffffff;
|
||||
$contrast-button-background: #b5c01c;
|
||||
$contrast-Button-color: #000000;
|
@ -0,0 +1,74 @@
|
||||
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||
|
||||
.DocumentsLinksAccordion {
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: 0px auto;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.row {
|
||||
@include ms-Grid-row;
|
||||
@include ms-fontColor-white;
|
||||
background-color: $ms-color-themeDark;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.column {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg10;
|
||||
@include ms-xl8;
|
||||
@include ms-xlPush2;
|
||||
@include ms-lgPush1;
|
||||
}
|
||||
|
||||
.title {
|
||||
@include ms-font-xl;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.description {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.button {
|
||||
// Our button
|
||||
text-decoration: none;
|
||||
height: 32px;
|
||||
|
||||
// Primary Button
|
||||
min-width: 80px;
|
||||
background-color: $ms-color-themePrimary;
|
||||
border-color: $ms-color-themePrimary;
|
||||
color: $ms-color-white;
|
||||
|
||||
// Basic Button
|
||||
outline: transparent;
|
||||
position: relative;
|
||||
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: $ms-font-size-m;
|
||||
font-weight: $ms-font-weight-regular;
|
||||
border-width: 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 0 16px;
|
||||
|
||||
.label {
|
||||
font-weight: $ms-font-weight-semibold;
|
||||
font-size: $ms-font-size-m;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 0 4px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,356 @@
|
||||
import * as React from "react";
|
||||
import * as strings from "DocumentsLinksAccordionWebPartStrings";
|
||||
import { filter, findIndex, uniqBy } from "lodash";
|
||||
import {
|
||||
Customizer,
|
||||
INavLink,
|
||||
INavLinkGroup,
|
||||
Label,
|
||||
Link,
|
||||
mergeStyleSets,
|
||||
MessageBar,
|
||||
MessageBarType,
|
||||
Spinner,
|
||||
SpinnerSize,
|
||||
Stack,
|
||||
FontIcon,
|
||||
Text,
|
||||
DetailsList,
|
||||
DetailsListLayoutMode,
|
||||
IColumn,
|
||||
SelectionMode,
|
||||
IDetailsListProps,
|
||||
IStackStyles,
|
||||
IStyle,
|
||||
IDetailsListStyles,
|
||||
} from "office-ui-fabric-react";
|
||||
|
||||
import { getFileTypeIconProps } from "@uifabric/file-type-icons";
|
||||
import { useList } from "../../hooks/useList";
|
||||
import { IDocumentsLinksAccordionState } from "./IDocumentsLinksAccordionState";
|
||||
import { IDocumentsLinksAccordionProps } from "./IDocumentsLinksAccordionProps";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
AccordionItemHeading,
|
||||
AccordionItemButton,
|
||||
AccordionItemPanel,
|
||||
} from "@pnp/spfx-controls-react/lib/AccessibleAccordion";
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
|
||||
const { getGroupItems, getGroupHeaders, getField } = useList();
|
||||
export const DocumentsLinksAccordion: React.FunctionComponent<IDocumentsLinksAccordionProps> = (
|
||||
props: IDocumentsLinksAccordionProps
|
||||
) => {
|
||||
const [state, setState] = React.useState<IDocumentsLinksAccordionState>({
|
||||
navLinkGroups: [],
|
||||
isLoading: false,
|
||||
hasError: false,
|
||||
errorMessage: "",
|
||||
listName: "",
|
||||
});
|
||||
|
||||
const stackItemStyles: Partial<IStackStyles> = React.useMemo(() => {
|
||||
return {
|
||||
root: {
|
||||
padding: 7,
|
||||
} as IStyle,
|
||||
};
|
||||
}, []);
|
||||
|
||||
const listViewStyles: Partial<IDetailsListStyles> = React.useMemo(() => {
|
||||
return {
|
||||
focusZone: {
|
||||
width: "auto",
|
||||
maxHeight: 450,
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden",
|
||||
"&::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: props.themeVariant?.palette?.neutralLighter,
|
||||
},
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "7.5px",
|
||||
},
|
||||
"scrollbar-color": props.themeVariant?.palette?.neutralLighter,
|
||||
"scrollbar-width": "thin",
|
||||
},
|
||||
root: {
|
||||
"&::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: props.themeVariant?.palette?.neutralLighter,
|
||||
},
|
||||
"&::-webkit-scrollbar": {
|
||||
height: "7.5px",
|
||||
},
|
||||
"scrollbar-color": props.themeVariant?.palette?.neutralLighter,
|
||||
"scrollbar-width": "thin",
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
|
||||
const classComponent = React.useMemo(() => {
|
||||
return mergeStyleSets({
|
||||
webPartTitle: {
|
||||
fontWeight: 600,
|
||||
overflowX: "hidden",
|
||||
textOverflow: "Ellipsis",
|
||||
fontSize: props.themeVariant.fonts.large.fontSize,
|
||||
marginBottom: 10,
|
||||
},
|
||||
});
|
||||
}, [props.themeVariant]);
|
||||
|
||||
const stateRef = React.useRef(state); // Use to access state on eventListenners
|
||||
|
||||
const columns: IColumn[] = React.useMemo(() => {
|
||||
return [
|
||||
{
|
||||
key: "documentRenderLink",
|
||||
name: "Document",
|
||||
fieldName: "name",
|
||||
minWidth: 400,
|
||||
maxWidth: 800,
|
||||
isResizable: false,
|
||||
data: "string",
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
|
||||
const onRenderRow: IDetailsListProps["onRenderRow"] = (propsItem) => {
|
||||
if (propsItem.item) {
|
||||
const item = propsItem.item as INavLink;
|
||||
return (
|
||||
<Stack horizontal horizontalAlign="start" tokens={{ childrenGap: 10 }} styles={stackItemStyles}>
|
||||
<FontIcon iconName={item.iconProps.iconName} />
|
||||
<Link href={item.url} target="_blank">
|
||||
<Text variant={"medium"}>{item.name}</Text>
|
||||
</Link>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
if (!props.listId || !props.fieldName) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let _navLinksGroups: INavLinkGroup[] = [];
|
||||
stateRef.current = {
|
||||
...stateRef.current,
|
||||
isLoading: true,
|
||||
navLinkGroups: _navLinksGroups,
|
||||
};
|
||||
setState(stateRef.current);
|
||||
const _groupHeaders = await getGroupHeaders(props.listId, props.fieldName, props.listBaseTemplate);
|
||||
const { fieldName } = props;
|
||||
const _field: any = await getField(props.listId, props.fieldName);
|
||||
|
||||
for (const groupHeader of _groupHeaders) {
|
||||
let _name: any;
|
||||
switch (_field.fieldType) {
|
||||
case "TaxonomyFieldType":
|
||||
_name = groupHeader[fieldName]?.Label ?? "Unassigned";
|
||||
break;
|
||||
case "TaxonomyFieldTypeMulti":
|
||||
_name = groupHeader[fieldName][0]?.Label ?? "Unassigned";
|
||||
break;
|
||||
case "User":
|
||||
if (_name != "Unassigned") {
|
||||
_name = groupHeader[fieldName][0]?.title;
|
||||
}
|
||||
break;
|
||||
case "Lookup":
|
||||
_name =
|
||||
groupHeader[props.fieldName] !== "" &&
|
||||
groupHeader[props.fieldName] !== undefined &&
|
||||
groupHeader[props.fieldName][0].lookupValue !== ""
|
||||
? groupHeader[props.fieldName][0]?.lookupValue
|
||||
: "Unassigned";
|
||||
break;
|
||||
default:
|
||||
_name =
|
||||
groupHeader[props.fieldName] !== "" && groupHeader[props.fieldName] !== undefined
|
||||
? groupHeader[props.fieldName]
|
||||
: "Unassigned";
|
||||
break;
|
||||
}
|
||||
_navLinksGroups.push({
|
||||
name: _name,
|
||||
groupData: _name,
|
||||
collapseByDefault: true,
|
||||
links: [],
|
||||
});
|
||||
// Ensure the groups name are unique!
|
||||
_navLinksGroups = uniqBy(_navLinksGroups, "name");
|
||||
}
|
||||
stateRef.current = {
|
||||
...stateRef.current,
|
||||
hasError: false,
|
||||
errorMessage: "",
|
||||
isLoading: false,
|
||||
listName: _field.fieldScope,
|
||||
navLinkGroups: _navLinksGroups,
|
||||
};
|
||||
|
||||
setState(stateRef.current);
|
||||
} catch (error) {
|
||||
stateRef.current = {
|
||||
...stateRef.current,
|
||||
hasError: true,
|
||||
errorMessage: error.message,
|
||||
};
|
||||
setState(stateRef.current);
|
||||
}
|
||||
})();
|
||||
}, [props.listId, props.fieldName]);
|
||||
|
||||
// On Header click get Items for the header
|
||||
const onGroupHeaderClick = React.useCallback(
|
||||
async (ev: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||
try {
|
||||
const _groupName = ev.currentTarget.innerText;
|
||||
const { navLinkGroups } = stateRef.current;
|
||||
|
||||
setState(stateRef.current);
|
||||
const _navGroup = filter(navLinkGroups, { name: _groupName });
|
||||
if (_navGroup?.length && _navGroup[0]?.links?.length === 0) {
|
||||
const _navlinks: INavLink[] = [];
|
||||
const _groupHeaderItems: any[] = await getGroupItems(
|
||||
props.listId,
|
||||
props.fieldName,
|
||||
_groupName,
|
||||
props.listBaseTemplate
|
||||
);
|
||||
if (_groupHeaderItems?.length) {
|
||||
for (const _groupHeaderItem of _groupHeaderItems) {
|
||||
if (props.listBaseTemplate === 0) {
|
||||
// List
|
||||
_navlinks.push({
|
||||
name: _groupHeaderItem.Title,
|
||||
url: `${_groupHeaderItem.FileDirRef}/dispform.aspx?ID=${_groupHeaderItem.Id}`,
|
||||
iconProps: {
|
||||
iconName: "TaskManager",
|
||||
},
|
||||
key: _groupHeaderItem.Id,
|
||||
target: "_blank",
|
||||
isExpanded: false,
|
||||
});
|
||||
}
|
||||
if (props.listBaseTemplate === 1) {
|
||||
// Document Library
|
||||
_navlinks.push({
|
||||
name: _groupHeaderItem.FileLeafRef,
|
||||
url: _groupHeaderItem.FileRef,
|
||||
iconProps: {
|
||||
...getFileTypeIconProps({
|
||||
extension: _groupHeaderItem.DocIcon,
|
||||
size: 16,
|
||||
imageFileType: "svg",
|
||||
}),
|
||||
},
|
||||
key: _groupHeaderItem.title,
|
||||
target: "_blank",
|
||||
isExpanded: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update Navigation with Items of Group
|
||||
|
||||
_navGroup[0].links = _navlinks;
|
||||
}
|
||||
const _index = findIndex(navLinkGroups, { name: _groupName });
|
||||
_navGroup[0].collapseByDefault = true;
|
||||
navLinkGroups[_index] = _navGroup[0];
|
||||
|
||||
stateRef.current = { ...stateRef.current, navLinkGroups: navLinkGroups };
|
||||
setState(stateRef.current);
|
||||
} catch (error) {}
|
||||
},
|
||||
[props]
|
||||
);
|
||||
|
||||
// Show Error if Exists
|
||||
if (state.hasError) {
|
||||
return (
|
||||
<>
|
||||
<MessageBar messageBarType={MessageBarType.error} isMultiline>
|
||||
{state.errorMessage}
|
||||
</MessageBar>
|
||||
</>
|
||||
);
|
||||
}
|
||||
// render component
|
||||
if (!props.listId || !props.fieldName) {
|
||||
return (
|
||||
<Placeholder
|
||||
iconName="Edit"
|
||||
iconText={strings.PlaceHolderIconText}
|
||||
description={strings.PlaceHolderDescription}
|
||||
buttonLabel={strings.PlaceHolderButtonLable}
|
||||
onConfigure={props.onConfigure}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Customizer settings={{ theme: props.themeVariant }}>
|
||||
{state.isLoading ? (
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Spinner size={SpinnerSize.medium}></Spinner>
|
||||
</Stack>
|
||||
) : (
|
||||
<>
|
||||
<Stack horizontalAlign="space-between" horizontal tokens={{ childrenGap: 10 }} style={{ width: "100%" }}>
|
||||
<div className={classComponent.webPartTitle}>{props.title}</div>
|
||||
<Link href={state.listName}>{strings.ViewAllLabel}</Link>
|
||||
</Stack>
|
||||
{state.navLinkGroups?.length === 0 ? (
|
||||
<Label
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontSize: props.themeVariant.fonts.small.fontSize,
|
||||
}}
|
||||
>
|
||||
{strings.NodocumentsLabel}
|
||||
</Label>
|
||||
) : (
|
||||
<Accordion allowZeroExpanded allowMultipleExpanded>
|
||||
{state.navLinkGroups.map((item, i) => {
|
||||
return (
|
||||
<AccordionItem>
|
||||
<AccordionItemHeading
|
||||
onClick={async (ev) => {
|
||||
await onGroupHeaderClick(ev);
|
||||
}}
|
||||
>
|
||||
<AccordionItemButton>{item.name}</AccordionItemButton>
|
||||
</AccordionItemHeading>
|
||||
<AccordionItemPanel>
|
||||
<Stack>
|
||||
<DetailsList
|
||||
items={item.links}
|
||||
columns={columns}
|
||||
styles={listViewStyles}
|
||||
compact={true}
|
||||
selectionMode={SelectionMode.none}
|
||||
setKey="none"
|
||||
layoutMode={DetailsListLayoutMode.justified}
|
||||
isHeaderVisible={false}
|
||||
onRenderRow={onRenderRow}
|
||||
/>
|
||||
</Stack>
|
||||
</AccordionItemPanel>
|
||||
</AccordionItem>
|
||||
);
|
||||
})}
|
||||
</Accordion>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Customizer>
|
||||
</>
|
||||
);
|
||||
};
|
@ -0,0 +1,14 @@
|
||||
|
||||
import { IReadonlyTheme } from "@microsoft/sp-component-base";
|
||||
import { DisplayMode } from "@microsoft/sp-core-library";
|
||||
|
||||
export interface IDocumentsLinksAccordionProps {
|
||||
title: string;
|
||||
listId:string;
|
||||
listBaseTemplate:number;
|
||||
fieldName:string;
|
||||
locale:string;
|
||||
themeVariant: IReadonlyTheme | undefined;
|
||||
onConfigure: () => void;
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { Nav, INavStyles, INavLinkGroup } from 'office-ui-fabric-react/lib/Nav';
|
||||
export interface IDocumentsLinksAccordionState {
|
||||
navLinkGroups: INavLinkGroup[];
|
||||
isLoading: boolean;
|
||||
hasError:boolean;
|
||||
errorMessage:string;
|
||||
listName:string;
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
export interface IListItemsMenu {
|
||||
groupBy:string;
|
||||
id:string;
|
||||
title:string;
|
||||
url:string;
|
||||
}
|
137
samples/react-document-links-accordion/src/hooks/useList.ts
Normal file
137
samples/react-document-links-accordion/src/hooks/useList.ts
Normal file
@ -0,0 +1,137 @@
|
||||
import "@pnp/sp/fields";
|
||||
import "@pnp/sp/items";
|
||||
import "@pnp/sp/lists";
|
||||
import "@pnp/sp/webs";
|
||||
|
||||
import { sortBy, uniqBy } from "lodash";
|
||||
|
||||
import { sp } from "@pnp/sp";
|
||||
import { IFieldInfo } from "@pnp/sp/fields";
|
||||
import { IListInfo } from "@pnp/sp/lists";
|
||||
import * as moment from "moment";
|
||||
import { format, parse, parseISO } from "date-fns";
|
||||
import { checkIfValidDate } from "../Utils/Utils";
|
||||
|
||||
export const useList = () => {
|
||||
// Run on useList hook
|
||||
(async () => {})();
|
||||
|
||||
// Get List Columns
|
||||
const getListColumns = async (listId: string): Promise<IFieldInfo[]> => {
|
||||
const _listColumnsResults: IFieldInfo[] = await sp.web.lists.getById(listId).fields.filter("Hidden eq false").get();
|
||||
|
||||
const _wColumns: IFieldInfo[] = uniqBy(sortBy(_listColumnsResults, "Title"), "Title");
|
||||
return _wColumns;
|
||||
};
|
||||
|
||||
const getField = async (listId: string, field: string): Promise<any> => {
|
||||
const _field: IFieldInfo = await sp.web.lists.getById(listId).fields.getByInternalNameOrTitle(field).get();
|
||||
|
||||
const fieldType = _field.TypeAsString;
|
||||
const fieldScope = _field.Scope;
|
||||
return { fieldType, fieldScope };
|
||||
};
|
||||
|
||||
const getGroupHeaders = async (listId: string, groupByField: string, baseTemplate: number): Promise<any[]> => {
|
||||
let _viewXml = `<View Scope='Recursive'>
|
||||
<Query>
|
||||
<GroupBy Collapse="TRUE">
|
||||
<FieldRef Name="${groupByField}"/>
|
||||
</GroupBy>
|
||||
</Query>
|
||||
<RowLimit>1000</RowLimit>
|
||||
</View>`;
|
||||
|
||||
const _groupHeadersResults = await sp.web.lists.getById(listId).renderListDataAsStream({ ViewXml: _viewXml });
|
||||
return uniqBy(_groupHeadersResults.Row, groupByField);
|
||||
};
|
||||
|
||||
const getGroupItems = async (
|
||||
listId: string,
|
||||
groupByField: string,
|
||||
groupFieldValue: string,
|
||||
baseTemplate: number
|
||||
): Promise<any[]> => {
|
||||
const _field: any = await getField(listId, groupByField);
|
||||
|
||||
if (checkIfValidDate(groupFieldValue)) {
|
||||
groupFieldValue = format(new Date(groupFieldValue), "yyyy-MM-dd");
|
||||
}
|
||||
|
||||
switch (_field.fieldType) {
|
||||
case "DateTime":
|
||||
groupFieldValue =
|
||||
groupFieldValue != "Unassigned" ? format(parseISO(groupFieldValue), "yyyy-MM-dd") : "Unassigned";
|
||||
break;
|
||||
case "AllDayEvent":
|
||||
groupFieldValue = groupFieldValue === "No" ? "0" : "1";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
let _viewXml = `<View Scope='Recursive'>
|
||||
<Query>
|
||||
<OrderBy>
|
||||
<FieldRef Name="${groupByField}" Ascending="FALSE"></FieldRef>
|
||||
</OrderBy>
|
||||
</Query>
|
||||
</View>`;
|
||||
|
||||
if (groupFieldValue != "Unassigned") {
|
||||
_viewXml = `<View Scope='Recursive'>
|
||||
<Query>
|
||||
<OrderBy>
|
||||
<FieldRef Name="${groupByField}" Ascending="FALSE"></FieldRef>
|
||||
</OrderBy>
|
||||
<Where>
|
||||
<Eq>
|
||||
<FieldRef Name="${groupByField}"></FieldRef>
|
||||
<Value Type="${_field.fieldType}" IncludeTimeValue="FALSE">${groupFieldValue}</Value>
|
||||
</Eq>
|
||||
</Where>
|
||||
</Query>
|
||||
</View>`;
|
||||
}
|
||||
|
||||
if (groupFieldValue === "Unassigned") {
|
||||
_viewXml = `<View Scope='Recursive'>
|
||||
<Query>
|
||||
<OrderBy>
|
||||
<FieldRef Name="${groupByField}" Ascending="FALSE"></FieldRef>
|
||||
</OrderBy>
|
||||
<Where>
|
||||
<IsNull>
|
||||
<FieldRef Name="${groupByField}"></FieldRef>
|
||||
</IsNull>
|
||||
</Where>
|
||||
</Query>
|
||||
</View>`;
|
||||
}
|
||||
|
||||
const _groupItemsResults = await sp.web.lists.getById(listId).renderListDataAsStream({ ViewXml: _viewXml });
|
||||
|
||||
return _groupItemsResults.Row;
|
||||
};
|
||||
|
||||
// Get Lists
|
||||
const getLists = async (baseTemplate: number): Promise<IListInfo[]> => {
|
||||
let _filter: string = "Hidden eq false and ";
|
||||
if (baseTemplate === 0) {
|
||||
_filter = _filter + " BaseType ne 1";
|
||||
} else {
|
||||
_filter = _filter + " BaseType eq 1";
|
||||
}
|
||||
const _lists: IListInfo[] = await sp.web.lists.filter(_filter).get();
|
||||
return _lists;
|
||||
};
|
||||
|
||||
// Return functions
|
||||
return {
|
||||
getListColumns,
|
||||
getLists,
|
||||
getGroupItems,
|
||||
getGroupHeaders,
|
||||
getField,
|
||||
};
|
||||
};
|
1
samples/react-document-links-accordion/src/index.ts
Normal file
1
samples/react-document-links-accordion/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "a0215264-a8cd-4952-aecd-4e80719de202",
|
||||
"alias": "DocumentsLinksAccordionWebPart",
|
||||
"componentType": "WebPart",
|
||||
"supportsFullBleed": true,
|
||||
// The "*" signifies that the version should be taken from the package.json
|
||||
"version": "*",
|
||||
"manifestVersion": 2,
|
||||
|
||||
// If true, the component can only be installed on sites where Custom Script is allowed.
|
||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": ["SharePointWebPart", "SharePointFullPage", "TeamsPersonalApp","TeamsTab"],
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
|
||||
"group": { "default": "SPFx Custom Web Parts" },
|
||||
"title": { "default": "Documents Links Accordion" },
|
||||
"description": { "default": "Documents" },
|
||||
"officeFabricIconFontName": "GroupedList",
|
||||
"properties": {
|
||||
"title": "Documents",
|
||||
"listId": "",
|
||||
"fieldName": "",
|
||||
"listBasetemplate": 1
|
||||
}
|
||||
}]
|
||||
}
|
@ -0,0 +1,302 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDom from "react-dom";
|
||||
|
||||
import {
|
||||
loadTheme,
|
||||
MessageBarType,
|
||||
SpinnerSize
|
||||
} from "office-ui-fabric-react";
|
||||
|
||||
import {
|
||||
IReadonlyTheme,
|
||||
ThemeChangedEventArgs,
|
||||
ThemeProvider
|
||||
} from "@microsoft/sp-component-base";
|
||||
import { MSGraphClient } from "@microsoft/sp-http";
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
IPropertyPaneDropdownOption,
|
||||
IPropertyPaneField,
|
||||
IPropertyPaneGroup,
|
||||
IPropertyPanePage,
|
||||
PropertyPaneDropdown,
|
||||
PropertyPaneTextField
|
||||
} from "@microsoft/sp-property-pane";
|
||||
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
|
||||
import { sp } from "@pnp/sp";
|
||||
import {
|
||||
PropertyFieldListPicker,
|
||||
PropertyFieldListPickerOrderBy
|
||||
} from "@pnp/spfx-property-controls/lib/PropertyFieldListPicker";
|
||||
import {
|
||||
PropertyFieldMessage
|
||||
} from "@pnp/spfx-property-controls/lib/PropertyFieldMessage";
|
||||
import {
|
||||
PropertyFieldSpinner
|
||||
} from "@pnp/spfx-property-controls/lib/PropertyFieldSpinner";
|
||||
|
||||
|
||||
import { useList } from "../../hooks/useList";
|
||||
|
||||
export interface IListItemsMenuWebPartProps {
|
||||
title: string;
|
||||
listId: string;
|
||||
fieldName: string;
|
||||
listBasetemplate: number;
|
||||
}
|
||||
|
||||
const teamsDefaultTheme = require("../../common/TeamsDefaultTheme.json");
|
||||
const teamsDarkTheme = require("../../common/TeamsDarkTheme.json");
|
||||
const teamsContrastTheme = require("../../common/TeamsContrastTheme.json");
|
||||
|
||||
const { getListColumns, getLists } = useList() ;
|
||||
|
||||
import * as strings from 'DocumentsLinksAccordionWebPartStrings';
|
||||
import { IDocumentsLinksAccordionProps } from "../../components/DocumentsLinksAccordion/IDocumentsLinksAccordionProps";
|
||||
import {DocumentsLinksAccordion} from "../../components/DocumentsLinksAccordion/DocumentsLinksAccordion";
|
||||
import { Version } from "@microsoft/sp-core-library";
|
||||
export interface IDocumentsLinksAccordionWebPartProps {
|
||||
title: string;
|
||||
listId: string;
|
||||
fieldName: string;
|
||||
listBasetemplate: number;
|
||||
}
|
||||
|
||||
export default class DocumentsLinksAccordionWebPart extends BaseClientSideWebPart<IDocumentsLinksAccordionWebPartProps> {
|
||||
|
||||
private columns: IPropertyPaneDropdownOption[] = [];
|
||||
private lists: IPropertyPaneDropdownOption[] = [];
|
||||
private _themeProvider: ThemeProvider;
|
||||
private _themeVariant: IReadonlyTheme | undefined;
|
||||
private _msgGraphclient: MSGraphClient;
|
||||
private _hasError: boolean = false;
|
||||
private _messageError: string = undefined;
|
||||
|
||||
|
||||
protected async onInit(): Promise<void> {
|
||||
|
||||
sp.setup({
|
||||
spfxContext: this.context,
|
||||
});
|
||||
|
||||
this._msgGraphclient = await this.context.msGraphClientFactory.getClient();
|
||||
|
||||
this._themeProvider = this.context.serviceScope.consume(
|
||||
ThemeProvider.serviceKey
|
||||
);
|
||||
// If it exists, get the theme variant
|
||||
this._themeVariant = this._themeProvider.tryGetTheme();
|
||||
// Register a handler to be notified if the theme variant changes
|
||||
this._themeProvider.themeChangedEvent.add(
|
||||
this,
|
||||
this._handleThemeChangedEvent
|
||||
);
|
||||
|
||||
if (this.context.sdks.microsoftTeams) {
|
||||
// in teams ?
|
||||
const context = this.context.sdks.microsoftTeams!.context;
|
||||
this._applyTheme(context.theme || "default");
|
||||
this.context.sdks.microsoftTeams.teamsJs.registerOnThemeChangeHandler(
|
||||
this._applyTheme
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current theme variant reference and re-render.
|
||||
*
|
||||
* @param args The new theme
|
||||
*/
|
||||
private _handleThemeChangedEvent(args: ThemeChangedEventArgs): void {
|
||||
this._themeVariant = args.theme;
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
// Apply theme id in Teams
|
||||
private _applyTheme = (theme: string): void => {
|
||||
this.context.domElement.setAttribute("data-theme", theme);
|
||||
document.body.setAttribute("data-theme", theme);
|
||||
|
||||
if (theme == "dark") {
|
||||
loadTheme({
|
||||
palette: teamsDarkTheme,
|
||||
});
|
||||
}
|
||||
|
||||
if (theme == "default") {
|
||||
loadTheme({
|
||||
palette: teamsDefaultTheme,
|
||||
});
|
||||
}
|
||||
|
||||
if (theme == "contrast") {
|
||||
loadTheme({
|
||||
palette: teamsContrastTheme,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
const element: React.ReactElement<IDocumentsLinksAccordionProps> = React.createElement(
|
||||
DocumentsLinksAccordion,
|
||||
{
|
||||
title: this.properties.title,
|
||||
listId: this.properties.listId,
|
||||
fieldName: this.properties.fieldName,
|
||||
themeVariant: this._themeVariant,
|
||||
locale: this.context.pageContext.cultureInfo.currentUICultureName,
|
||||
listBaseTemplate: this.properties.listBasetemplate ?? 1,
|
||||
onConfigure: () =>{ this.context.propertyPane.open(); },
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get disableReactivePropertyChanges() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async onPropertyPaneConfigurationStart() {
|
||||
if (
|
||||
this.properties.fieldName &&
|
||||
this.properties.listId &&
|
||||
this.columns.length === 0
|
||||
) {
|
||||
await this.addListColumns(this.properties.listId);
|
||||
this.context.propertyPane.refresh();
|
||||
}
|
||||
|
||||
if ( this.properties.listId && this.lists.length === 0){
|
||||
await this.addLists('1');
|
||||
this.context.propertyPane.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
protected async onPropertyPaneFieldChanged(
|
||||
propertyPath: string,
|
||||
oldValue: any,
|
||||
newValue: any
|
||||
) {
|
||||
|
||||
if (propertyPath === "listId" && newValue != oldValue) {
|
||||
this.columns = [];
|
||||
|
||||
this.context.propertyPane.refresh();
|
||||
await this.addListColumns(newValue);
|
||||
this.context.propertyPane.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private async addLists(newValue: any) {
|
||||
try {
|
||||
this.lists = [];
|
||||
const _lists = await getLists(newValue);
|
||||
for (const _list of _lists) {
|
||||
this.lists.push({ key: _list.Id, text: _list.Title });
|
||||
}
|
||||
} catch (error) {
|
||||
this._hasError = true;
|
||||
this._messageError =error.message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async addListColumns(newValue: any) {
|
||||
try {
|
||||
this.columns = [];
|
||||
const _listColumns = await getListColumns(newValue);
|
||||
for (const _column of _listColumns) {
|
||||
this.columns.push({ key: _column.InternalName, text: _column.Title });
|
||||
}
|
||||
} catch (error) {
|
||||
this._hasError = true;
|
||||
this._messageError = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
const _pages: IPropertyPanePage[] = [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription,
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField("title", {
|
||||
label: strings.DescriptionFieldLabel,
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
let groups: IPropertyPaneGroup = _pages[0].groups[0] as IPropertyPaneGroup;
|
||||
let groupFields: IPropertyPaneField<any>[] = groups.groupFields;
|
||||
groupFields.push(
|
||||
PropertyFieldListPicker("listId", {
|
||||
label: "Select Document Library",
|
||||
selectedList: this.properties.listId ,
|
||||
includeHidden: false,
|
||||
baseTemplate: 101,
|
||||
orderBy: PropertyFieldListPickerOrderBy.Title,
|
||||
disabled: false,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
|
||||
properties: this.properties,
|
||||
context: this.context,
|
||||
onGetErrorMessage: null,
|
||||
deferredValidationTime: 0,
|
||||
key: "listPickerFieldId",
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
|
||||
if (this.properties.listId) {
|
||||
groupFields.push(
|
||||
PropertyFieldSpinner("", {
|
||||
key: "sp1",
|
||||
size: SpinnerSize.medium,
|
||||
isVisible: (this.columns.length || this._hasError) ? false : true,
|
||||
label: "Loading ...",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Show Columns
|
||||
if (this.columns.length > 0) {
|
||||
groupFields.push(
|
||||
PropertyPaneDropdown("fieldName", {
|
||||
label: "Select field to group by documents",
|
||||
options: this.columns,
|
||||
selectedKey: this.properties.fieldName,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Show Error
|
||||
if (this._hasError) {
|
||||
groupFields.push(
|
||||
PropertyFieldMessage("", {
|
||||
key: "msgError",
|
||||
messageType: MessageBarType.error,
|
||||
multiline: true,
|
||||
text: this._messageError,
|
||||
isVisible: this._hasError,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const _panelConfiguration: IPropertyPaneConfiguration = { pages: _pages };
|
||||
return _panelConfiguration;
|
||||
}
|
||||
}
|
12
samples/react-document-links-accordion/src/webparts/DocumentsLinksAccordion/loc/en-us.js
vendored
Normal file
12
samples/react-document-links-accordion/src/webparts/DocumentsLinksAccordion/loc/en-us.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
define([], function() {
|
||||
return {
|
||||
PlaceHolderButtonLable: "Configure",
|
||||
PlaceHolderDescription: "Please configure the web part.",
|
||||
PlaceHolderIconText: "Configure Documents Links Accordion Web Part",
|
||||
"PropertyPaneDescription": "Show documents grouped by field",
|
||||
"BasicGroupName": "Properties",
|
||||
"DescriptionFieldLabel": "Title",
|
||||
"NodocumentsLabel":"No documents found in library",
|
||||
"ViewAllLabel": "View All"
|
||||
}
|
||||
});
|
15
samples/react-document-links-accordion/src/webparts/DocumentsLinksAccordion/loc/mystrings.d.ts
vendored
Normal file
15
samples/react-document-links-accordion/src/webparts/DocumentsLinksAccordion/loc/mystrings.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
declare interface IDocumentsLinksAccordionWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
ViewAllLabel:string;
|
||||
NodocumentsLabel:string;
|
||||
PlaceHolderButtonLable: string;
|
||||
PlaceHolderDescription: string;
|
||||
PlaceHolderIconText: string;
|
||||
}
|
||||
|
||||
declare module 'DocumentsLinksAccordionWebPartStrings' {
|
||||
const strings: IDocumentsLinksAccordionWebPartStrings;
|
||||
export = strings;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 383 B |
35
samples/react-document-links-accordion/tsconfig.json
Normal file
35
samples/react-document-links-accordion/tsconfig.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.7/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
30
samples/react-document-links-accordion/tslint.json
Normal file
30
samples/react-document-links-accordion/tslint.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"export-name": false,
|
||||
"forin": false,
|
||||
"label-position": false,
|
||||
"member-access": true,
|
||||
"no-arg": false,
|
||||
"no-console": false,
|
||||
"no-construct": false,
|
||||
"no-duplicate-variable": true,
|
||||
"no-eval": false,
|
||||
"no-function-expression": true,
|
||||
"no-internal-module": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-unnecessary-semicolons": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-with-statement": true,
|
||||
"semicolon": true,
|
||||
"trailing-comma": false,
|
||||
"typedef": false,
|
||||
"typedef-whitespace": false,
|
||||
"use-named-parameter": true,
|
||||
"variable-name": false,
|
||||
"whitespace": false
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ I got the idea from this great article [Use Power Automate to Notify of Upcoming
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
|
||||
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
![Node.js LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
|
||||
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
|
||||
![Workbench Hosted: Does not work with local workbench](https://img.shields.io/badge/Workbench-Hosted-yellow.svg "Does not work with local workbench")
|
||||
@ -32,6 +32,7 @@ react-graph-app-secret-expiration | [Aimery Thomas](https://github.com/a1mery) (
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|September 17, 2021|Initial release
|
||||
1.1|October 10, 2021|Add pagination
|
||||
|
||||
|
||||
## Minimal Path to Awesome
|
||||
@ -39,14 +40,14 @@ Version|Date|Comments
|
||||
- Clone this repository
|
||||
- Ensure that you are at the solution folder
|
||||
- In the command-line run:
|
||||
- **npm install**
|
||||
- **gulp bundle**
|
||||
- **gulp package-solution**
|
||||
- `npm install`
|
||||
- `gulp bundle`
|
||||
- `gulp package-solution`
|
||||
- Deploy the package to your app catalog
|
||||
- Approve the API permission request from the SharePoint admin
|
||||
- Add the web part to a page
|
||||
- In the command-line run:
|
||||
- **gulp serve --nobrowser**
|
||||
- `gulp serve --nobrowser`
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
"This sample web part shows the list of your applications registered in Azure AD along with their associated client secret/certificate expiration date."
|
||||
],
|
||||
"creationDateTime": "2021-09-17",
|
||||
"updateDateTime": "2021-09-17",
|
||||
"updateDateTime": "2021-10-10",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
@ -22,6 +22,10 @@
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.12.1"
|
||||
},
|
||||
{
|
||||
"key": "PNPCONTROLS",
|
||||
"value": "Pagination"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
|
@ -3,7 +3,7 @@
|
||||
"solution": {
|
||||
"name": "react-graph-app-secret-expiration-client-side-solution",
|
||||
"id": "b25d85a4-7310-408a-a263-25959b0a5b1b",
|
||||
"version": "1.0.0.0",
|
||||
"version": "1.1.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false,
|
||||
"skipFeatureDeployment": true,
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-graph-app-secret-expiration",
|
||||
"version": "0.0.1",
|
||||
"version": "1.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-graph-app-secret-expiration",
|
||||
"version": "0.0.1",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
@ -5,7 +5,9 @@ import { ListView, IViewField, SelectionMode, GroupOrder, IGrouping } from "@pnp
|
||||
import { IApplications, IApplication, IFormattedApplication } from '../../../models/IApplication';
|
||||
import { IGraphAppSecretExpirationState } from './GraphAppSecretExpirationState';
|
||||
import * as moment from 'moment';
|
||||
import { DefaultButton, Spinner, mergeStyles } from '@fluentui/react';
|
||||
import { DefaultButton, Spinner, mergeStyles, SearchBox } from '@fluentui/react';
|
||||
import { Pagination } from "@pnp/spfx-controls-react/lib/pagination";
|
||||
import * as strings from 'GraphAppSecretExpirationWebPartStrings';
|
||||
|
||||
const stackItemHidden = mergeStyles({
|
||||
display: 'none',
|
||||
@ -57,9 +59,13 @@ export default class GraphAppSecretExpiration extends React.Component<IGraphAppS
|
||||
super(props);
|
||||
this.state = {
|
||||
applications: [],
|
||||
filteredApplications: [],
|
||||
filterValue: "",
|
||||
searchFilter: "",
|
||||
error: undefined,
|
||||
loading: true,
|
||||
groupByFields: []
|
||||
groupByFields: [],
|
||||
page: 1
|
||||
};
|
||||
}
|
||||
|
||||
@ -113,42 +119,80 @@ export default class GraphAppSecretExpiration extends React.Component<IGraphAppS
|
||||
var today = (moment(Date.now())).format('DD-MMM-YYYY');
|
||||
try {
|
||||
applications.forEach(app => {
|
||||
|
||||
if (app.passwordCredentials.length > 0) {
|
||||
app.passwordCredentials.forEach(pswd => {
|
||||
let daysBeforeExpiration = moment.duration((moment(pswd.endDateTime)).diff(today, 'days'), 'days').asDays();
|
||||
let formatedApp: IFormattedApplication = {
|
||||
applicationId: app.appId,
|
||||
displayName: app.displayName,
|
||||
type: "Secret",
|
||||
expirationDate: (moment(pswd.endDateTime)).format('DD-MMM-YYYY'),
|
||||
daysLeft: daysBeforeExpiration > 0 ? daysBeforeExpiration : 0
|
||||
};
|
||||
displayedApplication.push(formatedApp);
|
||||
});
|
||||
}
|
||||
if (app.keyCredentials.length > 0) {
|
||||
app.keyCredentials.forEach(keyCred => {
|
||||
let daysBeforeExpiration = moment.duration((moment(keyCred.endDateTime)).diff(today, 'days'), 'days').asDays();
|
||||
let formatedApp: IFormattedApplication = {
|
||||
applicationId: app.appId,
|
||||
displayName: app.displayName,
|
||||
type: "Certificate",
|
||||
expirationDate: (moment(keyCred.endDateTime)).format('DD-MMM-YYYY'),
|
||||
daysLeft: daysBeforeExpiration > 0 ? daysBeforeExpiration : 0
|
||||
};
|
||||
displayedApplication.push(formatedApp);
|
||||
});
|
||||
}
|
||||
app.passwordCredentials.forEach(pswd => {
|
||||
let daysBeforeExpiration = moment.duration((moment(pswd.endDateTime)).diff(today, 'days'), 'days').asDays();
|
||||
let formatedApp: IFormattedApplication = {
|
||||
applicationId: app.appId,
|
||||
displayName: app.displayName,
|
||||
type: "Secret",
|
||||
expirationDate: (moment(pswd.endDateTime)).format('DD-MMM-YYYY'),
|
||||
daysLeft: daysBeforeExpiration > 0 ? daysBeforeExpiration : 0
|
||||
};
|
||||
displayedApplication.push(formatedApp);
|
||||
});
|
||||
app.keyCredentials.forEach(keyCred => {
|
||||
let daysBeforeExpiration = moment.duration((moment(keyCred.endDateTime)).diff(today, 'days'), 'days').asDays();
|
||||
let formatedApp: IFormattedApplication = {
|
||||
applicationId: app.appId,
|
||||
displayName: app.displayName,
|
||||
type: "Certificate",
|
||||
expirationDate: (moment(keyCred.endDateTime)).format('DD-MMM-YYYY'),
|
||||
daysLeft: daysBeforeExpiration > 0 ? daysBeforeExpiration : 0
|
||||
};
|
||||
displayedApplication.push(formatedApp);
|
||||
});
|
||||
});
|
||||
this.setState({
|
||||
applications: displayedApplication
|
||||
applications: displayedApplication,
|
||||
filteredApplications: displayedApplication
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
private _getPage(selectedPage: number) {
|
||||
this.setState({
|
||||
page: selectedPage
|
||||
});
|
||||
}
|
||||
|
||||
private _filterApplication = (value, clear: boolean) => {
|
||||
let searchResult: IFormattedApplication[] = [];
|
||||
if (clear) {
|
||||
this.state.applications.forEach(app => {
|
||||
if (this._filterByProperties(app, value)) {
|
||||
searchResult.push(app);
|
||||
}
|
||||
});
|
||||
this.setState({
|
||||
filteredApplications: searchResult,
|
||||
filterValue: value
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
filteredApplications: this.state.applications,
|
||||
filterValue: value,
|
||||
page: 1
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private _filterByProperties(application: IFormattedApplication, filterValue) {
|
||||
if (application.applicationId.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) {
|
||||
return true;
|
||||
} else if (application.displayName.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) {
|
||||
return true;
|
||||
} else if (application.expirationDate.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) {
|
||||
return true;
|
||||
} else if (application.type.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private _groupView = () => {
|
||||
if (this.state.groupByFields.length === 0) {
|
||||
let groupByFields: IGrouping[] = [
|
||||
@ -177,21 +221,31 @@ export default class GraphAppSecretExpiration extends React.Component<IGraphAppS
|
||||
<p className={styles.title}>Application list :</p>
|
||||
<div className={this.state.loading ? "" : stackItemHidden}>
|
||||
<Spinner label="Loading..." ariaLive="assertive" labelPosition="left" />
|
||||
<br/>
|
||||
<br />
|
||||
</div>
|
||||
<div className={this.state.loading ? stackItemHidden : ""}>
|
||||
<DefaultButton text={this.state.groupByFields.length === 0 ? "Group by App ID" : "Ungroup"} onClick={this._groupView} />
|
||||
<SearchBox placeholder="Search" onChange={(e, text) => this._filterApplication(text, false)} onClear={() => this._filterApplication("", true)} value={this.state.filterValue} />
|
||||
<ListView
|
||||
items={this.state.applications}
|
||||
items={this.state.filteredApplications.slice(this.state.page === 1 || this.state.filterValue !== "" ? 0 : this.state.page * 10 - 10, this.state.page * 10)}
|
||||
viewFields={_viewFields}
|
||||
iconFieldName="ServerRelativeUrl"
|
||||
compact={true}
|
||||
selectionMode={SelectionMode.none}
|
||||
selection={this._getSelection}
|
||||
groupByFields={this.state.groupByFields}
|
||||
showFilter={true}
|
||||
showFilter={false}
|
||||
filterPlaceHolder="Search..." />
|
||||
</div>
|
||||
<Pagination
|
||||
currentPage={1}
|
||||
totalPages={Math.floor(this.state.filteredApplications.length / 10) + 1}
|
||||
onChange={(page) => this._getPage(page)}
|
||||
limiter={3} // Optional - default value 3
|
||||
hideFirstPageJump // Optional
|
||||
hideLastPageJump // Optional
|
||||
limiterIcon={"Emoji12"} // Optional
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -3,7 +3,11 @@ import { IApplications, IApplication,IPasswordCredential,IKeyCredential,IFormatt
|
||||
|
||||
export interface IGraphAppSecretExpirationState {
|
||||
applications: IFormattedApplication[];
|
||||
filteredApplications: IFormattedApplication[];
|
||||
filterValue: string;
|
||||
searchFilter: string;
|
||||
groupByFields: IGrouping[];
|
||||
page: number;
|
||||
error: string;
|
||||
loading: boolean;
|
||||
}
|
1
samples/react-groups-teams/.gitignore
vendored
1
samples/react-groups-teams/.gitignore
vendored
@ -10,6 +10,7 @@ node_modules
|
||||
dist
|
||||
lib
|
||||
solution
|
||||
release
|
||||
temp
|
||||
*.sppkg
|
||||
|
||||
|
@ -26,11 +26,13 @@ Web part pulls all Microsoft 365 Groups and Teams that the logged in user has ac
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.10](https://img.shields.io/badge/SPFx-1.10.0-green.svg)
|
||||
![Node.js LTS 8.x | LTS 10.x](https://img.shields.io/badge/Node.js-LTS%208.x%20%7C%20LTS%210.x-green.svg)
|
||||
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
|
||||
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
|
||||
![Workbench Hosted: Only after API permissions granted](https://img.shields.io/badge/Workbench-Hosted-yellow.svg "Only after API permissions granted")
|
||||
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
|
||||
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%202019-Not%20compatible-red.svg)
|
||||
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%202016%20(Feature%20Pack%202)-Not%20compatible-red.svg)
|
||||
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "This solution requires API permissions")
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-yellow.svg "Only after API permissions granted")
|
||||
|
||||
## Applies to
|
||||
|
||||
@ -41,7 +43,7 @@ Web part pulls all Microsoft 365 Groups and Teams that the logged in user has ac
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
React-Groups-Teams | [Alison Collins](https://github.com/ReactIntern) |
|
||||
React-Groups-Teams | [Alison Collins](https://github.com/ReactIntern) ([Blog](https://graphgod.dev), [LinkedIn](https://www.linkedin.com/in/alison-collins-53192b219/)) |
|
||||
|
||||
## Version history
|
||||
|
||||
@ -49,7 +51,7 @@ React-Groups-Teams | [Alison Collins](https://github.com/ReactIntern) |
|
||||
| ------- | ---------------- | --------------- |
|
||||
| 1.0.0 | April 16, 2021 | Initial release |
|
||||
| 1.0.1 | August 1, 2021 | Fixed references to Office.com |
|
||||
|
||||
| 1.1.0 | October 8, 2021 | Upgraded to SPFx 1.12.1 for higher compatibility and added Teams Tab deployment support. |
|
||||
|
||||
|
||||
# Prerequisites
|
||||
|
@ -9,7 +9,7 @@
|
||||
"Web part pulls all Microsoft 365 Groups and Teams that the logged in user has access to view."
|
||||
],
|
||||
"creationDateTime": "2021-05-06",
|
||||
"updateDateTime": "2021-08-01",
|
||||
"updateDateTime": "2021-10-08",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
@ -21,7 +21,7 @@
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.10.0"
|
||||
"value": "1.12.1"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
|
13
samples/react-groups-teams/gulpfile.js
vendored
13
samples/react-groups-teams/gulpfile.js
vendored
@ -1,7 +1,16 @@
|
||||
'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.`);
|
||||
|
||||
build.initialize(gulp);
|
||||
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.initialize(require('gulp'));
|
22496
samples/react-groups-teams/npm-shrinkwrap.json
generated
Normal file
22496
samples/react-groups-teams/npm-shrinkwrap.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20536
samples/react-groups-teams/package-lock.json
generated
20536
samples/react-groups-teams/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,10 +12,10 @@
|
||||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.9.1",
|
||||
"@microsoft/sp-lodash-subset": "1.9.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.9.1",
|
||||
"@microsoft/sp-webpart-base": "1.9.1",
|
||||
"@microsoft/sp-core-library": "1.12.1",
|
||||
"@microsoft/sp-lodash-subset": "1.12.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.12.1",
|
||||
"@microsoft/sp-webpart-base": "1.12.1",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
@ -28,10 +28,10 @@
|
||||
"@types/react": "16.8.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.9.1",
|
||||
"@microsoft/sp-tslint-rules": "1.9.1",
|
||||
"@microsoft/sp-module-interfaces": "1.9.1",
|
||||
"@microsoft/sp-webpart-workbench": "1.9.1",
|
||||
"@microsoft/sp-build-web": "1.12.1",
|
||||
"@microsoft/sp-tslint-rules": "1.12.1",
|
||||
"@microsoft/sp-module-interfaces": "1.12.1",
|
||||
"@microsoft/sp-webpart-workbench": "1.12.1",
|
||||
"@microsoft/rush-stack-compiler-2.9": "0.7.16",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": "3.4.34",
|
||||
|
@ -0,0 +1,66 @@
|
||||
{
|
||||
"id": "5ced32db-af85-469a-a3cb-39f3986e1f1a",
|
||||
"alias": "MicrosoftGroupsWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "1.0.1",
|
||||
"manifestVersion": 2,
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": [
|
||||
"SharePointWebPart",
|
||||
"TeamsTab"
|
||||
],
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
|
||||
"group": {
|
||||
"default": "Other"
|
||||
},
|
||||
"title": {
|
||||
"default": "Microsoft Groups"
|
||||
},
|
||||
"description": {
|
||||
"default": "Microsoft Groups description"
|
||||
},
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "Microsoft Groups"
|
||||
}
|
||||
}
|
||||
],
|
||||
"loaderConfig": {
|
||||
"internalModuleBaseUrls": [
|
||||
"https://localhost:4321/dist/"
|
||||
],
|
||||
"entryModuleId": "microsoft-groups-web-part",
|
||||
"scriptResources": {
|
||||
"microsoft-groups-web-part": {
|
||||
"type": "path",
|
||||
"path": "microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js"
|
||||
},
|
||||
"@microsoft/sp-core-library": {
|
||||
"type": "component",
|
||||
"id": "7263c7d0-1d6a-45ec-8d85-d4d1d234171b",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"@microsoft/sp-webpart-base": {
|
||||
"type": "component",
|
||||
"id": "974a7777-0990-4136-8fa6-95d80114c2e0",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"react": {
|
||||
"type": "component",
|
||||
"id": "0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d",
|
||||
"version": "16.8.5"
|
||||
},
|
||||
"react-dom": {
|
||||
"type": "component",
|
||||
"id": "aa0a46ec-1505-43cd-a44a-93f3a5aa460a",
|
||||
"version": "16.8.5"
|
||||
},
|
||||
"MicrosoftGroupsWebPartStrings": {
|
||||
"type": "path",
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_b41dd8b4c7f5f69692bd8f24e2b83745.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"DescriptionFieldLabel": "Description Field"
|
||||
}
|
||||
});
|
1
samples/react-groups-teams/release/assets/microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js
vendored
Normal file
1
samples/react-groups-teams/release/assets/microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,98 @@
|
||||
{
|
||||
"bundles": {
|
||||
"microsoft-groups-web-part": {
|
||||
"dependencies": [
|
||||
{
|
||||
"componentId": "7263c7d0-1d6a-45ec-8d85-d4d1d234171b",
|
||||
"componentName": "@microsoft/sp-core-library",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": true
|
||||
},
|
||||
{
|
||||
"componentId": "01c4df03-e775-48cb-aa14-171ee5199a15",
|
||||
"componentName": "tslib",
|
||||
"componentVersion": "1.10.0",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "2e09fb9b-13bb-48f2-859f-97d6fff71176",
|
||||
"componentName": "@ms/odsp-core-bundle",
|
||||
"componentVersion": "1.1.13",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "73e1dc6c-8441-42cc-ad47-4bd3659f8a3a",
|
||||
"componentName": "@microsoft/sp-lodash-subset",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "974a7777-0990-4136-8fa6-95d80114c2e0",
|
||||
"componentName": "@microsoft/sp-webpart-base",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": true
|
||||
},
|
||||
{
|
||||
"componentId": "8217e442-8ed3-41fd-957d-b112e841286a",
|
||||
"componentName": "@ms/sp-telemetry",
|
||||
"componentVersion": "0.19.2",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "467dc675-7cc5-4709-8aac-78e3b71bd2f6",
|
||||
"componentName": "@microsoft/sp-component-base",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "e40f8203-b39d-425a-a957-714852e33b79",
|
||||
"componentName": "@microsoft/sp-dynamic-data",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "78359e4b-07c2-43c6-8d0b-d060b4d577e8",
|
||||
"componentName": "@microsoft/sp-diagnostics",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "1c4541f7-5c31-41aa-9fa8-fbc9dc14c0a8",
|
||||
"componentName": "@microsoft/sp-page-context",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "229b8d08-79f3-438b-8c21-4613fc877abd",
|
||||
"componentName": "@microsoft/load-themed-styles",
|
||||
"componentVersion": "0.1.2",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "c07208f0-ea3b-4c1a-9965-ac1b825211a6",
|
||||
"componentName": "@microsoft/sp-http",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "1c6c9123-7aac-41f3-a376-3caea41ed83f",
|
||||
"componentName": "@microsoft/sp-loader",
|
||||
"componentVersion": "1.12.1",
|
||||
"isDirectDependency": false
|
||||
},
|
||||
{
|
||||
"componentId": "0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d",
|
||||
"componentName": "react",
|
||||
"componentVersion": "16.8.5",
|
||||
"isDirectDependency": true
|
||||
},
|
||||
{
|
||||
"componentId": "aa0a46ec-1505-43cd-a44a-93f3a5aa460a",
|
||||
"componentName": "react-dom",
|
||||
"componentVersion": "16.8.5",
|
||||
"isDirectDependency": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
{
|
||||
"id": "5ced32db-af85-469a-a3cb-39f3986e1f1a",
|
||||
"alias": "MicrosoftGroupsWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "1.0.1",
|
||||
"manifestVersion": 2,
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": [
|
||||
"SharePointWebPart",
|
||||
"TeamsTab"
|
||||
],
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
|
||||
"group": {
|
||||
"default": "Other"
|
||||
},
|
||||
"title": {
|
||||
"default": "Microsoft Groups"
|
||||
},
|
||||
"description": {
|
||||
"default": "Microsoft Groups description"
|
||||
},
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "Microsoft Groups"
|
||||
}
|
||||
}
|
||||
],
|
||||
"loaderConfig": {
|
||||
"internalModuleBaseUrls": [
|
||||
"<!-- PATH TO CDN -->"
|
||||
],
|
||||
"entryModuleId": "microsoft-groups-web-part",
|
||||
"scriptResources": {
|
||||
"microsoft-groups-web-part": {
|
||||
"type": "path",
|
||||
"path": "microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js"
|
||||
},
|
||||
"@microsoft/sp-core-library": {
|
||||
"type": "component",
|
||||
"id": "7263c7d0-1d6a-45ec-8d85-d4d1d234171b",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"@microsoft/sp-webpart-base": {
|
||||
"type": "component",
|
||||
"id": "974a7777-0990-4136-8fa6-95d80114c2e0",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"react": {
|
||||
"type": "component",
|
||||
"id": "0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d",
|
||||
"version": "16.8.5"
|
||||
},
|
||||
"react-dom": {
|
||||
"type": "component",
|
||||
"id": "aa0a46ec-1505-43cd-a44a-93f3a5aa460a",
|
||||
"version": "16.8.5"
|
||||
},
|
||||
"MicrosoftGroupsWebPartStrings": {
|
||||
"type": "path",
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_b41dd8b4c7f5f69692bd8f24e2b83745.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
{
|
||||
"id": "5ced32db-af85-469a-a3cb-39f3986e1f1a",
|
||||
"alias": "MicrosoftGroupsWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "1.0.1",
|
||||
"manifestVersion": 2,
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": [
|
||||
"SharePointWebPart",
|
||||
"TeamsTab"
|
||||
],
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
|
||||
"group": {
|
||||
"default": "Other"
|
||||
},
|
||||
"title": {
|
||||
"default": "Microsoft Groups"
|
||||
},
|
||||
"description": {
|
||||
"default": "Microsoft Groups description"
|
||||
},
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "Microsoft Groups"
|
||||
}
|
||||
}
|
||||
],
|
||||
"loaderConfig": {
|
||||
"internalModuleBaseUrls": [
|
||||
"<!-- PATH TO CDN -->"
|
||||
],
|
||||
"entryModuleId": "microsoft-groups-web-part",
|
||||
"scriptResources": {
|
||||
"microsoft-groups-web-part": {
|
||||
"type": "path",
|
||||
"path": "microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js"
|
||||
},
|
||||
"@microsoft/sp-core-library": {
|
||||
"type": "component",
|
||||
"id": "7263c7d0-1d6a-45ec-8d85-d4d1d234171b",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"@microsoft/sp-webpart-base": {
|
||||
"type": "component",
|
||||
"id": "974a7777-0990-4136-8fa6-95d80114c2e0",
|
||||
"version": "1.12.1"
|
||||
},
|
||||
"react": {
|
||||
"type": "component",
|
||||
"id": "0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d",
|
||||
"version": "16.8.5"
|
||||
},
|
||||
"react-dom": {
|
||||
"type": "component",
|
||||
"id": "aa0a46ec-1505-43cd-a44a-93f3a5aa460a",
|
||||
"version": "16.8.5"
|
||||
},
|
||||
"MicrosoftGroupsWebPartStrings": {
|
||||
"type": "path",
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_b41dd8b4c7f5f69692bd8f24e2b83745.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": ["SharePointWebPart"],
|
||||
"supportedHosts": ["SharePointWebPart", "TeamsTab"],
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
|
@ -1,25 +0,0 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# we recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
1
samples/react-kanban-board/.gitignore
vendored
1
samples/react-kanban-board/.gitignore
vendored
@ -11,6 +11,7 @@ dist
|
||||
lib
|
||||
solution
|
||||
temp
|
||||
release
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
16
samples/react-kanban-board/.npmignore
Normal file
16
samples/react-kanban-board/.npmignore
Normal file
@ -0,0 +1,16 @@
|
||||
!dist
|
||||
config
|
||||
|
||||
gulpfile.js
|
||||
|
||||
release
|
||||
src
|
||||
temp
|
||||
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
|
||||
*.log
|
||||
|
||||
.yo-rc.json
|
||||
.vscode
|
18
samples/react-kanban-board/.vscode/launch.json
vendored
18
samples/react-kanban-board/.vscode/launch.json
vendored
@ -4,23 +4,7 @@
|
||||
* Chrome browser: https://aka.ms/spfx-debugger-extensions
|
||||
*/
|
||||
"version": "0.2.0",
|
||||
"configurations": [{
|
||||
"name": "Local workbench",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "https://localhost:4321/temp/workbench.html",
|
||||
"webRoot": "${workspaceRoot}",
|
||||
"sourceMaps": true,
|
||||
"sourceMapPathOverrides": {
|
||||
"webpack:///.././src/*": "${webRoot}/src/*",
|
||||
"webpack:///../../../src/*": "${webRoot}/src/*",
|
||||
"webpack:///../../../../src/*": "${webRoot}/src/*",
|
||||
"webpack:///../../../../../src/*": "${webRoot}/src/*"
|
||||
},
|
||||
"runtimeArgs": [
|
||||
"--remote-debugging-port=9222"
|
||||
]
|
||||
},
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Hosted workbench",
|
||||
"type": "chrome",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.10.0",
|
||||
"version": "1.13.0",
|
||||
"libraryName": "react-kanban-board",
|
||||
"libraryId": "cccbd72b-7b89-4128-9348-0a4850ded8fd",
|
||||
"packageManager": "npm",
|
||||
|
@ -24,9 +24,17 @@ The web part uses the default columns of the SharePoint Tasks list for showing t
|
||||
|
||||
![picture of the web part in action](assets/kanbanofficeUI.gif)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![1.10.0](https://img.shields.io/badge/version-1.10.0-green.svg)
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.13.0](https://img.shields.io/badge/SPFx-1.13.0-green.svg)
|
||||
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![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")
|
||||
![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")
|
||||
![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")
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
|
||||
|
||||
## Applies to
|
||||
|
||||
@ -49,9 +57,10 @@ The Task list can be chosen using the web part properties (BaseTemplate 171 or 1
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-kanban-board | [Ram](https://twitter.com/ram_meenavalli)
|
||||
react-kanban-board | Daniel Westerdale ([Westerdale Solutions Ltd.](https://westerdale.blog), [@westerdaled](https://twitter.com/westerdaled?s=20))
|
||||
react-kanban-board | Peter Paul Kirschner ([@petkir_at](https://twitter.com/petkir_at))
|
||||
react-kanban-board | [Ram Prasad Meenavalli](https://github.com/RamPrasadMeenavalli) ([@ram_meenavalli](https://twitter.com/ram_meenavalli))
|
||||
react-kanban-board | [Daniel Westerdale](https://github.com/westerdaled) ([Westerdale Solutions Ltd.](https://westerdale.blog), [@westerdaled](https://twitter.com/westerdaled?s=20))
|
||||
react-kanban-board | [Peter Paul Kirschner](https://github.com/petkir) ([@petkir_at](https://twitter.com/petkir_at))
|
||||
react-kanban-board | [Alex Terentiev](https://github.com/AJIXuMuK) ([@alexaterentiev](https://twitter.com/alexaterentiev))
|
||||
|
||||
## Version history
|
||||
|
||||
@ -60,6 +69,7 @@ Version|Date|Comments
|
||||
1.0.0.0|July 17, 2019|Initial release
|
||||
1.0.1.0|April 21, 2020|Added support for Teams hosts
|
||||
2.0.0.0|July 10, 2020| jqwidgets replaced with a custom Kanban Board based on Office UI Component and IE11 Support
|
||||
3.0.0.0|October 29, 2021| SPFx 1.13, PnPJS v2, PnP Controls v3
|
||||
|
||||
[Read More about the implementation of this Board](./src/kanban/README.md)
|
||||
|
||||
@ -80,13 +90,6 @@ Version|Date|Comments
|
||||
<!---* [Jean-Philippe CIVADE](https://github.com/ewidance) for Bug Report IE11 (initiator of rewrite of this sample)-->
|
||||
<!---* [RamPrasadMeenavalli](https://github.com/RamPrasadMeenavalli) for the initial Idea-->
|
||||
|
||||
## Disclaimer
|
||||
|
||||
**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.**
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
* Clone this repository
|
||||
@ -102,4 +105,26 @@ This sample highlights the following concepts
|
||||
|
||||
When a task is moved to different columns in the Kanban Board, the status of the respective SharePoint list item is updated using PnP JS
|
||||
|
||||
|
||||
## Disclaimer
|
||||
|
||||
**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.**
|
||||
|
||||
## Help
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/labels/react-kanban-board) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=label%3Areact-kanban-board) and see what the community is saying
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-kanban-board&authors=@RamPrasadMeenavalli%20@westerdaled%20@petkir%20@AJIXuMuK&title=react-kanban-board%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-kanban-board&authors=@RamPrasadMeenavalli%20@westerdaled%20@petkir%20@AJIXuMuK&title=react-kanban-board%20-%20).
|
||||
|
||||
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=suggestion.yml&sample=react-kanban-board&authors=@RamPrasadMeenavalli%20@westerdaled%20@petkir%20@AJIXuMuK&title=react-kanban-board%20-%20).
|
||||
|
||||
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-kanban-board" />
|
||||
|
@ -21,11 +21,15 @@
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.10.0"
|
||||
"value": "1.13.0"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-TEAMSTAB",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "PNPCONTROLS",
|
||||
"value": "PropertyFieldListPicker, PropertyFieldOrder, WebPartTitle, Placeholder"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
@ -57,6 +61,13 @@
|
||||
"pictureUrl": "https://github.com/petkir.png",
|
||||
"name": "Peter Paul Kirschner",
|
||||
"twitter": "petkir_at"
|
||||
},
|
||||
{
|
||||
"gitHubAccount": "AJIXuMuK",
|
||||
"company": "Sharepointalist",
|
||||
"pictureUrl": "https://avatars.githubusercontent.com/u/17036219?s=460\u0026u=b8e83fb70a90eae0c0e0078c206990785e1a5b6f\u0026v=4",
|
||||
"name": "Alex Terentiev",
|
||||
"twitter": "alexaterentiev"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
"workingDir": "./release/assets/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-kanban-board",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
|
@ -3,10 +3,17 @@
|
||||
"solution": {
|
||||
"name": "react-kanban-board-client-side-solution",
|
||||
"id": "cccbd72b-7b89-4128-9348-0a4850ded8fd",
|
||||
"version": "2.0.0.0",
|
||||
"version": "3.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"websiteUrl": "",
|
||||
"mpnId": ""
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-kanban-board.sppkg"
|
||||
|
@ -2,9 +2,5 @@
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
"initialPage": "https://enter-your-SharePoint-site/_layouts/workbench.aspx"
|
||||
}
|
||||
|
49
samples/react-kanban-board/gulpfile.js
vendored
49
samples/react-kanban-board/gulpfile.js
vendored
@ -6,50 +6,13 @@ 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.`);
|
||||
|
||||
// This section is inspired by Stefan Bauer's article at https://n8d.at/how-to-version-new-sharepoint-framework-projects/
|
||||
// Stefan rocks!
|
||||
let syncVersionsSubtask = build.subTask('version-sync', function (gulp, buildOptions, done) {
|
||||
this.log('Synching versions');
|
||||
|
||||
// import gulp utilits to write error messages
|
||||
const gutil = require('gulp-util');
|
||||
|
||||
// import file system utilities form nodeJS
|
||||
const fs = require('fs');
|
||||
|
||||
// read package.json
|
||||
var pkgConfig = require('./package.json');
|
||||
|
||||
// read configuration of web part solution file
|
||||
var pkgSolution = require('./config/package-solution.json');
|
||||
|
||||
// log old version
|
||||
this.log('package-solution.json version:\t' + pkgSolution.solution.version);
|
||||
|
||||
// Generate new MS compliant version number
|
||||
var newVersionNumber = pkgConfig.version.split('-')[0] + '.0';
|
||||
|
||||
if (pkgSolution.solution.version !== newVersionNumber) {
|
||||
// assign newly generated version number to web part version
|
||||
pkgSolution.solution.version = newVersionNumber;
|
||||
|
||||
// log new version
|
||||
this.log('New package-solution.json version:\t' + pkgSolution.solution.version);
|
||||
|
||||
fs.writeFile('./config/package-solution.json', JSON.stringify(pkgSolution, null, 4), function (err, result) {
|
||||
if (err) this.log('error', err);
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
this.log('package-solution.json version is up-to-date');
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
let syncVersionTask = build.task('version-sync', syncVersionsSubtask);
|
||||
build.rig.addPreBuildTask(syncVersionTask);
|
||||
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.initialize(gulp);
|
||||
|
33446
samples/react-kanban-board/package-lock.json
generated
33446
samples/react-kanban-board/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,53 +1,39 @@
|
||||
{
|
||||
"name": "react-kanban-board",
|
||||
"main": "lib/index.js",
|
||||
"version": "2.0.0",
|
||||
"version": "3.0.0",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"engines": "undefined",
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.10.0",
|
||||
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
|
||||
"@microsoft/sp-property-pane": "1.10.0",
|
||||
"@microsoft/sp-webpart-base": "1.10.0",
|
||||
"@pnp/common": "^1.3.3",
|
||||
"@pnp/logging": "^1.3.3",
|
||||
"@pnp/odata": "^1.3.3",
|
||||
"@pnp/polyfill-ie11": "^2.0.2",
|
||||
"@pnp/sp": "^1.3.3",
|
||||
"@pnp/spfx-controls-react": "1.19.0",
|
||||
"@pnp/spfx-property-controls": "1.19.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"classnames": "^2.2.6",
|
||||
"office-ui-fabric-react": "6.214.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
"@microsoft/sp-core-library": "1.13.0",
|
||||
"@microsoft/sp-lodash-subset": "1.13.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.13.0",
|
||||
"@microsoft/sp-property-pane": "1.13.0",
|
||||
"@microsoft/sp-webpart-base": "1.13.0",
|
||||
"@pnp/sp": "2.10.0",
|
||||
"@pnp/spfx-controls-react": "^3.5.0-beta.2d993b2",
|
||||
"@pnp/spfx-property-controls": "^3.3.0-beta.d48002e",
|
||||
"office-ui-fabric-react": "7.174.1",
|
||||
"react": "16.13.1",
|
||||
"react-dom": "16.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/rush-stack-compiler-2.9": "0.7.7",
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"@microsoft/sp-build-web": "1.10.0",
|
||||
"@microsoft/sp-module-interfaces": "1.10.0",
|
||||
"@microsoft/sp-tslint-rules": "1.10.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.10.0",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"@microsoft/rush-stack-compiler-3.7": "0.2.3",
|
||||
"@microsoft/rush-stack-compiler-3.9": "0.4.47",
|
||||
"@microsoft/sp-build-web": "1.13.0",
|
||||
"@microsoft/sp-module-interfaces": "1.13.0",
|
||||
"@microsoft/sp-tslint-rules": "1.13.0",
|
||||
"@types/react": "16.9.51",
|
||||
"@types/react-dom": "16.9.8",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"ajv": "~5.2.2",
|
||||
"autoprefixer": "^9.8.4",
|
||||
"gulp": "~3.9.1",
|
||||
"gulp": "4.0.2",
|
||||
"react-html-parser": "^2.0.2"
|
||||
}
|
||||
}
|
||||
|
@ -331,6 +331,7 @@ const hasprocessIndicator = buckets.filter((b)=> b.showPercentageHeadline).lengt
|
||||
}
|
||||
|
||||
private onDragStart(event, taskId: string, bucket: string): void {
|
||||
console.log('onDragStart');
|
||||
const taskitem = this.props.tasks.filter(p => p.taskId === taskId);
|
||||
if (taskitem.length === 1) {
|
||||
event.dataTransfer.setData("text", taskId);
|
||||
@ -353,6 +354,7 @@ const hasprocessIndicator = buckets.filter((b)=> b.showPercentageHeadline).lengt
|
||||
|
||||
private onDragOver(event, targetbucket: string): void {
|
||||
event.preventDefault();
|
||||
console.log('onDragOver');
|
||||
|
||||
if (this.dragelement.bucket !== targetbucket) {
|
||||
const index = findIndex(this.props.buckets, element => element.bucket == targetbucket);
|
||||
|
@ -4,7 +4,7 @@
|
||||
import * as React from 'react';
|
||||
import styles from './KanbanTaskManagedProp.module.scss';
|
||||
import { IKanbanTaskManagedProps, KanbanTaskMamagedPropertyType } from './IKanbanTask';
|
||||
import { Stack } from 'office-ui-fabric-react/lib/Stack';
|
||||
import { Stack } from 'office-ui-fabric-react/lib/Stack';
|
||||
import ReactHtmlParser from 'react-html-parser';
|
||||
import { Persona, PersonaSize, IPersonaProps } from 'office-ui-fabric-react';
|
||||
|
||||
@ -67,10 +67,8 @@ export default class KanbanTaskManagedProp extends React.Component<IKanbanTaskMa
|
||||
size={PersonaSize.size32}
|
||||
hidePersonaDetails={false}
|
||||
/>))
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
};
|
||||
</span>);
|
||||
break;
|
||||
case KanbanTaskMamagedPropertyType.complex:
|
||||
|
@ -11,7 +11,6 @@ import { cloneDeep } from '@microsoft/sp-lodash-subset';
|
||||
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
|
||||
import { PropertyFieldOrder } from '@pnp/spfx-property-controls/lib/PropertyFieldOrder';
|
||||
import * as strings from 'KanbanBoardWebPartStrings';
|
||||
import "@pnp/polyfill-ie11";
|
||||
import { sp } from '@pnp/sp';
|
||||
|
||||
import PropertyPaneBucketConfigComponent from './components/PropertyPaneBucketConfig';
|
||||
@ -113,7 +112,7 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
|
||||
onListsRetrieved: (lists) => {
|
||||
//TODO Check from TS Definition it should be a string but i get a number
|
||||
// with Typesafe equal it fails
|
||||
if (Environment.type == EnvironmentType.Local || Environment.type == EnvironmentType.Test) {
|
||||
if (Environment.type == EnvironmentType.Test) {
|
||||
return lists;
|
||||
} else {
|
||||
const alists = lists.filter((l: any) => {
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { ISPKanbanService } from "./ISPKanbanService";
|
||||
import "@pnp/polyfill-ie11";
|
||||
import { sp } from '@pnp/sp';
|
||||
import { IKanbanTask, KanbanTaskMamagedPropertyType } from "../../../kanban";
|
||||
import * as strings from 'KanbanBoardWebPartStrings';
|
||||
|
||||
|
@ -1,8 +1,16 @@
|
||||
import { ISPKanbanService } from "./ISPKanbanService";
|
||||
import "@pnp/polyfill-ie11";
|
||||
import { sp } from '@pnp/sp';
|
||||
import '@pnp/sp/webs';
|
||||
import '@pnp/sp/lists';
|
||||
import '@pnp/sp/items';
|
||||
import '@pnp/sp/fields';
|
||||
import { IKanbanTask, KanbanTaskMamagedPropertyType } from "../../../kanban";
|
||||
import * as strings from 'KanbanBoardWebPartStrings';
|
||||
import { IFieldInfo } from "@pnp/sp/fields";
|
||||
|
||||
interface IFieldChoiceInfo extends IFieldInfo {
|
||||
Choices: string[];
|
||||
}
|
||||
|
||||
export default class SPKanbanService implements ISPKanbanService {
|
||||
|
||||
@ -50,7 +58,7 @@ export default class SPKanbanService implements ISPKanbanService {
|
||||
}
|
||||
public getBuckets(listId: string, ): Promise<string[]> {
|
||||
return sp.web.lists.getById(listId).fields.getByInternalNameOrTitle("Status").get()
|
||||
.then(status => status.Choices.map((val, index) => {
|
||||
.then((status: IFieldChoiceInfo) => status.Choices.map((val, index) => {
|
||||
return val;
|
||||
}));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.9/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
@ -19,20 +19,18 @@
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection"
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts", "src/webparts/kanbanBoard/components/bucketOrder.tsx"
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"lib"
|
||||
]
|
||||
"exclude": []
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"export-name": false,
|
||||
@ -17,7 +17,6 @@
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-unnecessary-semicolons": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-with-statement": true,
|
||||
"semicolon": true,
|
||||
"trailing-comma": false,
|
||||
|
@ -1,25 +0,0 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# we recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
4
samples/react-list-items-menu/.gitignore
vendored
4
samples/react-list-items-menu/.gitignore
vendored
@ -9,8 +9,10 @@ node_modules
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
release
|
||||
solution
|
||||
temp
|
||||
release
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
@ -30,4 +32,4 @@ obj
|
||||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
||||
*.scss.d.ts
|
||||
*.scss.d.ts
|
||||
|
16
samples/react-list-items-menu/.npmignore
Normal file
16
samples/react-list-items-menu/.npmignore
Normal file
@ -0,0 +1,16 @@
|
||||
!dist
|
||||
config
|
||||
|
||||
gulpfile.js
|
||||
|
||||
release
|
||||
src
|
||||
temp
|
||||
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
|
||||
*.log
|
||||
|
||||
.yo-rc.json
|
||||
.vscode
|
@ -24,7 +24,7 @@
|
||||
"environment": "spo",
|
||||
"framework": "react",
|
||||
"isCreatingSolution": true,
|
||||
"version": "1.11.0",
|
||||
"version": "1.13.0",
|
||||
"libraryName": "react-list-items-menu",
|
||||
"libraryId": "8b4a758d-a968-4e7c-a949-b42e7dd5ad14",
|
||||
"packageManager": "npm",
|
||||
|
@ -17,13 +17,12 @@ When the user clicks on the header it dynamically load documents.
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.11](https://img.shields.io/badge/SPFx-1.11.0-green.svg)
|
||||
![Node.js LTS 10.x](https://img.shields.io/badge/Node.js-LTS%2010.x-green.svg)
|
||||
![SPFx 1.13.0](https://img.shields.io/badge/SPFx-1.13.0-green.svg)
|
||||
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![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")
|
||||
![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")
|
||||
![Teams Incompatible](https://img.shields.io/badge/Teams-Incompatible-lightgrey.svg)
|
||||
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "The solution requires access to SharePoint content")
|
||||
![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")
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
|
||||
## Applies to
|
||||
@ -31,11 +30,11 @@ When the user clicks on the header it dynamically load documents.
|
||||
* [SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||
* [Office 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
||||
|
||||
## WebPart Properties
|
||||
## Web Part Properties
|
||||
|
||||
Property |Type|Required| comments
|
||||
--------------------|----|--------|----------
|
||||
WebPart Title| Text| no|
|
||||
Web Part Title| Text| no|
|
||||
Select Document Library| dropdown|yes
|
||||
Select Field to Group By | dropdown|yes
|
||||
|
||||
@ -57,6 +56,8 @@ Version|Date|Comments
|
||||
1.0.0|November 20, 2020|Initial release
|
||||
1.0.1|February 18, 2021|Added support for metadata columns
|
||||
1.0.2|February 21, 2021|Fixed `gulp build` issues
|
||||
1.0.3|October 25, 2021|Fixed bug support for metadata columns and Lookup fields
|
||||
1.0.4|October 31🦇, 2021|Upgraded to SPFx 1.13
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
@ -75,11 +76,15 @@ Version|Date|Comments
|
||||
**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.**
|
||||
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
We do not support samples, but we do use GitHub to track issues and constantly want to improve these samples.
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/labels/react-list-items-menu) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=label%3Areact-list-items-menu) and see what the community is saying.
|
||||
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-list-items-menu&authors=@joaojmendes%20@Ravikadri&title=react-list-items-menu%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-list-items-menu&authors=@joaojmendes%20@Ravikadri&title=react-list-items-menu%20-%20).
|
||||
|
@ -9,7 +9,7 @@
|
||||
"Allows user create a navigation menu , grouped by any column of document library. When the user clicks on the header it dynamically load documents."
|
||||
],
|
||||
"creationDateTime": "2021-02-18",
|
||||
"updateDateTime": "2021-02-18",
|
||||
"updateDateTime": "2021-10-31",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
@ -21,7 +21,7 @@
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.11.0"
|
||||
"value": "1.13.0"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-SUPPORTSTHEMEVARIANTS",
|
||||
@ -34,6 +34,14 @@
|
||||
{
|
||||
"key": "SPFX-TEAMSPERSONALAPP",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"key": "PNPCONTROLS",
|
||||
"value": "PropertyFieldListPicker, PropertyFieldMessage, PropertyFieldSpinner"
|
||||
},
|
||||
{
|
||||
"key": "REACT-HOOKS",
|
||||
"value": "true"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
@ -69,6 +77,13 @@
|
||||
"pictureUrl": "https://github.com/joaojmendes.png",
|
||||
"name": "Jo\u00E3o Mendes",
|
||||
"twitter": "joaojmendes"
|
||||
},
|
||||
{
|
||||
"gitHubAccount": "mohammadamer",
|
||||
"company": "Atea Global Services",
|
||||
"pictureUrl": "https://avatars.githubusercontent.com/u/19314043?s=460&u=79acb7fd0ad466e1040ddd8a739fa93385018b81&v=4",
|
||||
"name": "Mohammed Amer",
|
||||
"twitter": "Mohammad3mer"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user