Updated linting warnings, container, readme, sample manifest

This commit is contained in:
Hugo Bernier 2024-03-10 13:52:12 -04:00
parent 298ee7c40b
commit d463d11d78
11 changed files with 92 additions and 65 deletions

View File

@ -1,39 +1,38 @@
// For more information on how to run this SPFx project in a VS Code Remote Container, please visit https://aka.ms/spfx-devcontainer
{
"name": "SPFx 1.4.1",
"image": "docker.io/m365pnp/spfx:1.4.1",
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
4321,
35729,
5432
],
"portsAttributes": {
"4321": {
"protocol": "https",
"label": "Manifest",
"onAutoForward": "silent",
"requireLocalPort": true
},
"5432": {
"protocol": "https",
"label": "Workbench",
"onAutoForward": "silent"
},
"35729": {
"protocol": "https",
"label": "LiveReload",
"onAutoForward": "silent",
"requireLocalPort": true
}
},
"postCreateCommand": "bash .devcontainer/spfx-startup.sh",
"remoteUser": "node"
}
"name": "SPFx 1.18.2",
"image": "docker.io/m365pnp/spfx:1.18.2",
"customizations": {
"vscode": {
"extensions": [
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint"
]
}
},
"forwardPorts": [
4321,
35729,
5432
],
"portsAttributes": {
"4321": {
"protocol": "https",
"label": "Manifest",
"onAutoForward": "silent",
"requireLocalPort": true
},
"5432": {
"protocol": "https",
"label": "Workbench",
"onAutoForward": "silent"
},
"35729": {
"protocol": "https",
"label": "LiveReload",
"onAutoForward": "silent",
"requireLocalPort": true
}
},
"postCreateCommand": "bash .devcontainer/spfx-startup.sh",
"remoteUser": "node"
}

View File

@ -7,9 +7,11 @@ echo
echo -e "\e[1;94mGenerating dev certificate\e[0m"
gulp trust-dev-cert
# Convert the generated PEM certificate to a CER certificate
openssl x509 -inform PEM -in ~/.rushstack/rushstack-serve.pem -outform DER -out ./spfx-dev-cert.cer
cp ~/.gcb-serve-data/gcb-serve.cer ./spfx-dev-cert.cer
cp ~/.gcb-serve-data/gcb-serve.cer ./spfx-dev-cert.pem
# Copy the PEM ecrtificate for non-Windows hosts
cp ~/.rushstack/rushstack-serve.pem ./spfx-dev-cert.pem
## add *.cer to .gitignore to prevent certificates from being saved in repo
if ! grep -Fxq '*.cer' ./.gitignore

View File

