Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cmeessen committed Sep 25, 2024
1 parent 970967d commit c7aae51
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 25 deletions.
5 changes: 4 additions & 1 deletion frontend/auth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import {refreshSession} from './refreshSession'
const testMargin = process.env.REFRESH_MARGIN_MSEC ? parseInt(process.env.REFRESH_MARGIN_MSEC) : undefined
export const REFRESH_MARGIN = testMargin ?? 5 * 60 * 1000
export type RsdRole = 'rsd_admin' | 'rsd_user'
export type RsdUserData = {
[property: string]: string[]
}
export type RsdUser = {
iss: 'rsd_auth'
role: RsdRole
Expand All @@ -28,7 +31,7 @@ export type RsdUser = {
account: string
// display name
name: string,
edupersonEntitlements: string[] | null
data?: RsdUserData,
}

export type Session = {
Expand Down
31 changes: 31 additions & 0 deletions frontend/config/RsdPluginContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
//
// SPDX-License-Identifier: Apache-2.0

import {createContext} from 'react'

export type PluginSlot={
name: string,
icon: JSX.Element,
href: string,
title: string,
subtitle: string | null
}

export type RsdPluginProps = {
pluginSlots: PluginSlot[]
}

export const RsdPluginContext = createContext<RsdPluginProps>({
pluginSlots: []
})

export default function PluginSettingsProvider(props: any) {
const {pluginSlots} = props

return <RsdPluginContext.Provider
value={{pluginSlots}}
{...props}
/>
}
2 changes: 2 additions & 0 deletions frontend/config/UserSettingsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// SPDX-FileCopyrightText: 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0
Expand Down
10 changes: 7 additions & 3 deletions frontend/config/menuItems.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2021 - 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2021 - 2023 dv4all
// SPDX-FileCopyrightText: 2022 - 2023 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2022 - 2023 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2022 - 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2022 - 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) (dv4all)
Expand All @@ -21,7 +21,7 @@ import Diversity3Icon from '@mui/icons-material/Diversity3'
import {RsdModule} from './rsdSettingsReducer'

export type MenuItemType = {
type?: 'link' | 'function' |'divider'
type?: 'link' | 'function' |'divider' | 'pluginSlot'
label: string,
// used as url link
path?: string,
Expand Down Expand Up @@ -120,6 +120,10 @@ export const userMenuItems: MenuItemType[] = [
},
path: '/user/communities',
icon: <Diversity3Icon />,
}, {
module: 'user',
type: 'pluginSlot',
label: 'Unused label for plugin slot',
}, {
module: 'user',
type: 'divider',
Expand Down
10 changes: 10 additions & 0 deletions frontend/config/pluginSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
//
// SPDX-License-Identifier: Apache-2.0

// Defines the possible names for plugin slots, referred by the individual components
export enum PluginSlotNames {
userMenu = 'userMenu',
softwareEditSidebar = 'softwareEditSidebar',
}
3 changes: 2 additions & 1 deletion frontend/config/rsdSettingsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export type RsdHost = {
limit: number,
description?: string | null
},
modules?: RsdModule[]
modules?: RsdModule[],
plugins?: string[]
}

export type CustomLink = {
Expand Down
30 changes: 25 additions & 5 deletions frontend/config/useUserMenuItems.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
// SPDX-FileCopyrightText: 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {userMenuItems} from './menuItems'
import {MenuItemType, userMenuItems} from './menuItems'
import {useSession} from '~/auth'
import useRsdSettings from './useRsdSettings'
import {useContext} from 'react'
import {RsdPluginContext} from './RsdPluginContext'

export default function useUserMenuItems(){
const {user} = useSession()
const {host} = useRsdSettings()
const {pluginSlots} = useContext(RsdPluginContext)

const items = userMenuItems.filter(item=>{
if (item.active){
return item.active({role: user?.role, modules: host.modules})
const items: MenuItemType[] = []

userMenuItems.forEach( (item) => {
if (item.active && item.active({role: user?.role, modules: host.modules})){
items.push(item)
} else if (item.type == 'pluginSlot') {
pluginSlots.forEach(
(pluginSlot) => {
if (pluginSlot.name == 'userMenuItem') {
items.push({
module: 'user',
type: 'link',
label: pluginSlot.title,
path: pluginSlot.href,
icon: typeof pluginSlot.icon === 'string' ? <span dangerouslySetInnerHTML={{__html: pluginSlot.icon}} /> : pluginSlot.icon as JSX.Element
})
}
}
)
}
return true
})

return items
Expand Down
6 changes: 6 additions & 0 deletions frontend/next.rewrites.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) <[email protected]>
// SPDX-FileCopyrightText: 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -47,6 +49,10 @@ if (process.env.NODE_ENV === 'docker') {
{
source: '/documentation/:path*',
destination: 'http://localhost/documentation/:path*',
},
{
source: '/modules/:path*',
destination: 'http://localhost/modules/:path*'
}
]
}
Expand Down
39 changes: 25 additions & 14 deletions frontend/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-FileCopyrightText: 2021 - 2023 dv4all
// SPDX-FileCopyrightText: 2022 - 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 Jesús García Gonzalez (Netherlands eScience Center) <[email protected]>
// SPDX-FileCopyrightText: 2023 - 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2023 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2023 - 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -41,14 +41,17 @@ import Announcement from '~/components/Announcement/Announcement'
// user settings (from cookies)
import {getUserSettings} from '~/utils/userSettings'
import {UserSettingsProps, UserSettingsProvider} from '~/config/UserSettingsContext'
import getUserPlugins from '~/utils/userPlugins'
import PluginSettingsProvider, {PluginSlot} from '~/config/RsdPluginContext'

// extend Next app props interface with emotion cache
export interface MuiAppProps extends AppProps {
emotionCache: EmotionCache
session: Session,
settings: RsdSettingsState,
matomo: Matomo,
userSettings?:UserSettingsProps
userSettings?: UserSettingsProps,
pluginSlots?: PluginSlot[]
}

// define npgrogres setup, no spinner
Expand Down Expand Up @@ -77,7 +80,7 @@ Router.events.on('routeChangeError', ()=>{
function RsdApp(props: MuiAppProps) {
const {
Component, emotionCache = clientSideEmotionCache,
pageProps, session, settings, matomo, userSettings
pageProps, session, settings, matomo, userSettings, pluginSlots
} = props

//currently we support only default (light) and dark RSD theme for MUI
Expand All @@ -94,6 +97,7 @@ function RsdApp(props: MuiAppProps) {
const [rsdSession] = useState(session)
const [rsdSettings] = useState(settings)
const [rsdUserSettings] = useState(userSettings)
const [rsdPluginSlots] = useState(pluginSlots)
// request theme when options changed
const {muiTheme, cssVariables} = useMemo(() => {
return loadMuiTheme(rsdSettings.theme)
Expand Down Expand Up @@ -136,13 +140,16 @@ function RsdApp(props: MuiAppProps) {
<AuthProvider session={rsdSession}>
{/* RSD settings/config */}
<RsdSettingsProvider settings={rsdSettings}>
{/* MUI snackbar service */}
<MuiSnackbarProvider>
{/* User settings rows, page layout etc. */}
<UserSettingsProvider user={rsdUserSettings}>
<Component {...pageProps} />
</UserSettingsProvider>
</MuiSnackbarProvider>
{/* Plugin slots context */}
<PluginSettingsProvider pluginSlots={rsdPluginSlots}>
{/* MUI snackbar service */}
<MuiSnackbarProvider>
{/* User settings rows, page layout etc. */}
<UserSettingsProvider user={rsdUserSettings}>
<Component {...pageProps} />
</UserSettingsProvider>
</MuiSnackbarProvider>
</PluginSettingsProvider>
</RsdSettingsProvider>
</AuthProvider>
{/* Matomo cookie consent dialog */}
Expand Down Expand Up @@ -190,6 +197,8 @@ RsdApp.getInitialProps = async(appContext:AppContext) => {
let session: Session | null = null
// user settings variable to extract from cookies
let userSettings:UserSettingsProps|null = null
// List of all plugins that can be used by the user
let pluginSlots: PluginSlot[] = []
// Matomo cached settings passed via getInitialProps
// Note! getInitialProps does not always run server side
// so we keep the last obtained values in this object
Expand All @@ -198,6 +207,8 @@ RsdApp.getInitialProps = async(appContext:AppContext) => {
id: process.env.MATOMO_ID || null,
consent: null
}
// extract rsd settings
const settings = await getSettingsServerSide(req, appContext.router.query)
// extract user session from cookies and
// matomo consent if matomo is used (id)
// only in SSR mode (req && res present)
Expand All @@ -209,11 +220,10 @@ RsdApp.getInitialProps = async(appContext:AppContext) => {
}
// get user settings from cookies
userSettings = getUserSettings(req)
pluginSlots = await getUserPlugins(session?.token, settings.host.plugins)
// set content security header
setContentSecurityPolicyHeader(res)
}
// extract rsd settings
const settings = await getSettingsServerSide(req, appContext.router.query)

// console.group('RsdApp.getInitialProps')
// console.log('session...', session)
Expand All @@ -227,7 +237,8 @@ RsdApp.getInitialProps = async(appContext:AppContext) => {
session,
settings,
matomo,
userSettings
userSettings,
pluginSlots
}
}

Expand Down
3 changes: 2 additions & 1 deletion frontend/public/data/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"limit": 5,
"description": null
},
"modules":["software","projects","organisations"]
"modules":["software","projects","organisations"],
"plugins": ["consult"]
},
"links": [
{
Expand Down
33 changes: 33 additions & 0 deletions frontend/utils/userPlugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2024 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
//
// SPDX-License-Identifier: Apache-2.0

import {PluginSlot} from '~/config/RsdPluginContext'
import {createJsonHeaders} from './fetchHelpers'

export default async function getUserPlugins(
token?: string, plugins?: string[]
) {
if (!token || !plugins) {
return []
}

const promises = plugins?.map(async pluginPath => {
const url = `/modules/${pluginPath}/config`
try {
const response = await fetch(url, {
headers: {
...createJsonHeaders(token)
},
signal: AbortSignal.timeout(200)
})
return response.json() as Promise<PluginSlot>
} catch (e) {
console.log(`Failed to load plugin config for plugin ${pluginPath}`, e)
return []
}
})
const pluginSlots = await Promise.all(promises ?? []) as PluginSlot[]
return pluginSlots.flat()
}
7 changes: 7 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ upstream backend {
upstream authentication {
server auth:7000;
}
upstream consult {
server middleware:8080;
}

server {
listen 80;
Expand Down Expand Up @@ -79,6 +82,10 @@ server {
proxy_pass http://backend/;
}

location /modules/consult/ {
proxy_pass http://consult/;
}

location /metadata/codemeta/ {
proxy_pass http://codemeta:8000/;
proxy_redirect ~(.*) /metadata/codemeta$1;
Expand Down

0 comments on commit c7aae51

Please sign in to comment.