Merge pull request #2090 from joaojmendes/fix-bug-#1719-ListMenu-Items

This commit is contained in:
Hugo Bernier 2021-10-31 15:26:49 -04:00 committed by GitHub
commit 8b762f7a19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 123 additions and 20 deletions

View File

@ -11,6 +11,7 @@ dist
lib
solution
temp
release
*.sppkg
# Coverage directory used by tools like istanbul
@ -30,4 +31,4 @@ obj
# Styles Generated Code
*.scss.ts
*.scss.d.ts
*.scss.d.ts

View File

@ -17,25 +17,24 @@ 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.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)
![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")
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "The solution needs access to APIs")
![Hosted Workbench Compatible (with permissions)](https://img.shields.io/badge/Hosted%20Workbench-Compatible%20(with%20permissions)-yellow.svg "The solution needs access to APIs")
## 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)
## 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,7 @@ 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
## Minimal Path to Awesome
@ -75,7 +75,6 @@ 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.

View File

@ -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-25",
"products": [
"SharePoint",
"Office"
@ -34,6 +34,14 @@
{
"key": "SPFX-TEAMSPERSONALAPP",
"value": "true"
},
{
"key": "PNPCONTROLS",
"value": "PropertyFieldListPicker, PropertyFieldMessage, PropertyFieldSpinner"
},
{
"key": "REACT-HOOKS",
"value": "true"
}
],
"thumbnails": [

View File

@ -3,7 +3,7 @@
"solution": {
"name": "react-list-items-menu-client-side-solution",
"id": "8b4a758d-a968-4e7c-a949-b42e7dd5ad14",
"version": "1.0.2.0",
"version": "1.0.3.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false,

View File

@ -1,6 +1,6 @@
{
"name": "react-list-items-menu",
"version": "1.0.1",
"version": "1.0.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -8342,6 +8342,11 @@
}
}
},
"date-fns": {
"version": "2.25.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz",
"integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w=="
},
"dateformat": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",

View File

@ -1,6 +1,6 @@
{
"name": "react-list-items-menu",
"version": "1.0.2",
"version": "1.0.3",
"private": true,
"main": "lib/index.js",
"engines": {
@ -26,6 +26,7 @@
"@pnp/spfx-property-controls": "1.19.0",
"@types/jquery": "^3.5.0",
"@uifabric/file-type-icons": "^7.6.11",
"date-fns": "^2.25.0",
"jquery": "^3.5.1",
"jsstore": "^3.10.3",
"moment": "^2.29.1",

View File

@ -158,3 +158,11 @@ export const convertTimeTo24h = (
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);
};

View File

@ -69,7 +69,86 @@ export const ListItemsMenu: React.FunctionComponent<IListItemsMenuProps> = (
const stateRef = React.useRef(state); // Use to access state on eventListenners
// On component did mount only if listId or Field Change
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,
onHeaderClick: _onGroupHeaderClick,
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 component did mount only if listId or Field Change
React.useEffect(() => {
(async () => {
if (!props.listId || !props.fieldName) {
@ -142,7 +221,7 @@ export const ListItemsMenu: React.FunctionComponent<IListItemsMenuProps> = (
setState(stateRef.current);
}
})();
}, [props.listId, props.fieldName]);
}, [props.listId, props.fieldName]); */
// On Header click get Items for the header
const _onGroupHeaderClick = async (

View File

@ -9,7 +9,8 @@ import moment from "moment";
import { sp } from "@pnp/sp";
import { IFieldInfo } from "@pnp/sp/fields";
import { IListInfo } from "@pnp/sp/lists";
import { checkIfValidDate } from "../Utils/Utils";
import {format , parseISO} from 'date-fns';
export const useList = () => {
// Run on useList hook
(async () => {})();
@ -71,12 +72,14 @@ export const useList = () => {
): 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"
? moment(groupFieldValue).format("YYYY-MM-DD")
: "Unassigned";
groupFieldValue != "Unassigned" ? format(parseISO(groupFieldValue), "yyyy-MM-dd") : "Unassigned";
break;
case "AllDayEvent":
groupFieldValue = groupFieldValue === "No" ? "0" : "1";
@ -84,7 +87,6 @@ export const useList = () => {
default:
break;
}
let _viewXml = `<View Scope='Recursive'>
<Query>
<OrderBy>