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

Forbedret idémodul for visning av idéer og konfigurasjon #1589

Merged
merged 31 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
efe7572
Init IdeaModule
Remi749 Oct 17, 2024
4f5b4a9
Init IdeaModule v2
Remi749 Oct 17, 2024
8182325
Fix some issues [packages-only]
Remi749 Oct 17, 2024
c4066c2
Update readme [skip-ci]
Remi749 Oct 17, 2024
404487b
Add open/close hamburger
Remi749 Oct 21, 2024
9f7cea6
Hamboorger
Remi749 Oct 22, 2024
c638a8f
Get ideas dynamically including values, field mappings ++
Remi749 Oct 25, 2024
7c140bc
getSelectedIdea dynamically
Remi749 Oct 31, 2024
9b93a6a
Improvements to getting ideas + change idea state
Remi749 Nov 7, 2024
cfff383
Improvements to ideaConfiguration + ideaPhase bar + merging of regist…
Remi749 Nov 8, 2024
a9dc6d1
Ideamodule - ClientSidePage + Navigation
Remi749 Nov 8, 2024
f171f5c
Add "Idémodul" as category and add elements to "Prosjektinnholdskolon…
Remi749 Nov 11, 2024
524885b
Fix IdeaView for "Prosjektinnholdskolonner"
Remi749 Nov 12, 2024
5336512
Use "Prosjektinnholdskolonner" for fieldconfig + hideFields functiona…
Remi749 Nov 12, 2024
8b8b336
Add dynamic ideaPhaseBar + restructuring of components
Remi749 Nov 12, 2024
ba55aea
Fix selectedValue for NavDrawer [packages-only]
Remi749 Nov 12, 2024
ec69523
Add accordion if in process for registration item
Remi749 Nov 12, 2024
8698c64
Changes to styling and responsiveness for small screens [packages-only]
Remi749 Nov 13, 2024
93b4916
Add dynamic copying of data from registrationList to processingList
Remi749 Nov 13, 2024
1f83b2c
Bugfix for processing idea without values [skip-ci]
Remi749 Nov 13, 2024
fd040b9
Change title of IDEA_PROCESSING_LINK [skip-ci]
Remi749 Nov 13, 2024
fd14e41
Code improvements and adjustments [skip-ci]
Remi749 Nov 13, 2024
93f2369
Add provisionUrl property + some styling fixes [packages-only]
Remi749 Nov 14, 2024
34a073b
Add CT to IdeaColumns and fix view
Remi749 Nov 14, 2024
6f3cced
Refine field copying logic in registrationList [packages-only]
Remi749 Nov 14, 2024
bb7d907
Add Commandbar
Remi749 Nov 15, 2024
703e4b9
Build IdeaModule pre-release
Remi749 Nov 27, 2024
b9fa003
Bugfix for URL type fields [skpi-ci]
Remi749 Dec 2, 2024
ad3845d
Minor adjustment [skip-ci]
Remi749 Dec 2, 2024
8920170
Fix styling and nav logic
Remi749 Dec 12, 2024
4ed5ca0
Changelog ++
Remi749 Dec 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: Build release (main)

on:
push:
branches: [main]
branches:
- main
paths:
- 'SharePointFramework/**'
- 'Install/**'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-channel-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- releases/1.10
- feat/ideamodule
paths:
- 'SharePointFramework/**'
- 'Install/**'
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Sjekk ut [release notes](./releasenotes/1.10.0.md) for høydepunkter og mer deta
### Ny funksjonalitet

