added react-display-hierarchy (#673)
This commit is contained in:
parent
f1359c18cc
commit
e2dd322679
|
@ -0,0 +1,25 @@
|
|||
# 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
|
|
@ -0,0 +1,32 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
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
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.6.0",
|
||||
"libraryName": "spfx-react-hierarchy-view",
|
||||
"libraryId": "2fd9a018-0cd9-4cca-9e84-4fac64b83333",
|
||||
"packageManager": "npm",
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
## Web part displaying hierarchical information from SharePoint list
|
||||
|
||||
### Summary
|
||||
At the time of developing this sample, the Office 365 UI fabric does not have any control for displaying hierarchical information. This web part helps to display the hierarchical information from SharePoint list.
|
||||
|
||||
![Web part preview][figure1]
|
||||
|
||||
The web part is configured to render the mock data when added to local SharePoint workbench.
|
||||
![Local SharePoint Workbench Run][figure2]
|
||||
|
||||
When added to SharePoint site, the source list containing hierarchical information can be configured from web part properties.
|
||||
The sample also provisions the list called “Hierarchy” which can be used as an example to start using the web part.
|
||||
![SharePoint Run][figure3]
|
||||
|
||||
### SharePoint Asset
|
||||
A SharePoint list (named Hierarchy) is provisioned to store the hierarchical data. The schema of the list is as below.
|
||||
![List Schema][figure4]
|
||||
The Parent column is a lookup on same list’s Title column.
|
||||
|
||||
The solution also provisions sample data to the Hierarchy list.
|
||||
![List Sample Data][figure5]
|
||||
|
||||
### NPM Packages Used
|
||||
Below NPM packages are used to develop this sample.
|
||||
1. sp-pnp-js (https://www.npmjs.com/package/sp-pnp-js)
|
||||
2. react-orgchart (https://www.npmjs.com/package/react-orgchart)
|
||||
3. array-to-tree (https://www.npmjs.com/package/array-to-tree)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-1.6-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework Developer Preview](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
|
||||
* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant)
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-display-hierarchy|[Nanddeep Nachan](https://www.linkedin.com/in/nanddeepnachan/) (SharePoint Consultant, [@NanddeepNachan](https://http://twitter.com/NanddeepNachan) )
|
||||
|[Ravi Kulkarni](https://www.linkedin.com/in/ravi-kulkarni-a5381723/) (SharePoint Consultant)
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0|October 15, 2018|Initial release
|
||||
|
||||
## 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.**
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- SharePoint Online tenant
|
||||
- Site Collection created under the **/sites/** or **/**
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
- Clone this repo
|
||||
- npm i
|
||||
- gulp serve --nobrowser
|
||||
- Open workbench on your tennant, ie. https://contoso.sharepoint.com/sites/salestesm/_layouts/15/workbench.aspx
|
||||
- Search and add web part "Display Hierarchy"
|
||||
|
||||
## Features
|
||||
This sample web part shows how data stored in SharePoint list can be transformed to show hierarchical information
|
||||
- Rendering hierarchical information
|
||||
- SharePoint assets provisioning
|
||||
- Creating extensible services
|
||||
- Using mock data to test the web part locally
|
||||
- Using @sp-pnp-js
|
||||
- Using @react-orgchart
|
||||
- Using @array-to-tree
|
||||
|
||||
|
||||
[figure1]: ./assets/webpart-preview.png
|
||||
[figure2]: ./assets/local-sharepoint-workbench-run.png
|
||||
[figure3]: ./assets/sharepoint-run.gif
|
||||
[figure4]: ./assets/list-schema.png
|
||||
[figure5]: ./assets/list-sample-data.png
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
After Width: | Height: | Size: 95 KiB |
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"react-hierarchy-view-web-part": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/reactHierarchyView/ReactHierarchyViewWebPart.js",
|
||||
"manifest": "./src/webparts/reactHierarchyView/ReactHierarchyViewWebPart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"ReactHierarchyViewWebPartStrings": "lib/webparts/reactHierarchyView/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "spfx-react-hierarchy-view",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "spfx-react-hierarchy-view-client-side-solution",
|
||||
"id": "2fd9a018-0cd9-4cca-9e84-4fac64b83333",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"features": [
|
||||
{
|
||||
"title": "react-display-hierarchy-deployment",
|
||||
"description": "react-display-hierarchy-deployment",
|
||||
"id": "c99c6e2c-f45c-41f4-84b4-f05f2031eab3",
|
||||
"version": "1.0.0.0",
|
||||
"assets": {
|
||||
"elementManifests": [
|
||||
"elements.xml"
|
||||
],
|
||||
"elementFiles": [
|
||||
"schema.xml"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/spfx-react-hierarchy-view.sppkg"
|
||||
}
|
||||
}
|
|
@ -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 -->"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
'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);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "spfx-react-hierarchy-view",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.6.0",
|
||||
"@microsoft/sp-lodash-subset": "1.6.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.6.0",
|
||||
"@microsoft/sp-webpart-base": "1.6.0",
|
||||
"@pnp/common": "^1.2.3",
|
||||
"@pnp/graph": "^1.2.3",
|
||||
"@pnp/logging": "^1.2.3",
|
||||
"@pnp/odata": "^1.2.3",
|
||||
"@pnp/sp": "^1.2.3",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "15.6.6",
|
||||
"@types/react-dom": "15.5.6",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"array-to-tree": "^3.3.0",
|
||||
"react": "15.6.2",
|
||||
"react-dom": "15.6.2",
|
||||
"react-orgchart": "^1.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.6.0",
|
||||
"@microsoft/sp-module-interfaces": "1.6.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.6.0",
|
||||
"tslint-microsoft-contrib": "~5.0.0",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"ajv": "~5.2.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
|
||||
|
||||
<ListInstance
|
||||
CustomSchema="schema.xml"
|
||||
FeatureId="00bfea71-de22-43b2-a848-c05709900100"
|
||||
Title="Hierarchy"
|
||||
Description="List with hierarchy information"
|
||||
TemplateType="100"
|
||||
Url="Lists/Hierarchy">
|
||||
<Data>
|
||||
<Rows>
|
||||
<Row>
|
||||
<Field Name="Title">Director of Human Resources</Field>
|
||||
<Field Name="Parent"></Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Compensation Analysis</Field>
|
||||
<Field Name="Parent">1;#Director of Human Resources</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Risk Management</Field>
|
||||
<Field Name="Parent">1;#Director of Human Resources</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Employee Relations</Field>
|
||||
<Field Name="Parent">1;#Director of Human Resources</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Staffing</Field>
|
||||
<Field Name="Parent">1;#Director of Human Resources</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Job Evaluation</Field>
|
||||
<Field Name="Parent">2;#Compensation Analysis</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Salary Board</Field>
|
||||
<Field Name="Parent">2;#Compensation Analysis</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Merit Admin</Field>
|
||||
<Field Name="Parent">2;#Compensation Analysis</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Emergency Procedures</Field>
|
||||
<Field Name="Parent">3;#Risk Management</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Safety Program</Field>
|
||||
<Field Name="Parent">3;#Risk Management</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Grievance Procedure</Field>
|
||||
<Field Name="Parent">4;#Employee Relations</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Client Consultations</Field>
|
||||
<Field Name="Parent">4;#Employee Relations</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Job Posting</Field>
|
||||
<Field Name="Parent">5;#Staffing</Field>
|
||||
</Row>
|
||||
<Row>
|
||||
<Field Name="Title">Application Screening</Field>
|
||||
<Field Name="Parent">5;#Staffing</Field>
|
||||
</Row>
|
||||
</Rows>
|
||||
</Data>
|
||||
</ListInstance>
|
||||
|
||||
</Elements>
|
|
@ -0,0 +1,31 @@
|
|||
<List xmlns:ows="Microsoft SharePoint" Title="Hierarchy" EnableContentTypes="TRUE" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/Hierarchy" BaseType="0" xmlns="http://schemas.microsoft.com/sharepoint/">
|
||||
<MetaData>
|
||||
<Fields>
|
||||
<Field ID="{6C798145-A205-4FC4-8175-837B0F7744CC}" Type="Lookup" DisplayName="Parent" Required="false" List="Lists/Hierarchy" ShowField="Title" UnlimitedLengthInDocumentLibrary="TRUE" StaticName="Parent" Name="Parent" Version="1" />
|
||||
<Field ID="{c29e077d-f466-4d8e-8bbe-72b66c5f205c}" Name="URL" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="URL" Group="Base Columns" Type="URL" DisplayName="URL" AllowDeletion="TRUE" ColName="nvarchar4" RowOrdinal="0" ColName2="nvarchar5" RowOrdinal2="0" />
|
||||
</Fields>
|
||||
<Views>
|
||||
<View BaseViewID="1" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/generic.png" Url="AllItems.aspx">
|
||||
<XslLink Default="TRUE">main.xsl</XslLink>
|
||||
<JSLink>clienttemplates.js</JSLink>
|
||||
<RowLimit Paged="TRUE">30</RowLimit>
|
||||
<Toolbar Type="Standard" />
|
||||
<ViewFields>
|
||||
<FieldRef Name="LinkTitle"></FieldRef>
|
||||
<FieldRef Name="Parent"></FieldRef>
|
||||
<FieldRef Name="URL"></FieldRef>
|
||||
</ViewFields>
|
||||
<Query>
|
||||
<OrderBy>
|
||||
<FieldRef Name="Title" />
|
||||
</OrderBy>
|
||||
</Query>
|
||||
</View>
|
||||
</Views>
|
||||
<Forms>
|
||||
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
|
||||
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
|
||||
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
|
||||
</Forms>
|
||||
</MetaData>
|
||||
</List>
|
|
@ -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": "a0696899-5523-4520-9744-acbb0bae821f",
|
||||
"alias": "ReactHierarchyViewWebPart",
|
||||
"componentType": "WebPart",
|
||||
// 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,
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": {
|
||||
"default": "Other"
|
||||
},
|
||||
"title": {
|
||||
"default": "Display Hierarchy"
|
||||
},
|
||||
"description": {
|
||||
"default": "Display hierarchical view from SharePoint list"
|
||||
},
|
||||
"officeFabricIconFontName": "GitGraph",
|
||||
"properties": {
|
||||
"description": "ReactHierarchyView"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
|
||||
import * as strings from 'ReactHierarchyViewWebPartStrings';
|
||||
import ReactHierarchyView from './components/ReactHierarchyView';
|
||||
import { IReactHierarchyViewProps } from './components/IReactHierarchyViewProps';
|
||||
import {
|
||||
Environment,
|
||||
EnvironmentType,
|
||||
ServiceScope
|
||||
} from '@microsoft/sp-core-library';
|
||||
|
||||
// sp-pnp-js for SPFx context configuration
|
||||
import * as pnp from "@pnp/sp";
|
||||
|
||||
export interface IReactHierarchyViewWebPartProps {
|
||||
listName: string;
|
||||
}
|
||||
|
||||
export default class ReactHierarchyViewWebPart extends BaseClientSideWebPart<IReactHierarchyViewWebPartProps> {
|
||||
|
||||
public async onInit(): Promise<void> {
|
||||
return super.onInit().then(_ => {
|
||||
pnp.sp.setup({
|
||||
spfxContext: this.context
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<IReactHierarchyViewProps> = React.createElement(
|
||||
ReactHierarchyView,
|
||||
{
|
||||
serviceScope: this.context.serviceScope,
|
||||
listName: this.properties.listName
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('listName', {
|
||||
label: strings.DescriptionFieldLabel
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import { ServiceScope } from '@microsoft/sp-core-library';
|
||||
|
||||
export interface IReactHierarchyViewProps {
|
||||
serviceScope: ServiceScope;
|
||||
listName: string;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
|
||||
@import '~react-orgchart/index.css';
|
||||
|
||||
:global(#workbenchPageContent) {
|
||||
max-width: initial;
|
||||
}
|
||||
|
||||
:global(.initechNode) {
|
||||
border: 1px solid;
|
||||
border-radius: 3px;
|
||||
padding: 5px;
|
||||
margin: 1px;
|
||||
display: inline-block;
|
||||
background: #005a9e;
|
||||
}
|
||||
|
||||
:global(#initechOrgChart .orgNodeChildGroup .nodeGroupLineVerticalMiddle) {
|
||||
border-right: solid 3px #005a9e
|
||||
}
|
||||
|
||||
:global(#initechOrgChart .nodeLineBorderTop) {
|
||||
border-top: solid 3px #005a9e;
|
||||
}
|
||||
|
||||
:global(.reactOrgChart .nodeLineBorderTop) {
|
||||
border-top: 2px solid #005a9e;
|
||||
}
|
||||
|
||||
:global(.reactOrgChart .orgNodeChildGroup .nodeGroupLineVerticalMiddle) {
|
||||
border-right: 2px solid #005a9e;
|
||||
}
|
||||
|
||||
.reactHierarchyView {
|
||||
.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;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.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,127 @@
|
|||
import * as React from 'react';
|
||||
import styles from './ReactHierarchyView.module.scss';
|
||||
import { IReactHierarchyViewProps } from './IReactHierarchyViewProps';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import { IHierarchyService } from '../interfaces';
|
||||
import { IHierarchyItem, Item } from '../interfaces/IHierarchyItem';
|
||||
import OrgChart from 'react-orgchart';
|
||||
import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
|
||||
|
||||
import { HierarchyService } from '../services';
|
||||
import { MockHierarchyService } from '../mocks';
|
||||
import { ServiceScope, Environment, EnvironmentType } from '@microsoft/sp-core-library';
|
||||
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
|
||||
|
||||
export interface IReactHierarchyState {
|
||||
hierarchyItems: any;
|
||||
isLoading: boolean;
|
||||
showErrorMessage: boolean;
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
export default class ReactHierarchyView extends React.Component<IReactHierarchyViewProps, IReactHierarchyState> {
|
||||
private HierarchyServiceInstance: IHierarchyService;
|
||||
private _listName: string;
|
||||
constructor(props: IReactHierarchyViewProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hierarchyItems: null,
|
||||
isLoading: true,
|
||||
showErrorMessage: false,
|
||||
errorMessage: ""
|
||||
};
|
||||
|
||||
let serviceScope: ServiceScope;
|
||||
serviceScope = this.props.serviceScope;
|
||||
this._listName = this.props.listName;
|
||||
|
||||
// Based on the type of environment, return the correct instance of the IHierarchyServiceInstance interface
|
||||
if (Environment.type == EnvironmentType.SharePoint || Environment.type == EnvironmentType.ClassicSharePoint) {
|
||||
// Mapping to be used when webpart runs in SharePoint.
|
||||
this.HierarchyServiceInstance = serviceScope.consume(HierarchyService.serviceKey);
|
||||
}
|
||||
else {
|
||||
// This means webpart is running in the local workbench or from a unit test.
|
||||
// So we will need a non default implementation of the IHierarchyServiceInstance i.e. MockHierarchyService
|
||||
this.HierarchyServiceInstance = serviceScope.consume(MockHierarchyService.serviceKey);
|
||||
}
|
||||
|
||||
this.HierarchyServiceInstance.getHierarchyInfo(this._listName).then((hierarchyItems: any) => {
|
||||
if (Environment.type == EnvironmentType.SharePoint || Environment.type == EnvironmentType.ClassicSharePoint) {
|
||||
if (hierarchyItems.length > 0) {
|
||||
let hierarchyNodes: Array<Item> = [];
|
||||
var count: number;
|
||||
|
||||
for (count = 0; count < hierarchyItems.length; count++) {
|
||||
hierarchyNodes.push(new Item(hierarchyItems[count].Id, hierarchyItems[count].Title, hierarchyItems[count].Url, hierarchyItems[count].Parent ? hierarchyItems[count].Parent.Id : undefined));
|
||||
}
|
||||
|
||||
var arrayToTree: any = require('array-to-tree');
|
||||
var orgChartHierarchyNodes: any = arrayToTree(hierarchyNodes);
|
||||
|
||||
var output: any = JSON.stringify(orgChartHierarchyNodes[0]);
|
||||
|
||||
this.setState({
|
||||
hierarchyItems: JSON.parse(output),
|
||||
isLoading: false
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
showErrorMessage: true,
|
||||
errorMessage: "No records to be displayed"
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.setState({
|
||||
hierarchyItems: JSON.parse(hierarchyItems),
|
||||
isLoading: false
|
||||
});
|
||||
}
|
||||
}).catch((error) =>
|
||||
this.setState({
|
||||
errorMessage: "Please verify webpart configuration. Error details: " + error.message,
|
||||
isLoading: false,
|
||||
showErrorMessage: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IReactHierarchyViewProps> {
|
||||
return (
|
||||
<div className={styles.reactHierarchyView}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.row}>
|
||||
<div className={styles.column}>
|
||||
{this.state.isLoading && <Spinner label="Loading Hierarchy View..." />}
|
||||
{this.state.hierarchyItems &&
|
||||
<OrgChart tree={this.state.hierarchyItems} NodeComponent={this.MyNodeComponent} />
|
||||
}
|
||||
</div>
|
||||
{this.state.showErrorMessage &&
|
||||
<MessageBar messageBarType={MessageBarType.warning} isMultiline={false} dismissButtonAriaLabel="Close">
|
||||
{this.state.errorMessage}</MessageBar>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private MyNodeComponent = ({ node }) => {
|
||||
if (node.url) {
|
||||
return (
|
||||
<div className="initechNode">
|
||||
<a href={node.url.Url} className={styles.link} >{node.title}</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<div className="initechNode">{node.title}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
export interface IHierarchyItem {
|
||||
Title: string;
|
||||
Id: number;
|
||||
parent_id: number;
|
||||
Url?: string;
|
||||
Parent: any;
|
||||
}
|
||||
|
||||
export class Item {
|
||||
private id: number;
|
||||
private title: string;
|
||||
private url: string;
|
||||
private parent_id?: number;
|
||||
|
||||
constructor(id: number, title: string, url: string, parent_id?: number) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.parent_id = parent_id;
|
||||
this.url = url;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
|
||||
export interface IHierarchyService {
|
||||
getHierarchyInfo: (listName?: string) => Promise<any>;
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { IHierarchyService } from './IHierarchyService';
|
|
@ -0,0 +1,7 @@
|
|||
define([], function () {
|
||||
return {
|
||||
"PropertyPaneDescription": "Hierarchy View List Configuration",
|
||||
"BasicGroupName": "Group Name",
|
||||
"DescriptionFieldLabel": "List Name"
|
||||
}
|
||||
});
|
10
samples/react-display-hierarchy/src/webparts/reactHierarchyView/loc/mystrings.d.ts
vendored
Normal file
10
samples/react-display-hierarchy/src/webparts/reactHierarchyView/loc/mystrings.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
declare interface IReactHierarchyViewWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'ReactHierarchyViewWebPartStrings' {
|
||||
const strings: IReactHierarchyViewWebPartStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import { IHierarchyService } from '../interfaces';
|
||||
import { ServiceScope, ServiceKey } from '@microsoft/sp-core-library';
|
||||
|
||||
export class MockHierarchyService implements IHierarchyService {
|
||||
public static readonly serviceKey: ServiceKey<IHierarchyService> = ServiceKey.create<IHierarchyService>('datacenter:MockHierarchyService', MockHierarchyService);
|
||||
constructor(serviceScope: ServiceScope) {
|
||||
}
|
||||
|
||||
public getHierarchyInfo(listName: string): Promise<any> {
|
||||
const initechOrg: any =
|
||||
{
|
||||
id: 1,
|
||||
title: "Microsoft",
|
||||
url: {Description: "Microsoft", Url: "http://www.microsoft.com"},
|
||||
children:[
|
||||
{
|
||||
id: 2,
|
||||
title: "CMS",
|
||||
url: null,
|
||||
parent_id: 1,
|
||||
children:[
|
||||
{ id: 3, title: "SharePoint", parent_id: 2, url: null },
|
||||
{ id: 5, title: "DotNetNuke", parent_id: 2, url: null },
|
||||
{ id: 6, title: "Sitefinity", parent_id: 2, url: null }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: "E-Commerce",
|
||||
url: null,
|
||||
parent_id: 1,
|
||||
children:[
|
||||
{ id: 8, title: "nopCommerce", parent_id: 7, url: null },
|
||||
{ id: 9, title: "asp.net storetront", parent_id: 7, url: null }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
title: "3rd Party",
|
||||
url: null,
|
||||
parent_id: 1,
|
||||
children:[
|
||||
{ id: 11, title: "Telerik", parent_id: 10, url: null },
|
||||
{ id: 12, title: "DevExpress", parent_id: 10, url: null }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
;
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
resolve(JSON.stringify(initechOrg));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { MockHierarchyService } from './MockHierarchyService';
|
|
@ -0,0 +1,29 @@
|
|||
import { IHierarchyService } from '../interfaces';
|
||||
import { ServiceKey, ServiceScope } from '@microsoft/sp-core-library';
|
||||
import { PageContext } from '@microsoft/sp-page-context';
|
||||
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
|
||||
import { IHierarchyItem } from '../interfaces/IHierarchyItem';
|
||||
import * as pnp from "@pnp/sp";
|
||||
|
||||
export class HierarchyService implements IHierarchyService {
|
||||
public static readonly serviceKey: ServiceKey<IHierarchyService> = ServiceKey.create<IHierarchyService>('datacenter:hierarchyService', HierarchyService);
|
||||
|
||||
private _spHttpClient: SPHttpClient;
|
||||
private _pageContext: PageContext;
|
||||
private _currentWebUrl: string;
|
||||
|
||||
constructor(serviceScope: ServiceScope) {
|
||||
serviceScope.whenFinished(() => {
|
||||
this._spHttpClient = serviceScope.consume(SPHttpClient.serviceKey);
|
||||
this._pageContext = serviceScope.consume(PageContext.serviceKey);
|
||||
this._currentWebUrl = this._pageContext.web.absoluteUrl;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public getHierarchyInfo(listName: string): Promise<IHierarchyItem[]> {
|
||||
return pnp.sp.web.lists.getByTitle(listName).items.select('Title,Id,URL,Parent/Id,Parent/Title&$expand=Parent/Id').get().then((items: IHierarchyItem[]) => {
|
||||
return Promise.resolve(items);
|
||||
}).catch((error) => Promise.reject(error));
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { HierarchyService } from './HierarchyService';
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"lib"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"rulesDirectory": [
|
||||
"tslint-microsoft-contrib"
|
||||
],
|
||||
"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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue