Skip to content

Commit

Permalink
Prosjektutlisting forbedringer på ytelse og innlasting (#1493)
Browse files Browse the repository at this point in the history
* Use react-window and AutoSizer to improve loading of projectList webpart

* Improve loading of project logos

* Minor adjustments

* Add missing package config

* Changelog

* Linting
  • Loading branch information
Remi749 authored Apr 5, 2024
1 parent fe1b1f4 commit df6690f
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 96 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Sjekk ut [release notes](./releasenotes/1.9.0.md) for høydepunkter og mer detal

- Lagt til muligheten for et summeringsfelt i prosjektstatusseksjoner, denne kan summere eller finne gjennomsnitt av verdier basert på en kolonne i en liste- eller usikkerhetsseksjon [#1485](https://github.com/Puzzlepart/prosjektportalen365/issues/1485)

### Forbedringer

- Forbedret ytelsen betraktelig og innlasting av store mengder prosjekter i prosjektutlisting webdel på forsiden av porteføljen [#1493](https://github.com/Puzzlepart/prosjektportalen365/pull/1493)

## 1.9.1 - TBA

### Feilrettinger
Expand Down
136 changes: 68 additions & 68 deletions SharePointFramework/PortfolioWebParts/config/config.json
Original file line number Diff line number Diff line change
@@ -1,71 +1,71 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"latest-projects-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/latestProjects/index.js",
"manifest": "./src/webparts/latestProjects/manifest.json"
}
]
},
"portfolio-insights-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/portfolioInsights/index.js",
"manifest": "./src/webparts/portfolioInsights/manifest.json"
}
]
},
"portfolio-overview-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/portfolioOverview/index.js",
"manifest": "./src/webparts/portfolioOverview/manifest.json"
}
]
},
"project-list-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/projectList/index.js",
"manifest": "./src/webparts/projectList/manifest.json"
}
]
},
"resource-allocation-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/resourceAllocation/index.js",
"manifest": "./src/webparts/resourceAllocation/manifest.json"
}
]
},
"project-timeline-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/projectTimeline/index.js",
"manifest": "./src/webparts/projectTimeline/manifest.json"
}
]
},
"portfolio-aggregation-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/portfolioAggregation/index.js",
"manifest": "./src/webparts/portfolioAggregation/manifest.json"
}
]
}
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"latest-projects-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/latestProjects/index.js",
"manifest": "./src/webparts/latestProjects/manifest.json"
}
]
},
"externals": {},
"localizedResources": {
"ControlStrings": "lib/loc/{locale}.js",
"PortfolioWebPartsStrings": "lib/loc/{locale}.js",
"PzlSPFxComponentsStrings": "lib/loc/{locale}.js",
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js",
"ProjectWebPartsStrings": "node_modules/pp365-projectwebparts/lib/loc/{locale}.js",
"SharedLibraryStrings": "node_modules/pp365-shared-library/lib/loc/{locale}.js"
"portfolio-insights-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/portfolioInsights/index.js",
"manifest": "./src/webparts/portfolioInsights/manifest.json"
}
]
},
"portfolio-overview-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/portfolioOverview/index.js",
"manifest": "./src/webparts/portfolioOverview/manifest.json"
}
]
},
"project-list-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/projectList/index.js",
"manifest": "./src/webparts/projectList/manifest.json"
}
]
},
"resource-allocation-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/resourceAllocation/index.js",
"manifest": "./src/webparts/resourceAllocation/manifest.json"
}
]
},
"project-timeline-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/projectTimeline/index.js",
"manifest": "./src/webparts/projectTimeline/manifest.json"
}
]
},
"portfolio-aggregation-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/portfolioAggregation/index.js",
"manifest": "./src/webparts/portfolioAggregation/manifest.json"
}
]
}
}
},
"externals": {},
"localizedResources": {
"ControlStrings": "lib/loc/{locale}.js",
"PortfolioWebPartsStrings": "lib/loc/{locale}.js",
"PzlSPFxComponentsStrings": "lib/loc/{locale}.js",
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js",
"ProjectWebPartsStrings": "node_modules/pp365-projectwebparts/lib/loc/{locale}.js",
"SharedLibraryStrings": "node_modules/pp365-shared-library/lib/loc/{locale}.js"
}
}
7 changes: 5 additions & 2 deletions SharePointFramework/PortfolioWebParts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
"@fluentui/react-icons": "~2.0.224",
"@fluentui/react-search-preview": "~0.1.33",
"use-image-color": "~0.0.9",
"react-error-boundary": "~4.0.11"
"react-error-boundary": "~4.0.11",
"react-window": "~1.8.10",
"react-virtualized-auto-sizer": "~1.0.24"
},
"devDependencies": {
"@microsoft/eslint-config-spfx": "1.17.4",
Expand Down Expand Up @@ -94,6 +96,7 @@
"typescript": "4.5.5",
"webpack": "5.74.0",
"@types/react-beautiful-dnd": "~13.1.4",
"@types/lodash": "~4.14.195"
"@types/lodash": "~4.14.195",
"@types/react-window": "~1.8.8"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import _ from 'lodash'
*/
function sortColumns({ columns, customColumnOrder, sortMode }: IEditViewColumnsPanelProps) {
return [...columns]
.filter((c) => c.data?.visibility ? c.data.visibility.includes('Portfolio') : true)
.filter((c) => (c.data?.visibility ? c.data.visibility.includes('Portfolio') : true))
.sort((a, b) => {
const columnOrderA = customColumnOrder.indexOf(a['id'])
const customColumnOrderIndexB = customColumnOrder.indexOf(b['id'])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import React, { FC, useCallback, useContext } from 'react'
import { ProjectCardContext } from '../context'
import styles from './ProjectCardHeader.module.scss'
import { useProjectCardHeader } from './useProjectCardHeader'
import { ProjectLogo } from 'pp365-shared-library/lib/components'
import { IProjectCardHeaderProps } from './types'
import { ProjectLogo } from 'pp365-shared-library'

export const ProjectCardHeader: FC<IProjectCardHeaderProps> = (props) => {
const context = useContext(ProjectCardContext)
Expand All @@ -14,7 +14,7 @@ export const ProjectCardHeader: FC<IProjectCardHeaderProps> = (props) => {
* Callback function to set the showCustomImage state.
*/
const customImageCallback = useCallback(
(value) => {
(value: boolean) => {
setShowCustomImage(value)
},
[context.showProjectLogo, showCustomImage]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import styles from './ProjectCardHeader.module.scss'

export function useProjectCardHeader() {
const context = useContext(ProjectCardContext)
const [showCustomImage, setShowCustomImage] = useState(true)
const [showCustomImage, setShowCustomImage] = useState(false)

const imageColorData = useImageColor(
context.project.logo ?? `${context.project.url}/_api/siteiconmanager/getsitelogo?type='1'`,
{ cors: true, colors: 2, windowSize: 5 }
)
const imageUrl = `${context.project.url}/_api/siteiconmanager/getsitelogo?type='1'`
const imageColorData = context.useDynamicColors
? context.project.logo ?? useImageColor(imageUrl, { cors: true, colors: 2, windowSize: 5 })
: null

const colors =
context.useDynamicColors && context.showProjectLogo
? imageColorData.colors
? imageColorData?.colors ?? ['transparent', 'transparent']
: ['transparent', 'transparent']

const headerProps: HTMLProps<HTMLDivElement> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
.commandBar {
display: flex;
flex-direction: row;
max-width: 996px;
max-width: 1024px;
gap: 15px;

.search {
Expand Down Expand Up @@ -44,7 +44,22 @@
display: flex;
flex-wrap: wrap;
flex-direction: row;
max-width: 996px;
max-width: 1024px;
gap: 12px;

.projectsSection {
width: 100%;
overflow-x: hidden !important;

.projectRow {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
align-content: flex-start;
gap: 12px;
left: 4px !important;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { SearchBox } from '@fluentui/react-search-preview'
import * as strings from 'PortfolioWebPartsStrings'
import { ProjectInformationPanel } from 'pp365-projectwebparts/lib/components/ProjectInformationPanel'
import { ProjectListModel, SiteContext, customLightTheme } from 'pp365-shared-library'
import React, { FC } from 'react'
import React, { FC, useMemo } from 'react'
import { find, isEmpty } from 'underscore'
import { List } from './List'
import { ListContext } from './List/context'
Expand All @@ -20,6 +20,8 @@ import { ProjectListVerticals } from './ProjectListVerticals'
import { IProjectListProps } from './types'
import { useProjectList } from './useProjectList'
import { Toolbar, UserMessage } from 'pp365-shared-library'
import { FixedSizeList } from 'react-window'
import AutoSizer from 'react-virtualized-auto-sizer'

export const ProjectList: FC<IProjectListProps> = (props) => {
const {
Expand All @@ -39,14 +41,62 @@ export const ProjectList: FC<IProjectListProps> = (props) => {
*
* @param projects - Projects to render
*/
function renderProjects(projects: ProjectListModel[]) {
const renderProjects = (projects: ProjectListModel[]) => {
const projectRow: FC<{ index: number; style: React.CSSProperties; itemsPerRow: number }> = ({
index,
style,
itemsPerRow
}) => {
const items = useMemo(() => {
const convertedIndex = index * itemsPerRow
const employeeItems = []

employeeItems.push(
...projects
.slice(convertedIndex, convertedIndex + itemsPerRow)
.filter(Boolean)
.map((project, idx) => (
<ProjectCardContext.Provider key={idx} value={createCardContext(project)}>
<ProjectCard />
</ProjectCardContext.Provider>
))
)
return employeeItems
}, [itemsPerRow])

return (
<div className={styles.projectRow} key={index} style={style}>
{items}
</div>
)
}

switch (state.renderMode) {
case 'tiles': {
return projects.map((project, idx) => (
<ProjectCardContext.Provider key={idx} value={createCardContext(project)}>
<ProjectCard />
</ProjectCardContext.Provider>
))
return (
<AutoSizer disableHeight style={{ width: '100%' }}>
{({ width }) => {
const cardWidth = 242
const itemsPerRow = Math.floor(width / cardWidth)
const itemCount = Math.ceil(projects.length / itemsPerRow)
const listHeight = Math.ceil(itemCount * 300)

return (
<FixedSizeList
className={styles.projectsSection}
style={{ gap: 12 }}
height={listHeight < 880 ? listHeight : 880}
itemCount={itemCount}
overscanCount={2}
itemSize={290}
width={width}
>
{({ index, style }) => projectRow({ index, style, itemsPerRow })}
</FixedSizeList>
)
}}
</AutoSizer>
)
}
case 'list':
case 'compactList': {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IProjectLogoProps } from './types'
* @returns An object containing the conditional styling based on project logo render mode.
*/
export function useProjectLogo(props: IProjectLogoProps) {
const [showCustomImage, setShowCustomImage] = useState(true)
const [showCustomImage, setShowCustomImage] = useState(false)

/**
* Checks if the image is a custom image.
Expand Down
Loading

0 comments on commit df6690f

Please sign in to comment.