- Lagt til instrumentvisning for 'Siste måling' på Gevinstoversikt [#1572](https://github.com/Puzzlepart/prosjektportalen365/issues/1572)
- Ny Idémodul for visning av idéer (registrering/behandling) samt feltkonfigurasjon slik at relevant data fra idéregistreringen kan videreføres til behandling [#1573](https://github.com/Puzzlepart/prosjektportalen365/issues/1573)

## 1.10.1 - TBA

Expand Down
2 changes: 1 addition & 1 deletion SharePointFramework/PortfolioExtensions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"watch": "concurrently \"npm run serve\" \"livereload './dist/*.js' -e 'js' -w 250\"",
"prewatch": "node node_modules/pzl-spfx-tasks --pre-watch --loglevel silent",
"postwatch": "node node_modules/pzl-spfx-tasks --post-watch --loglevel silent",
"serve": "concurrently \"gulp serve-deprecated --locale=nb-no --nobrowser\"",
"serve": "concurrently \"gulp serve-deprecated --locale=nb-no --nobrowser NODE --max-old-space-size=8192\"",
"build": "gulp bundle --ship && gulp package-solution --ship",
"postversion": "tsc && npm publish",
"lint": "eslint --ext .ts,.tsx ./src --color --fix --config ../.eslintrc.yaml && npm run prettier",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ import '@pnp/sp/lists'
import '@pnp/sp/folders/list'
import '@pnp/sp/site-groups/web'
import '@pnp/sp/clientside-pages/web'
import { ClientsideText, IClientsidePage } from '@pnp/sp/clientside-pages'
import { isUserAuthorized } from '../../helpers/isUserAuthorized'
import strings from 'PortfolioExtensionsStrings'
import { Choice, IdeaConfigurationModel, SPIdeaConfigurationItem } from 'models'
import { find } from 'underscore'
import {
getClassProperties,
ProjectContentColumn,
SPField,
SPProjectContentColumnItem
} from 'pp365-shared-library'
import _ from 'underscore'

const LOG_SOURCE: string = 'IdeaRegistrationCommand'

Expand All @@ -36,6 +42,7 @@ export default class IdeaRegistrationCommand extends BaseListViewCommandSet<any>
this._openCmd = this.tryGetCommand('OPEN_IDEA_REGISTRATION_DIALOG')
this._openCmd.visible = false
this._openLinkCmd = this.tryGetCommand('IDEA_PROCESSING_LINK')
// this._openLinkCmd.title = `Gå til ${this._config.processingList}`
this._openLinkCmd.visible = this.context.pageContext.list.title.includes('registrering')
this._userAuthorized = await isUserAuthorized(
this._sp,
Expand Down Expand Up @@ -203,9 +210,86 @@ export default class IdeaRegistrationCommand extends BaseListViewCommandSet<any>
* @param comment Comment from the dialog
*/
private _onSubmit = async (row: RowAccessor, comment: string): Promise<void> => {
const getProcessingColumns = async (): Promise<{ fields: SPField[] }> => {
const [listInfo] = await this._sp.web.lists
.filter(`Title eq '${this._config.processingList}'`)
.select('Id')()
const list = this._sp.web.lists.getById(listInfo.Id)
const fields = await list.fields
.select(...getClassProperties(SPField))
.filter("substringof('Gt', InternalName) or InternalName eq 'Title'")<SPField[]>()

return {
fields
}
}

const contentColumns = async () => {
try {
const list = this._sp.web.lists.getByTitle('Prosjektinnholdskolonner')

const columnItems = await list.items.select(
...Object.keys(new SPProjectContentColumnItem())
)()

const filteredColumnItems = columnItems.filter(
(col) =>
col.GtDataSourceCategory === 'Idémodul' ||
(!col.GtDataSourceCategory && !col.GtDataSourceLevel) ||
(!col.GtDataSourceCategory && _.contains(col.GtDataSourceLevel, 'Portefølje'))
)

return filteredColumnItems
.filter((col) => col.GtIdeaCopyToProcess)
.map((item) => new ProjectContentColumn(item))
} catch (error) {
throw new Error(error)
}
}

const columns = await contentColumns()
const processingColumns = await getProcessingColumns()
const registrationList = row

const userFields = registrationList.fields
.filter((fld) => fld.fieldType.indexOf('User') === 0)
.map((fld) => fld.internalName)

const columnsToCopy = processingColumns.fields.filter((col) => {
const field = registrationList.fields.find(
(f) => f.internalName === col.InternalName || f.displayName === col.Title
)

const fieldsToCopy =
field &&
columns.find(
(contentCol) =>
contentCol.internalName === field.internalName ||
contentCol.fieldName === field.displayName
)

return fieldsToCopy
})

const copyData = columnsToCopy
.map((col) => {
if (userFields.includes(col.InternalName)) {
return {
[`${col.InternalName}Id`]: registrationList.getValueByName(col.InternalName)[0]?.id
}
}

const internalName = registrationList.fields.find(
(fld) => fld.displayName === col.Title || fld.internalName === col.InternalName
)?.internalName

return {
[col.InternalName]: registrationList.getValueByName(internalName)
}
})
.reduce((acc, val) => ({ ...acc, ...val }), {})

const rowId = row.getValueByName('ID')
const rowTitle = row.getValueByName('Title')
const rowReporter = row.getValueByName('GtIdeaReporter')[0] || ''

await this._sp.web.lists
.getByTitle(this._config.registrationList)
Expand All @@ -218,9 +302,9 @@ export default class IdeaRegistrationCommand extends BaseListViewCommandSet<any>

Log.info(LOG_SOURCE, `Updated ${this._config.registrationList}: Approved`)

const pageUrl = await this._createSitePage(row)
await this._updateProcessingList(rowId, rowTitle, rowReporter, pageUrl)
const ideaModuleUrl = `${this.context.pageContext.site.absoluteUrl}/SitePages/Idemodul.aspx#ideaId=${rowId}`

await this._updateProcessingList(rowId, copyData, ideaModuleUrl)
window.location.reload()
}

Expand Down Expand Up @@ -255,19 +339,17 @@ export default class IdeaRegistrationCommand extends BaseListViewCommandSet<any>
* Update the work list with selected values of the registration list
*
* @param rowId Id of the row in the registration list
* @param rowTitle Title of the row in the registration list
* @param copyData Data to copy from the registration list to processing list
*/
private _updateProcessingList = async (
rowId: number,
rowTitle: string,
rowReporter: any,
copyData: any,
pageUrl: string
): Promise<void> => {
await this._sp.web.lists.getByTitle(this._config.processingList).items.add({
Title: rowTitle,
GtRegistratedIdeaId: rowId,
GtIdeaUrl: pageUrl,
GtIdeaReporterId: rowReporter?.id
...copyData
})

Log.info(LOG_SOURCE, 'Updated work list')
Expand All @@ -284,82 +366,4 @@ export default class IdeaRegistrationCommand extends BaseListViewCommandSet<any>
find(this._config.registration, { key: Choice.Approve })?.recommendation
)
}

/**
* Create a site page with the selected values of the registration list
*
* @param row Selected row
*/
private _createSitePage = async (row: RowAccessor): Promise<string> => {
const title: string = row.getValueByName('Title')
const urlFriendlyTitle = title.replace(/é/g, 'e').replace(/[^a-zA-Z0-9-_ÆØÅæøå ]/g, '')
const page: IClientsidePage = await this._sp.web.addClientsidePage(
`KUR-${urlFriendlyTitle}`,
`KUR-${urlFriendlyTitle}`,
'Article'
)

const reporter = row.getValueByName('GtIdeaReporter')[0] || null

page.layoutType = 'NoImage'
page.showTopicHeader = true
page.topicHeader = 'Idé'
page.description = `Konsept utredningsrapport for: ${title}`

const section = page.addSection()
const column1 = section.addColumn(4)
const column2 = section.addColumn(4)
const column3 = section.addColumn(4)

column1.addControl(new ClientsideText(`<h3>Tittel</h3>${row.getValueByName('Title')}`))
column1.addControl(
new ClientsideText(`<h3>Bakgrunn</h3>${row.getValueByName('GtIdeaBackground')}`)
)
column1.addControl(
new ClientsideText(
`<h3>Forslag til løsning</h3>${row.getValueByName('GtIdeaSolutionProposals')}`
)
)
column1.addControl(
new ClientsideText(
`<h3>Overordnet gjennomføringsplan</h3>${row.getValueByName('GtIdeaExecutionPlan')}`
)
)
column2.addControl(
new ClientsideText(
`<h3>Innmelder</h3>${
reporter
? `<a href="mailto:${reporter?.email}" target="_blank">${reporter?.title}</a>`
: 'Ikke angitt'
}`
)
)
column2.addControl(
new ClientsideText(`<h3>Ressursbehov</h3>${row.getValueByName('GtIdeaResourceRequirements')}`)
)
column2.addControl(
new ClientsideText(`<h3>Problemstilling</h3>${row.getValueByName('GtIdeaIssue')}`)
)
column2.addControl(
new ClientsideText(`<h3>Mulige gevinster</h3>${row.getValueByName('GtIdeaPossibleGains')}`)
)

column3.addControl(
new ClientsideText(`<h3>Berørte parter</h3>${row.getValueByName('GtIdeaAffectedParties')}`)
)
column3.addControl(
new ClientsideText(
`<h3>Kritiske suksessfaktorer</h3>${row.getValueByName('GtIdeaCriticalSuccessFactors')}`
)
)
column3.addControl(
new ClientsideText(`<h3>Andre kommentarer</h3>${row.getValueByName('GtIdeaOtherComments')}`)
)

section.emphasis = 1
page.save()
const savedPage = await page.load()

return savedPage['json'].AbsoluteUrl
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
},
"IDEA_PROCESSING_LINK": {
"title": {
"default": "Gå til idébehandling"
"default": "Gå til behandling"
},
"iconImageUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA/lJREFUWEe1l02ME2UYx//P27orIiaiQQ9GiSCShU5ljQfU2OnWQKKi7E4HDReJXvSiRCT4Fa0hfhDUqBe9aPBCdNvpqqAJxG7fGpWDcbFTdoOrGCQckCAmrl+7tu9jZtrisEw70y3Oceb5+L3P5zuEEM/q1ea8P3uVoYBHCLjJT4WBrwXw5kXTwjpwIPtXCLOuCAUJasl0Cop3g7AoSNb9zjgJQRvtYq4QRr4dAGnJ9JNgfuGMIYbNwIcQNBbhatl5X6NoHIr7CVgPgnZGluhpu5h7yUVq87QE0HTjUQCv/+ecn1pIp3dKKat+9nRdj57mhVtB9KLn+2ZbWm90DLByIH2zUPxlQ/G4iuDOQwXLDhPSlSlDEzV8AuAqR14JuuXQaO6rVrp+ESAtYRwGYVkYA36GzzoAY9IuWctbpeIcAG1gcABKuAVE4B1lmX8izMlny8T1oZcZtM19L1TKHh0Z9bNzDkA8aQwzw3Sqef6MWNxJS3kdOK37R4866nQPEbLlorUhFICWMH52lJgxXClZ987l9E2dWML4gAgbnMPYJeuKQIDF+qYLL8FUY4jQVlvmXukGQNPTjwO807HxGxbMOyp3/T3b3lkpWKGbSyNQ37v5F7S2PJrb3w1AfCC9hhXvc+cFxHXjMvtDe4DbzasjVfVTXYhNW+Zz3QDEEmmTiIddgKi4Zvyz7LG2AN4UdNMBTSfeTgiVAkdRSxjfOTOAAVmRVrKrCOhGkQAd9VlwfWAROgJxPb2dwc+4daDQX/7cOjgXiPhtxioWGHOTSby9Usw/Gwoglhq6lmp0pF4GmJw/I27odBY0ZsC3zWnKEV5SKeR/DAXgRiFpPMCMd1wGxmuVkrWlkyjEEsarRHjMjSLhwXLRereVfqttSJpujAC4p9OW9LYegI9saa1vB996Ha8ZXIQZ4fTtAgBTVYhlEzJ7op2xPt28Mgo12dRBj1pq7x85OSeARkHexeA9DQP7bD12BzIZ5WswkxGarHwKYK0bNdC6ssztDUpd8JVMN94C8JBjqN1un3WHeNuW1sNBzuugAU+fbl4cZXWkfifkjC3zz/upaPrQcwBlnMVTJbFkQmZ/D7IdCsAR8my1Mbtk3egLkDC+AaG/0y0aGAHHmXergeh+YjXthWASvWB+r/6usy0aDsBzSwoMa5vbT+hBNFtwVcrsq9XUeKBzAJGIWHGwkJ0IIxu6BrwAfg6Cvs95DjQVgxwEfT+vAH4b0rv5/pcULE8NXtZTE6eaExGgXQTl/nIxBAG8qTkBZyLq8sOFkV/Oaw3UW9H4GMC6AMN7bGndHdZ56CJ0h9GtGy+lC6Z3gHFfY9l4/UyB8D7/07ut8sXuXzsB+BfElbcwrolkGwAAAABJRU5ErkJggg==",
"type": "command"
}
}
}
}
8 changes: 8 additions & 0 deletions SharePointFramework/PortfolioWebParts/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@
"manifest": "./src/webparts/projectProvision/manifest.json"
}
]
},
"idea-module-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/ideaModule/index.js",
"manifest": "./src/webparts/ideaModule/manifest.json"
}
]
}
},
"externals": {},
Expand Down
4 changes: 3 additions & 1 deletion SharePointFramework/PortfolioWebParts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@
"react-virtualized-auto-sizer": "~1.0.24",
"@fluentui/react-datepicker-compat": "~0.4.38",
"@fluentui/react-motion-preview": "~0.5.20",
"react-gauge-component": "~1.2.61"
"@fluentui/react-nav-preview": "~0.9.1",
"react-gauge-component": "~1.2.61",
"@fluentui/react-motion-components-preview": "~0.3.0"
},
"devDependencies": {
"@microsoft/eslint-config-spfx": "1.17.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.commands {
display: flex;
flex-direction: column;
width: 100%;
height: 42px;
margin: 0px auto;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React, { FC } from 'react'
import { Toolbar } from 'pp365-shared-library'
import { useToolbarItems } from './useToolbarItems'
import styles from './Commands.module.scss'

export const Commands: FC = () => {
const { menuItems, farMenuItems } = useToolbarItems()

return (
<div className={styles.commands}>
<Toolbar items={menuItems} farItems={farMenuItems} />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Commands'
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useIdeaModuleContext } from '../context'

/**
* Hook for creating new ideas. Returns a callback function
* for creating a new idea
*/
export const useCreateNewIdea = () => {
const context = useIdeaModuleContext()
// TODO: Implement the useCreateNewIdea hook
// console.log('create', context)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useIdeaModuleContext } from '../context'

/**
* Hook for setting the decision for ideas. Returns a callback function for setting the decision.
*
* @returns A function callback that returns a promise of void
*/
export const useDecision = () => {
const context = useIdeaModuleContext()
return async (): Promise<void> => {
// TODO: Implement the useDecision hook
// console.log('decide', context)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useIdeaModuleContext } from '../context'

/**
* Hook for deletion of idea. Returns a callback function
* for deleting the selected report.
*
* @returns A function callback
*/
export const useDelete = () => {
const context = useIdeaModuleContext()
return async (): Promise<void> => {
// TODO: Implement the useDelete hook
// console.log('delete', context)
}
}
Loading
Loading