Skip to content

Commit

Permalink
Merge pull request #141 from QCDIS/138-make-homepage-customizable
Browse files Browse the repository at this point in the history
138 make homepage customizable
  • Loading branch information
gpelouze authored Sep 14, 2023
2 parents 56144c5 + 9533c5b commit 56a2cc2
Show file tree
Hide file tree
Showing 16 changed files with 255 additions and 93 deletions.
47 changes: 47 additions & 0 deletions vre-panel/context/PaasConfig.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {useEffect, useState, createContext, ReactNode} from "react";
import getConfig from "next/config";


export const PaasConfigContext = createContext({
paasConfig: {
title: "",
description: "",
documentation_url: "",
site_icon: "",
},
paasConfigLoading: true,
});

export function PaasConfigProvider({children,}: { children: ReactNode }) {
const {publicRuntimeConfig} = getConfig()

const [paasConfig, setPaasConfig] = useState({
title: "Virtual Lab environments",
description: "A collection of virtual lab environments",
documentation_url: "https://github.com/QCDIS/NaaVRE/blob/main/README.md",
site_icon: `${publicRuntimeConfig.staticFolder}/LW_ERIC_Logo.png`,
})
const [paasConfigLoading, setPaasConfigLoading] = useState(true)

useEffect(() => {
const apiUrl = `${window.location.origin}/${publicRuntimeConfig.apiBasePath}`
fetch(`${apiUrl}/paas_configuration`)
.then((res) => res.json())
.then((data) => {
if (data.length > 0) {
setPaasConfig(data[0]);
}
setPaasConfigLoading(false)
})
.catch((error) => {
console.log(error)
setPaasConfigLoading(false)
});
}, []);

return (
<PaasConfigContext.Provider value={{paasConfig: paasConfig, paasConfigLoading: paasConfigLoading}}>
{children}
</PaasConfigContext.Provider>
);
}
2 changes: 1 addition & 1 deletion vre-panel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
},
"devDependencies": {
"typescript": "^4.5",
"@types/node": "~20.5.7",
"@types/node": "~20.4.5",
"@types/react": "~18.2.0",
"autoprefixer": "~10.4.15",
"axios-mock-adapter": "~1.21.5",
Expand Down
6 changes: 5 additions & 1 deletion vre-panel/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { useState } from 'react';
// import RefreshTokenHandler from './auth/refreshTokenHandler';
import getConfig from 'next/config'

import {PaasConfigProvider} from '../context/PaasConfig';

export default function App({ Component, pageProps: { session, ...pageProps }} : AppProps): JSX.Element {

const { publicRuntimeConfig } = getConfig()
Expand All @@ -13,7 +15,9 @@ export default function App({ Component, pageProps: { session, ...pageProps }} :

return (
<SessionProvider session={session} refetchInterval={interval} basePath={`${publicRuntimeConfig.basePath}/api/auth`}>
<Component {...pageProps} />
<PaasConfigProvider>
<Component {...pageProps} />
</PaasConfigProvider>
</SessionProvider>
)
}
13 changes: 12 additions & 1 deletion vre-panel/pages/auth/signin.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { getProviders, getSession, signIn } from "next-auth/react"
import getConfig from 'next/config'
import {useContext} from "react";
import {PaasConfigContext} from "../../context/PaasConfig";

const { publicRuntimeConfig } = getConfig()

export default function SignIn({ providers }: { providers: any }) {

const {paasConfig, paasConfigLoading} = useContext(PaasConfigContext)

return (
<div className="mx-auto flex flex-col items-center justify-center h-screen">
<img className="w-fit h-fit object-cover" src={`${publicRuntimeConfig.staticFolder}/LW_VLICVRE_logo.png`} />
<div className="flex flex-col justify-center rounded-md overflow-hidden shadow-lg bg-white p-10 mt-10 w-screen">
<img src={`${publicRuntimeConfig.staticFolder}/LW_ERIC_Logo.png`} className="w-36 self-center" alt="LifeWatch Logo" />
{paasConfigLoading || (
<img
src={paasConfig.site_icon}
alt="Site icon"
className="h-16 self-center"
/>
)}
<>
{Object.values(providers).map((provider: any) => (
<div className="self-center" key={provider.name}>
Expand Down
203 changes: 115 additions & 88 deletions vre-panel/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,106 +1,133 @@
import { getToken } from 'next-auth/jwt';
// import { signIn, useSession } from 'next-auth/react';
import {useEffect, useState, useContext} from 'react';
import getConfig from 'next/config';
import Link from 'next/link';
import { useEffect, useState } from 'react';
import { NewVREDialog } from '../components/NewVREDialog';
import { Nav } from '../templates/Nav';
// import useAuth from './auth/useAuth';

import {NewVREDialog} from '../components/NewVREDialog';
import {Nav} from '../templates/Nav';
import {PaasConfigContext} from '../context/PaasConfig';

const getSlug = (title: string) => {

return title
.toLowerCase()
.replace(/ /g, '-')
.replace(/[^\w-]+/g, '');
return title
.toLowerCase()
.replace(/ /g, '-')
.replace(/[^\w-]+/g, '');
}

const VLabs = () => {

const { publicRuntimeConfig } = getConfig()

// const isAuthenticated = useAuth(true);
const [isOpen, setIsOpen] = useState(false);
const [vlabs, setVlabs] = useState([]);
const VLabs = ({}) => {

useEffect(() => {
const {publicRuntimeConfig} = getConfig()

// if (isAuthenticated) {
const {paasConfig, paasConfigLoading} = useContext(PaasConfigContext)

// var requestOptions: RequestInit = {
// method: "GET",
// headers: {
// "Authorization": "Bearer: " + token.accessToken
// },
// };
const apiUrl = `${window.location.origin}/${publicRuntimeConfig.apiBasePath}`
fetch(`${apiUrl}/vlabs`)
.then((res) => res.json())
.then((data) => {
setVlabs(data);
})
.catch((error) => {
console.log(error)
});
// }
}, []);
const [isOpen, setIsOpen] = useState(false);
const [vlabs, setVlabs] = useState([]);
const [vlabsLoading, setVlabsLoading] = useState(true);

// const { status } = useSession({
// required: true,
// onUnauthenticated() {
// signIn();
// },
// })
useEffect(() => {

// if (status === "loading") {
// return "Loading or not authenticated..."
// }
const apiUrl = `${window.location.origin}/${publicRuntimeConfig.apiBasePath}`
fetch(`${apiUrl}/vlabs`)
.then((res) => res.json())
.then((data) => {
setVlabs(data);
setVlabsLoading(false)
})
.catch((error) => {
console.log(error)
setVlabsLoading(false)
});
}, []);

return (
<div>
<Nav />
<div className='min-h-screen mx-auto bg-gradient-to-b from-sky-100 to-orange-300'>
<div className='grid grid-cols-3'>
{vlabs.map((vlab: any) => {
return (
<div key={getSlug(vlab.title)} className="max-w-sm rounded overflow-hidden shadow-lg bg-white m-10">
<Link
href={{
pathname: '/vlabs/[slug]',
query: { slug: vlab.slug }
}}
>
<div>
<img className="w-35 h-30 object-cover" src={`${publicRuntimeConfig.staticFolder}/HP-VRES.png`} />
<div className="font-bold text-l mb-2 bg-blue-500 text-white p-5">{vlab.title}</div>
<div className="px-3 py-2">
<p className="text-gray-700 text-base truncate ...">
{vlab.description}
</p>
</div>
</div>
</Link>
</div>
);
})}
return (
<div>
<Nav/>
<div className='min-h-screen mx-auto bg-gradient-to-b from-sky-100 to-orange-300 space-y-10 p-10'>
<div className="max-w-full rounded bg-white p-8">
<h1 className="text-2xl text-gray-800 mb-8">
{paasConfigLoading ? (
<span className="animate-pulse">
<span className="inline-block min-h-[1em] w-3/12 flex-auto cursor-wait bg-current align-middle opacity-50"></span>
</span>
) : (
paasConfig.title
)}
</h1>
<p className="text-l text-gray-800">
{paasConfigLoading ? (
<span className="animate-pulse">
<span className="inline-block min-h-[1em] w-full flex-auto cursor-wait bg-current align-middle opacity-50"></span>
</span>
) : (
paasConfig.description
)}
</p>
{paasConfigLoading || (
paasConfig.documentation_url && (
<p className="mt-4">
<a
href={paasConfig.documentation_url}
className="text-blue-800 hover:underline"
>
Documentation
</a>
</p>
)
)}
</div>
<div className='flex flex-row space-x-10'>
{vlabsLoading ? (
<div className="w-1/3 rounded overflow-hidden shadow-lg bg-white animate">
<div>
<img className="w-35 h-30 object-cover" src={`${publicRuntimeConfig.staticFolder}/HP-VRES.png`}/>
<div className="font-bold text-l mb-2 bg-gray-300 text-white p-5">
<p className="animate-pulse">
<span className="inline-block min-h-[1em] w-6/12 flex-auto cursor-wait bg-current align-middle opacity-50"></span>
</p>
</div>
<div className="px-3 py-2">
<p className="text-gray-700 text-base truncate animate-pulse ...">
<span className="inline-block min-h-[0.6em] w-6/12 flex-auto cursor-wait bg-current align-middle opacity-50"></span>
</p>
</div>
<NewVREDialog isOpen={isOpen} setIsOpen={setIsOpen} />
</div>
</div>
</div >
)
) : (
vlabs.length > 0 ? (
vlabs.map((vlab: any) => {
return (
<div key={getSlug(vlab.title)} className="w-1/3 rounded overflow-hidden shadow-lg bg-white">
<Link
href={{
pathname: '/vlabs/[slug]',
query: {slug: vlab.slug}
}}
>
<div>
<img className="w-35 h-30 object-cover" src={`${publicRuntimeConfig.staticFolder}/HP-VRES.png`}/>
<div className="font-bold text-l mb-2 bg-blue-500 text-white p-5">{vlab.title}</div>
<div className="px-3 py-2">
<p className="text-gray-700 text-base truncate ...">
{vlab.description}
</p>
</div>
</div>
</Link>
</div>
);
})
) : (
<div className="w-1/3 rounded overflow-hidden shadow-lg bg-white">
No virtual labs found
</div>
)
)
}
</div>
<NewVREDialog isOpen={isOpen} setIsOpen={setIsOpen}/>
</div>
</div>
)
};

export async function getServerSideProps(context:any) {

const { req } = context;
const secret = process.env.SECRET;
const token = await getToken({ req, secret });

return {
props: {
token: token
}
};
}

export default VLabs;
14 changes: 12 additions & 2 deletions vre-panel/templates/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@ import Link from 'next/link';
import { Menu, Transition } from '@headlessui/react';
import { useSession, signIn, signOut } from "next-auth/react"
import getConfig from 'next/config'
import {useContext} from "react";
import {PaasConfigContext} from "../context/PaasConfig";


const Nav = () => {

const { publicRuntimeConfig } = getConfig()
const { data: session, status } = useSession()

const {paasConfig, paasConfigLoading} = useContext(PaasConfigContext)

return (
<header className="sticky top-0 z-30 w-full px-2 py-4 bg-white sm:px-4 shadow-xl">
<nav className="bg-white border-gray-200 px-2 sm:px-4 py-2.5 rounded dark:bg-gray-800">
<nav className="bg-white border-gray-200 px-2 sm:px-4 rounded dark:bg-gray-800">
<div className="container flex flex-wrap justify-between items-center mx-auto">
<Link href='/' className="flex items-center">
<img src={`${publicRuntimeConfig.staticFolder}/LW_ERIC_Logo.png`} className="mr-3 h-6 h-14" alt="LifeWatch Logo" />
{paasConfigLoading || (
<img
src={paasConfig.site_icon}
alt="Site icon"
className="mr-3 h-16"
/>
)}
</Link>
<div className="flex items-center md:order-2">
<div className="relative inline-block text-left">
Expand Down
Empty file.
4 changes: 4 additions & 0 deletions vreapis/paas_configuration/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from django.contrib import admin
from .models import PaasConfiguration

admin.site.register(PaasConfiguration)
6 changes: 6 additions & 0 deletions vreapis/paas_configuration/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class PaasConfigurationConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'paas_configuration'
Empty file.
17 changes: 17 additions & 0 deletions vreapis/paas_configuration/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django.db import models

# Create your models here.


class PaasConfiguration(models.Model):
title = models.CharField(max_length=100, null=True)
description = models.TextField(null=True)
documentation_url = models.URLField(null=True, blank=True)
site_icon = models.TextField(
null=True,
help_text=("Base 64-encoded image, eg. data:image/png;base64,"
"ZXhhbXBsZQo="),
)

def __str__(self):
return self.title
Loading

0 comments on commit 56a2cc2

Please sign in to comment.