Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visninger for programmer i Porteføljeoversikt #1140

Merged
merged 13 commits into from
May 25, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Sjekk ut [release notes](./releasenotes/1.8.0.md) for høydepunkter og mer detal
- Støtte for tooltip-kolonne i porteføljeoversikten [#1079](https://github.com/Puzzlepart/prosjektportalen365/issues/1079)
- Prosjektscoring og idékonfigurasjon for å støtte flere forskjellige idéoppsett [#1082](https://github.com/Puzzlepart/prosjektportalen365/issues/1082)
- Støtte for egendefinerte rekkefølger for kolonner i porteføljeoversikten [#1114](https://github.com/Puzzlepart/prosjektportalen365/issues/1114)
- Visninger for programmer i Porteføljeoversikt [#933](https://github.com/Puzzlepart/prosjektportalen365/issues/933)

### Forbedringer

Expand Down
4 changes: 2 additions & 2 deletions SharePointFramework/@Shared/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion SharePointFramework/@Shared/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pp365-shared",
"version": "1.9.0-1128.20",
"version": "1.9.0-1140.1",
"repository": {
"type": "git",
"url": "https://github.com/Puzzlepart/prosjektportalen365.git",
Expand Down
122 changes: 113 additions & 9 deletions SharePointFramework/@Shared/src/models/PortfolioOverviewView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,91 @@ export class SPPortfolioOverviewViewItem {
}

export class PortfolioOverviewView {
public id: number
/**
* ID of the view. This can be a string or a number. If it's a
* number it's typically the SharePoint list item ID.
*/
public id: string | number

/**
* Title of the view.
*/
public title: string

/**
* Sort order for the view. This property is set when the view is
* configured with a sort order.
*/
public sortOrder: number

/**
* Search query for the view. This property is set when the view is
* configured with a search query.
*/
public searchQuery: string

/**
* Array of search queries for the view. This properties is set in
* special cases where the query text is too long to fit in the
* `searchQuery` property.
*/
public searchQueries: string[]

/**
* `true` if the view is the default view, `false` otherwise.
*/
public isDefaultView: boolean

/**
* Icon name for the view.
*/
public iconName: string

/**
* `true` if the view is a personal view, `false` otherwise.
*/
public isPersonal: boolean

/**
* Columns for the view.
*/
public columns: ProjectColumn[]

/**
* Refiners for the view.
*/
public refiners: ProjectColumn[]

/**
* Column to group by.
*/
public groupBy?: ProjectColumn

/**
* Scope of the view (not sure of the current usage of this property).
*/
public scope?: string

constructor(private _item: SPPortfolioOverviewViewItem) {
this.id = _item.Id
this.title = _item.Title
this.sortOrder = _item.GtSortOrder
this.searchQuery = _item.GtSearchQuery
this.isDefaultView = _item.GtPortfolioIsDefaultView
this.iconName = _item.GtPortfolioFabricIcon
this.isPersonal = _item.GtPortfolioIsPersonalView
/**
* Constructor for the PortfolioOverviewView class.
*
* @param _item SP list item to create the view from
*/
constructor(private _item?: SPPortfolioOverviewViewItem) {
this.id = _item?.Id
this.title = _item?.Title
this.sortOrder = _item?.GtSortOrder
this.searchQuery = _item?.GtSearchQuery
this.isDefaultView = _item?.GtPortfolioIsDefaultView
this.iconName = _item?.GtPortfolioFabricIcon
this.isPersonal = _item?.GtPortfolioIsPersonalView
}

/**
* Configure the view with columns.
*
* @param columns Columns to configure the view with
*/
public configure(columns: ProjectColumn[] = []): PortfolioOverviewView {
this.columns = this._item.GtPortfolioColumnsId.map((id) =>
_.find(columns, (col) => col.id === id)
Expand All @@ -48,4 +111,45 @@ export class PortfolioOverviewView {
this.groupBy = _.find(columns, (col) => col.id === this._item.GtPortfolioGroupById)
return this
}

/**
* Set properties on the view (id, title, iconName) and returns the updated
* properties.
*
* @param properties Properties to set on the view (id, title, iconName)
*/
public set(
properties: Pick<PortfolioOverviewView, 'id' | 'title' | 'iconName'>
): PortfolioOverviewView {
this.id = properties.id ?? this.id
this.title = properties.title ?? this.title
this.iconName = properties.iconName ?? this.iconName
return this
}

/**
* Append the specified `queryText` to the view's search query. Returns
* the view with the updated search query.
*
* @param queryText Query text to append to the view's search query
*/
public appendToQuery(queryText: string): PortfolioOverviewView {
this.searchQuery = `${this.searchQuery} ${queryText}`
return this
}

/**
* Configure the view from another view (copies the columns, refiners,
* groupBy, scope and searchQuery properties).
*
* @param view View to configure from≤
*/
public configureFrom(view: PortfolioOverviewView): PortfolioOverviewView {
this.columns = view.columns
this.refiners = view.refiners
this.groupBy = view.groupBy
this.scope = view.scope
this.searchQuery = view.searchQuery
return this
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,39 @@ export class PortalDataService {
}
}

/**
* Get programs from the projects list in the portfolio site.
*
* @param constructor Constructor / model class
*/
public async getPrograms<T>(constructor: new (item: any, web: Web) => T): Promise<T[]> {
try {
const items = await this.getItems(
this._configuration.listNames.PROJECTS,
constructor,
{
ViewXml: `<View>
<Query>
<OrderBy>
<FieldRef Name="Title" />
</OrderBy>
<Where>
<Eq>
<FieldRef Name="GtIsProgram" />
<Value Type="Boolean">1</Value>
</Eq>
</Where>
</Query>
</View>`
},
[]
)
return items
} catch (error) {
return []
}
}

/**
* Get project columns from the project columns list in the portfolio site.
*/
Expand Down
14 changes: 7 additions & 7 deletions SharePointFramework/PortfolioWebParts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion SharePointFramework/PortfolioWebParts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"moment": "2.24.0",
"msgraph-helper": "0.7.3",
"object-assign": "4.1.1",
"pp365-shared": "1.9.0-1128.20",
"pp365-shared": "1.9.0-1140.1",
"react": "16.13.1",
"react-calendar-timeline": "0.27.0",
"react-dom": "16.13.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { usePortfolioOverviewCommands } from './usePortfolioOverviewCommands'
*/
export const PortfolioOverviewCommands: React.FC<IPortfolioOverviewCommandsProps> = (props) => {
const context = useContext(PortfolioOverviewContext)
const { items, farItems, filters } = usePortfolioOverviewCommands(props)
const { commandBarProps, filters } = usePortfolioOverviewCommands(props)
return (
<div hidden={!context.props.showCommandBar}>
<CommandBar items={items} farItems={farItems} />
<CommandBar {...commandBarProps} />
<FilterPanel
isOpen={context.state.showFilterPanel}
layerHostId={context.layerHostId}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { ContextualMenuItemType, IContextualMenuItem } from '@fluentui/react'
import {
ContextualMenuItemType,
Dropdown,
IContextualMenuItem,
IDropdownOption
} from '@fluentui/react'
import * as strings from 'PortfolioWebPartsStrings'
import { IFilterProps } from 'components/FilterPanel'
import _ from 'lodash'
import * as strings from 'PortfolioWebPartsStrings'
import { ExcelExportService } from 'pp365-shared/lib/services'
import { PortfolioOverviewView } from 'pp365-shared/lib/models/PortfolioOverviewView'
import { ExcelExportService } from 'pp365-shared/lib/services'
import { redirect } from 'pp365-shared/lib/util'
import { useCallback, useContext } from 'react'
import React, { useCallback, useContext } from 'react'
import { PortfolioOverviewContext } from '../context'
import {
CHANGE_VIEW,
Expand All @@ -17,6 +22,7 @@ import {
} from '../reducer'
import { usePortfolioOverviewFilters } from '../usePortfolioOverviewFilters'
import { IPortfolioOverviewCommandsProps } from './types'
import { ProgramItem } from 'models'

/**
* Component logic hook for the PortfolioOverviewCommands component. Handles the logic for
Expand Down Expand Up @@ -59,6 +65,13 @@ export function usePortfolioOverviewCommands(props: IPortfolioOverviewCommandsPr

const sharedViews = convertViewsToContextualMenuItems((v) => !v.isPersonal)
const personalViews = convertViewsToContextualMenuItems((v) => v.isPersonal)
const programViewOptions: IDropdownOption[] = context.props.showProgramViews
? context.props.configuration.programs.map((p) => ({
key: p.id,
text: p.name,
data: p
}))
: []

/**
* Callback function for Excel export. Handles the export to Excel with state updates and
Expand Down Expand Up @@ -154,18 +167,39 @@ export function usePortfolioOverviewCommands(props: IPortfolioOverviewCommandsPr
key: 'VIEWS_DIVIDER',
itemType: ContextualMenuItemType.Divider
},
...context.props.configuration.views.map(
(view) =>
({
key: view.id.toString(),
name: view.title,
iconProps: { iconName: view.iconName },
canCheck: true,
checked: view.id === context.state.currentView?.id,
onClick: () => context.dispatch(CHANGE_VIEW(view))
} as IContextualMenuItem)
),
...sharedViews,
!_.isEmpty(programViewOptions) && {
key: 'PROGRAMS_HEADER',
itemType: ContextualMenuItemType.Header,
text: strings.ProgramsHeaderText
},
!_.isEmpty(programViewOptions) && {
key: 'PROGRAMS_DROPDOWN',
itemType: ContextualMenuItemType.Normal,
onRender: () => (
<div style={{ padding: '6px 12px' }}>
<Dropdown
placeholder={strings.SelectProgramText}
options={programViewOptions}
defaultSelectedKey={context.state.currentView?.id}
onChange={(_event, option) => {
const defaultView = context.props.configuration.views.find(
(v) => v.isDefaultView
)
const view = new PortfolioOverviewView().configureFrom(defaultView).set({
id: option.key,
title: option.text,
iconName: 'ProjectCollection'
})
view.searchQueries = (option.data as ProgramItem).buildQueries(
defaultView.searchQuery
)
context.dispatch(CHANGE_VIEW(view))
}}
/>
</div>
)
},
!_.isEmpty(personalViews) && {
key: 'PERSONAL_VIEWS_HEADER',
itemType: ContextualMenuItemType.Header,
Expand All @@ -184,7 +218,7 @@ export function usePortfolioOverviewCommands(props: IPortfolioOverviewCommandsPr
{
key: 'EDIT_VIEW',
name: strings.EditViewText,
disabled: context.state.loading,
disabled: context.state.loading || typeof context.state.currentView?.id !== 'number',
onClick: () =>
redirect(
`${context.props.configuration.viewsUrls.defaultEditFormUrl}?ID=${context.state.currentView?.id}`
Expand Down Expand Up @@ -212,8 +246,10 @@ export function usePortfolioOverviewCommands(props: IPortfolioOverviewCommandsPr
].filter((i) => i.data.isVisible)

return {
items,
farItems,
commandBarProps: {
items,
farItems
},
filters: [
{
column: {
Expand Down
Loading