diff --git a/apps/web/components/Organization/Slice/PowerBiSlice/PowerBiSlice.css.ts b/apps/web/components/Organization/Slice/PowerBiSlice/PowerBiSlice.css.ts
new file mode 100644
index 000000000000..3e90be0d77b6
--- /dev/null
+++ b/apps/web/components/Organization/Slice/PowerBiSlice/PowerBiSlice.css.ts
@@ -0,0 +1,5 @@
+import { style } from '@vanilla-extract/css'
+
+export const container = style({
+ height: '500px',
+})
diff --git a/apps/web/components/Organization/Slice/PowerBiSlice/PowerBiSlice.tsx b/apps/web/components/Organization/Slice/PowerBiSlice/PowerBiSlice.tsx
new file mode 100644
index 000000000000..102499772c13
--- /dev/null
+++ b/apps/web/components/Organization/Slice/PowerBiSlice/PowerBiSlice.tsx
@@ -0,0 +1,27 @@
+import { PowerBIEmbed } from 'powerbi-client-react'
+import { Embed } from 'powerbi-client'
+import { PowerBiSlice as PowerBiSliceSchema } from '@island.is/web/graphql/schema'
+import * as styles from './PowerBiSlice.css'
+
+interface PowerBiSliceProps {
+ slice: PowerBiSliceSchema
+}
+
+export const PowerBiSlice = ({ slice }: PowerBiSliceProps) => {
+ const getEmbeddedComponent = (embed: Embed) => {
+ if (slice?.powerBiEmbedProps?.height) {
+ embed.element.style.height = slice.powerBiEmbedProps.height
+ }
+ }
+
+ const embedProps = slice?.powerBiEmbedProps ?? {}
+ return (
+
+ )
+}
+
+export default PowerBiSlice
diff --git a/apps/web/components/Organization/Slice/PowerBiSlice/index.ts b/apps/web/components/Organization/Slice/PowerBiSlice/index.ts
new file mode 100644
index 000000000000..289b36d29e2e
--- /dev/null
+++ b/apps/web/components/Organization/Slice/PowerBiSlice/index.ts
@@ -0,0 +1,4 @@
+import dynamic from 'next/dynamic'
+export const PowerBiSlice = dynamic(() => import('./PowerBiSlice'), {
+ ssr: false,
+})
diff --git a/apps/web/components/Organization/index.ts b/apps/web/components/Organization/index.ts
index bea3ad6c1062..d6eef4606b7c 100644
--- a/apps/web/components/Organization/index.ts
+++ b/apps/web/components/Organization/index.ts
@@ -23,3 +23,4 @@ export * from './Slice/EventSlice/EventSlice'
export * from './SearchBox/SearchBox'
export * from './Slice/MailingListSignupSlice/MailingListSignupSlice'
export * from './Slice/LifeEventPageListSlice/LifeEventPageListSlice'
+export * from './Slice/PowerBiSlice'
diff --git a/apps/web/screens/Organization/SubPage.tsx b/apps/web/screens/Organization/SubPage.tsx
index 975adf0a4f1d..6e3db582d376 100644
--- a/apps/web/screens/Organization/SubPage.tsx
+++ b/apps/web/screens/Organization/SubPage.tsx
@@ -14,6 +14,7 @@ import {
import { withMainLayout } from '@island.is/web/layouts/main'
import {
ContentLanguage,
+ PowerBiSlice as PowerBiSliceSchema,
Query,
QueryGetNamespaceArgs,
QueryGetOrganizationPageArgs,
@@ -35,6 +36,7 @@ import {
SliceDropdown,
Form,
OneColumnTextSlice,
+ PowerBiSlice,
} from '@island.is/web/components'
import { CustomNextError } from '@island.is/web/units/errors'
import useContentfulId from '@island.is/web/hooks/useContentfulId'
@@ -178,6 +180,9 @@ const SubPage: Screen = ({
OneColumnText: (slice) => (
),
+ PowerBiSlice: (slice: PowerBiSliceSchema) => (
+
+ ),
},
})}
diff --git a/apps/web/screens/Project/Project.tsx b/apps/web/screens/Project/Project.tsx
index d84b26752084..0e39109f594d 100644
--- a/apps/web/screens/Project/Project.tsx
+++ b/apps/web/screens/Project/Project.tsx
@@ -19,6 +19,7 @@ import {
Stepper,
stepperUtils,
Form,
+ PowerBiSlice,
} from '@island.is/web/components'
import {
Box,
@@ -74,8 +75,9 @@ const ProjectPage: Screen = ({
>(undefined)
let content: SliceType[] = []
- if (!!subpage && renderSlicesAsTabs)
+ if (!!subpage && renderSlicesAsTabs) {
content = selectedSliceTab?.content as SliceType[]
+ }
if (!subpage) content = projectPage?.content as SliceType[]
useEffect(() => {
@@ -136,6 +138,7 @@ const ProjectPage: Screen = ({
richText(subpage.content as SliceType[], {
renderComponent: {
Form: (slice) => ,
+ PowerBiSlice: (slice) => ,
},
})}
@@ -168,7 +171,13 @@ const ProjectPage: Screen = ({
{selectedSliceTab.title}
)}
- {content && richText(content)}
+ {content &&
+ richText(content, {
+ renderComponent: {
+ Form: (slice) => ,
+ PowerBiSlice: (slice) => ,
+ },
+ })}
{!subpage && projectPage.stepper && (
{
}
}
+export interface IPowerBiSliceFields {
+ /** Title */
+ title?: string | undefined
+
+ /** Config */
+ config: Record
+}
+
+/** A Slice that embeds a Power BI report */
+
+export interface IPowerBiSlice extends Entry {
+ sys: {
+ id: string
+ type: string
+ createdAt: string
+ updatedAt: string
+ locale: string
+ contentType: {
+ sys: {
+ id: 'powerBiSlice'
+ linkType: 'ContentType'
+ type: 'Link'
+ }
+ }
+ }
+}
+
export interface IProcessEntryFields {
/** Type */
type:
@@ -3819,6 +3847,7 @@ export type CONTENT_TYPE =
| 'organizationTag'
| 'overviewLinks'
| 'pageHeader'
+ | 'powerBiSlice'
| 'processEntry'
| 'projectPage'
| 'projectSubpage'
diff --git a/libs/cms/src/lib/models/powerBiSlice.model.ts b/libs/cms/src/lib/models/powerBiSlice.model.ts
new file mode 100644
index 000000000000..06e51dcee285
--- /dev/null
+++ b/libs/cms/src/lib/models/powerBiSlice.model.ts
@@ -0,0 +1,28 @@
+import { Field, ID, ObjectType } from '@nestjs/graphql'
+import graphqlTypeJson from 'graphql-type-json'
+import { SystemMetadata } from '@island.is/shared/types'
+import { IPowerBiSlice } from '../generated/contentfulTypes'
+
+@ObjectType()
+export class PowerBiSlice {
+ @Field(() => ID)
+ id!: string
+
+ @Field()
+ title?: string
+
+ @Field(() => graphqlTypeJson, { nullable: true })
+ powerBiEmbedProps?: Record
+}
+
+export const mapPowerBiSlice = ({
+ fields,
+ sys,
+}: IPowerBiSlice): SystemMetadata => {
+ return {
+ typename: 'PowerBiSlice',
+ id: sys.id,
+ title: fields.title ?? '',
+ powerBiEmbedProps: fields.config ?? null,
+ }
+}
diff --git a/libs/cms/src/lib/unions/slice.union.ts b/libs/cms/src/lib/unions/slice.union.ts
index 26f23fc916b1..aeaa17d2aff5 100644
--- a/libs/cms/src/lib/unions/slice.union.ts
+++ b/libs/cms/src/lib/unions/slice.union.ts
@@ -34,6 +34,7 @@ import {
IGraphCard,
ILifeEventPageListSlice,
ISidebarCard,
+ IPowerBiSlice,
} from '../generated/contentfulTypes'
import { Image, mapImage } from '../models/image.model'
import { Asset, mapAsset } from '../models/asset.model'
@@ -96,6 +97,7 @@ import {
mapLifeEventPageListSlice,
} from '../models/lifeEventPageListSlice.model'
import { mapSidebarCard, SidebarCard } from '../models/sidebarCard.model'
+import { PowerBiSlice, mapPowerBiSlice } from '../models/powerBiSlice.model'
type SliceTypes =
| ITimeline
@@ -129,6 +131,7 @@ type SliceTypes =
| IGraphCard
| ILifeEventPageListSlice
| ISidebarCard
+ | IPowerBiSlice
export const SliceUnion = createUnionType({
name: 'Slice',
@@ -167,6 +170,7 @@ export const SliceUnion = createUnionType({
GraphCard,
LifeEventPageListSlice,
SidebarCard,
+ PowerBiSlice,
],
resolveType: (document) => document.typename, // typename is appended to request on indexing
})
@@ -236,6 +240,8 @@ export const mapSliceUnion = (slice: SliceTypes): typeof SliceUnion => {
return mapLifeEventPageListSlice(slice as ILifeEventPageListSlice)
case 'sidebarCard':
return mapSidebarCard(slice as ISidebarCard)
+ case 'powerBiSlice':
+ return mapPowerBiSlice(slice as IPowerBiSlice)
default:
throw new ApolloError(`Can not convert to slice: ${contentType}`)
}
diff --git a/package.json b/package.json
index 397207aa5edf..f9b4a7e0401c 100644
--- a/package.json
+++ b/package.json
@@ -217,6 +217,8 @@
"pdfkit": "0.11.0",
"pg": "8.1.0",
"pg-hstore": "2.3.3",
+ "powerbi-client": "2.21.1",
+ "powerbi-client-react": "1.3.5",
"prom-client": "12.0.0",
"pubsub-js": "1.8.0",
"react": "17.0.2",
diff --git a/yarn.lock b/yarn.lock
index e8766d184d3d..4ad8fa39c6e3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5177,15 +5177,6 @@
call-me-maybe "^1.0.1"
glob-to-regexp "^0.3.0"
-"@nestjs/apollo@^10.0.22":
- version "10.1.3"
- resolved "https://registry.yarnpkg.com/@nestjs/apollo/-/apollo-10.1.3.tgz#c5f02a032b29b2e55472f09f5a474628ee507695"
- integrity sha512-N0qm8R9KOJfOyIKu5U345uEdeO8n/8NOqKr1sJGUaiYn11PAIyg6159wO4Q4lhgJTqCV7QhRQ49sHzVHbjrtiA==
- dependencies:
- iterall "1.3.0"
- lodash.omit "4.5.0"
- tslib "2.4.0"
-
"@nestjs/axios@0.0.7":
version "0.0.7"
resolved "https://registry.yarnpkg.com/@nestjs/axios/-/axios-0.0.7.tgz#7f134636db13c2c1e8299365c7eceb73cd782b67"
@@ -14254,7 +14245,7 @@ dataloader@2.0.0, dataloader@^2.0.0:
resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.0.0.tgz#41eaf123db115987e21ca93c005cd7753c55fe6f"
integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ==
-dataloader@2.1.0, dataloader@^2.1.0:
+dataloader@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.1.0.tgz#c69c538235e85e7ac6c6c444bae8ecabf5de9df7"
integrity sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ==
@@ -15403,7 +15394,7 @@ es6-map@^0.1.5:
es6-symbol "~3.1.1"
event-emitter "~0.3.5"
-es6-promise@^3.2.1:
+es6-promise@^3.1.2, es6-promise@^3.2.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
integrity sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=
@@ -18360,6 +18351,13 @@ http-parser-js@>=0.5.1:
resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9"
integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==
+http-post-message@^0.2:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/http-post-message/-/http-post-message-0.2.3.tgz#32c560ac615f310a7e459ffc71277b579b242e1e"
+ integrity sha512-76heerrzYhvWptJfWxUarHw2O3fkMqF48bbq/S6XFWHUc34o8tkySBwtReXuAKJAECZWVu8U0TYLckFcwtSdrg==
+ dependencies:
+ es6-promise "^3.2.1"
+
http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
@@ -19671,7 +19669,7 @@ iterall@1.2.2:
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"
integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==
-iterall@1.3.0, iterall@^1.1.3, iterall@^1.2.1, iterall@^1.3.0:
+iterall@^1.1.3, iterall@^1.2.1, iterall@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea"
integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==
@@ -21701,7 +21699,7 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash.omit@4.5.0, lodash.omit@^4.5.0:
+lodash.omit@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=
@@ -22894,15 +22892,6 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0:
resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61"
integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==
-nestjs-dataloader@9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/nestjs-dataloader/-/nestjs-dataloader-9.0.0.tgz#2fb409c1cdd879cb9c46d0d33e43d00e7d14151e"
- integrity sha512-BiBEY+dhmhXxMjLOYjBOXs7kR1GF5z6cCBLLtwtRWGBAl7mz9EliyHk1gwlEgag+PK5w/pToqMUCV3D+SQkx9Q==
- dependencies:
- "@nestjs/apollo" "^10.0.22"
- dataloader "^2.1.0"
- rxjs "^7.5.6"
-
netmask@2.0.1, netmask@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.1.tgz#5a5cbdcbb7b6de650870e15e83d3e9553a414cf4"
@@ -25458,6 +25447,37 @@ posthtml@^0.13.4:
posthtml-parser "^0.5.0"
posthtml-render "^1.2.3"
+powerbi-client-react@1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/powerbi-client-react/-/powerbi-client-react-1.3.5.tgz#652f5077505a73c1524a7a9c5e75e2131b47e566"
+ integrity sha512-YqLpkus9UD6YxRe3W+Kcnao6lRv/Do2XZilx4UWRWlXS+roQ3QI6Dm8KsxUpvMYo636x4mzAjj3FOymQwoLi4w==
+ dependencies:
+ lodash.isequal "^4.5.0"
+ powerbi-client "^2.21.1"
+
+powerbi-client@2.21.1, powerbi-client@^2.21.1:
+ version "2.21.1"
+ resolved "https://registry.yarnpkg.com/powerbi-client/-/powerbi-client-2.21.1.tgz#b9924c73ebbbf9070892d85da7a4257870e627a7"
+ integrity sha512-v5rbqVnAiES5iU8OerUKdMVLfV934QykZkpge3Iyx9EcKob/Ga1mWa973e/32EejEqtGqoYNcvkrkK7utfGV+g==
+ dependencies:
+ http-post-message "^0.2"
+ powerbi-models "^1.11.0"
+ powerbi-router "^0.1"
+ window-post-message-proxy "^0.2"
+
+powerbi-models@^1.11.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/powerbi-models/-/powerbi-models-1.11.0.tgz#c2f1611068344b717bc211fbe19247c916d964ac"
+ integrity sha512-zRy6PBCmOhtHkZ6aWC/s7W/oV8aCmu7QlnG1GEy8XThj2baxFYnj2tCYaKAsOX7CvlCymw1NIXN9RhiRQI7EXQ==
+
+powerbi-router@^0.1:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/powerbi-router/-/powerbi-router-0.1.5.tgz#dd2d2d0474f8cb76690a85f6a51d8ca9fea93a32"
+ integrity sha512-DFJCKxwh/DqMZXtHSo6xZl87mbRviZGn4P7Oi2rT0L4HMI4AjnWIrwg0JCSM7ymBzYnNe5UmrsCaf2Upur5RQA==
+ dependencies:
+ es6-promise "^3.2.1"
+ route-recognizer "^0.1.11"
+
preact-render-to-string@^5.1.14:
version "5.1.19"
resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.1.19.tgz#ffae7c3bd1680be5ecf5991d41fe3023b3051e0e"
@@ -27477,6 +27497,11 @@ rosetta@1.0.0:
dlv "^1.1.3"
templite "^1.1.0"
+route-recognizer@^0.1.11:
+ version "0.1.11"
+ resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7"
+ integrity sha512-7JNu5mXQVa39zxmUKyk/bfpeF2WyEC5JKVTJO5HATcoUQpcQsI3eLzhwGU69xeOagQxfOQ+yr2sSv0G8xy+vQA==
+
rsvp@^4.8.4:
version "4.8.5"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
@@ -27542,13 +27567,6 @@ rxjs@^7.0.0:
dependencies:
tslib "^2.1.0"
-rxjs@^7.5.6:
- version "7.5.7"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39"
- integrity sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==
- dependencies:
- tslib "^2.1.0"
-
safe-buffer@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
@@ -31477,6 +31495,13 @@ wildcard@^2.0.0:
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
+window-post-message-proxy@^0.2:
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/window-post-message-proxy/-/window-post-message-proxy-0.2.6.tgz#8d9800d441629c8bff0a8cb2bf9e0119702940ca"
+ integrity sha512-IwNWtUWVFarBa2F9vhmfv2yr0PfPm57QuOBCw3qSLaunhD3THcHUKQ4HrJQiCuYUT7LEjhUtaoA+hrV+wQzNmQ==
+ dependencies:
+ es6-promise "^3.1.2"
+
winston-cloudwatch@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/winston-cloudwatch/-/winston-cloudwatch-3.1.1.tgz#f5b862dc29c9f8501e72541791fcd1d4b4822376"