@ -14,14 +14,18 @@ This web part shows an organization chart based on specified user, and user can
| :warning: Important |
|:---------------------------|
| Every SPFx version is only compatible with specific version(s) of Node.js. In order to be able to build this sample, please ensure that the version of Node on your workstation matches one of the versions listed in this section. This sample will not work on a different version of Node.|
| Every SPFx version is optimally compatible with specific versions of Node.js. In order to be able to build this sample, you need to ensure that the version of Node on your workstation matches one of the versions listed in this section. This sample will not work on a different version of Node.|
|Refer to <https://aka.ms/spfx-matrix> for more information on SPFx compatibility. |
![SPFx 1.4.1](https://img.shields.io/badge/SPFx-1.4.1-green.svg)
![Node.js v6 | v8](https://img.shields.io/badge/Node.js-LTS%206.x%20%7C%20v8-green.svg)
![SharePoint 2019 | Online](https://img.shields.io/badge/SharePoint-2019%20%7C%20Online-yellow.svg)
![Teams No: Not designed for Microsoft Teams](https://img.shields.io/badge/Teams-No-red.svg "Not designed for 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")
This sample is optimally compatible with the following environment configuration:
![SPFx 1.18.2](https://img.shields.io/badge/SPFx-1.18.2-green.svg)
![Node.js v16 | v18](https://img.shields.io/badge/Node.js-v16%20%7C%20v18-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)
![Compatible with Remote Containers](https://img.shields.io/badge/Remote%20Containers-Compatible-green.svg)
## Applies to
@ -30,14 +34,14 @@ This web part shows an organization chart based on specified user, and user can
## Contributors
- [João Mendes](https://github.com/joaojmendes), Storm Technology, ([@joaojmendes](https://twitter.com/joaojmendes))
- [Passoli Mirko](https://github.com/Paxol), Sicim S.p.A., ([Linkedin](https://www.linkedin.com/in/mirko-passoli))
- [João Mendes](https://github.com/joaojmendes)
- [Passoli Mirko](https://github.com/Paxol)
## Version history
|Version|Date|Comments|
|-------|----|--------|
|1.1|Feb, 2024|Guest user filter + update to latest sharepoint template|
|1.1|Feb, 2024|Guest user filter + update to SPFx 1.18.2|
|1.0|May, 2021|Initial release|
## Prerequisites

View File

@ -10,7 +10,7 @@
"Can be installed on SharePoint Server 2019, and SharePoint Online."
],
"creationDateTime": "2021-05-03",
"updateDateTime": "2021-05-03",
"updateDateTime": "2024-02-25",
"products": [
"SharePoint"
],
@ -21,7 +21,7 @@
},
{
"key": "SPFX-VERSION",
"value": "1.4.1"
"value": "1.18.2"
}
],
"thumbnails": [
@ -51,6 +51,10 @@
"pictureUrl": "https://github.com/joaojmendes.png",
"name": "João Mendes",
"twitter": "joaojmendes"
},
{
"gitHubAccount": "Paxol",
"pictureUrl": "https://github.com/Paxol.png"
}
],
"references": [

View File

@ -18,8 +18,10 @@ export const getUserPhoto = async (userId: string): Promise<string> => {
const personaImgUrl = PROFILE_IMAGE_URL + userId;
// tslint:disable-next-line: no-use-before-declare
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const url: string = await getImageBase64(personaImgUrl);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const newHash = await getMd5HashForUrl(url);
if (
@ -37,7 +39,7 @@ export const getUserPhoto = async (userId: string): Promise<string> => {
* @param url
*/
export const getMd5HashForUrl = async (url: string): Promise<Maybe<string>> => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-use-before-define
const library : any = await loadSPComponentById(MD5_MODULE_ID) ;
try {
const md5Hash = library.Md5Hash;
@ -71,6 +73,7 @@ export const getImageBase64 = async (pictureUrl: string): Promise<string> => {
const image = new Image();
image.addEventListener("load", () => {
const tempCanvas = document.createElement("canvas");
// eslint-disable-next-line no-unused-expressions, no-sequences
(tempCanvas.width = image.width),
(tempCanvas.height = image.height),
tempCanvas.getContext("2d")?.drawImage(image, 0, 0);

View File

@ -34,6 +34,7 @@ export const ExpandedCard: React.FunctionComponent<IExpandedCardProps> = (
return;
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
(async () => {
if (!user.manager) return;
@ -67,7 +68,7 @@ export const ExpandedCard: React.FunctionComponent<IExpandedCardProps> = (
<Text variant="smallPlus">{user.email}</Text>
</Link>
</Stack>
<div className={hoverCardStyles.separatorHorizontal}></div>
<div className={hoverCardStyles.separatorHorizontal} />
</>
)
}
@ -90,7 +91,7 @@ export const ExpandedCard: React.FunctionComponent<IExpandedCardProps> = (
<Text variant="smallPlus">{user.workPhone}</Text>
</Link>
</Stack>
<div className={hoverCardStyles.separatorHorizontal}></div>
<div className={hoverCardStyles.separatorHorizontal} />
</>
)}
{user.location && (
@ -133,7 +134,7 @@ export const ExpandedCard: React.FunctionComponent<IExpandedCardProps> = (
pictureUrl={manager.pictureUrl}
text={manager.displayName}
secondaryText={manager.title}
></Person>
/>
</>
)}
</Stack>

View File

@ -2,7 +2,7 @@ import { IButtonStyles, IDocumentCardActionsStyles, IStackStyles, mergeStyles, m
import type { Theme } from "spfx-uifabric-themes";
const currentTheme: Theme = window.__themeState__.theme;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/explicit-function-return-type
export const useHoverCardStyles = () => {
const stackPersonaStyles: Partial<IStackStyles> = {

View File

@ -99,11 +99,11 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
onUserSelected={onUserSelected}
selectedUser={currentUser}
showActionsBar={showActionsBar}
></PersonCard>
/>
<div
key={getGUID()}
className={orgChartClasses.separatorVertical}
></div>
/>
</>
);
}
@ -117,7 +117,7 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
onUserSelected={onUserSelected}
selectedUser={currentUser}
showActionsBar={showActionsBar}
></PersonCard>
/>
</>
);
}
@ -158,6 +158,7 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
);
React.useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
(async () => {
try {
if (startFromUserId === undefined) return;
@ -177,6 +178,7 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
}
const profileResponse = await getUserProfile(startFromUserId);
const wCurrentUser: IUserInfo = await manpingUserProperties(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
profileResponse!.currentUserProfile
);
dispatch({
@ -205,6 +207,7 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
}, [getUserProfile, startFromUserId]);
React.useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
(async () => {
if (!currentUser || !currentUser.id) return;
dispatch({
@ -251,7 +254,7 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
size={SpinnerSize.large}
label={"loading Organization Chart..."}
labelPosition={"bottom"}
></Spinner>
/>
</Stack>
</Overlay>
);
@ -284,15 +287,16 @@ export const OrgChart: React.FunctionComponent<IOrgChartProps> = (
{renderManagers}
<PersonCard
key={getGUID()}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
userInfo={currentUser!}
onUserSelected={onUserSelected}
selectedUser={currentUser}
showActionsBar={showActionsBar}
></PersonCard>
/>
{renderDirectReports.length && (
<>
<div className={orgChartClasses.separatorVertical}></div>
<div className={orgChartClasses.separatorHorizontal}></div>
<div className={orgChartClasses.separatorVertical} />
<div className={orgChartClasses.separatorHorizontal} />
</>
)}
</Stack>

View File

@ -2,7 +2,7 @@ import { mergeStyles, mergeStyleSets } from "@fluentui/react";
const currentTheme = window.__themeState__.theme;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/explicit-function-return-type
export const useOrgChartStyles = () => {
const orgChartClasses = mergeStyleSets({

View File

@ -2,7 +2,7 @@ import { IButtonStyles, IDocumentCardActionsStyles, IStackStyles, mergeStyles, m
import type { Theme } from "spfx-uifabric-themes";
const currentTheme: Theme = window.__themeState__.theme;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/explicit-function-return-type
export const usePersonaCardStyles = () => {
const stackPersonaStyles: Partial<IStackStyles> = {

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { sp, SPBatch } from "@pnp/sp/";
import { IUserInfo } from "../models/IUserInfo";
import * as React from "react";
@ -57,10 +58,12 @@ export const useGetUserProperties = (): {
// Get Direct Reports if exists
if (wDirectReports && wDirectReports.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
reportsLists = await getDirectReports(wDirectReports, showGuestUsers);
}
// Get Managers if exists
if (startUser && wExtendedManagers && wExtendedManagers.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
managersList = await getExtendedManagers(
wExtendedManagers,
loginNameStartUser!,
@ -88,10 +91,12 @@ const getDirectReports = async (
`${userReport}__orgchart__`
);
if (!cacheDirectReport) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
sp.profiles
.inBatch(batch)
.getPropertiesFor(userReport)
.then(async (directReport: IPersonProperties) => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const userInfo = await manpingUserProperties(directReport);
if (!showGuestUsers && userInfo.userType === "Guest") return;
@ -99,6 +104,7 @@ const getDirectReports = async (
await set(`${userReport}__orgchart__`, directReport);
});
} else {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const userInfo = await manpingUserProperties(cacheDirectReport);
if (!showGuestUsers && userInfo.userType === "Guest") continue;
@ -126,10 +132,12 @@ const getExtendedManagers = async (
`${manager}__orgchart__`
);
if (!cacheManager) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
sp.profiles
.inBatch(batch)
.getPropertiesFor(manager)
.then(async (_profile: IPersonProperties) => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const userInfo = await manpingUserProperties(_profile);
if (!showGuestUsers && userInfo.userType === "Guest") return;
@ -137,6 +145,7 @@ const getExtendedManagers = async (
await set(`${manager}__orgchart__`, _profile);
});
} else {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const userInfo = await manpingUserProperties(cacheManager);
if (!showGuestUsers && userInfo.userType === "Guest") continue;
@ -147,6 +156,7 @@ const getExtendedManagers = async (
return wManagers;
};
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function userTypeMapper(userType: string) {
switch (userType) {
case "0":