diff --git a/.env.development b/.env.development deleted file mode 100644 index a75c3062..00000000 --- a/.env.development +++ /dev/null @@ -1,4 +0,0 @@ -DIRACX_CLIENT_ID=myDIRACClientID -REDIRECT_URI=http://localhost:3000/dashboard/#authentication-callback -DEFAULT_SCOPE="vo:diracAdmin" -NEXT_PUBLIC_DIRACX_URL=http://localhost:8000 diff --git a/.env.production b/.env.production deleted file mode 100644 index 440a14f9..00000000 --- a/.env.production +++ /dev/null @@ -1,4 +0,0 @@ -DIRACX_CLIENT_ID=interactive.public.short -REDIRECT_URI=http://localhost:3000/dashboard/#authentication-callback -DEFAULT_SCOPE="openid profile email api offline_access" -NEXT_PUBLIC_DIRACX_URL=https://demo.duendesoftware.com diff --git a/.github/workflows/containerised.yml b/.github/workflows/containerised.yml index 1b15fd3e..24328c1f 100644 --- a/.github/workflows/containerised.yml +++ b/.github/workflows/containerised.yml @@ -27,5 +27,5 @@ jobs: with: context: . push: ${{ github.event_name == 'push' && github.repository == 'DIRACGrid/diracx-web' && github.ref_name == 'main' }} - tags: ghcr.io/diracgrid/diracx-web/client:latest + tags: ghcr.io/diracgrid/diracx-web/static:latest platforms: linux/amd64,linux/arm64 diff --git a/Dockerfile b/Dockerfile index 3f3e4cd2..4fcf6992 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,16 @@ -FROM node:16-alpine -EXPOSE 3000 - -# Set the working directory in the container +# Minimize the size and complexity of the final Docker image by separating the +# build stage and the runtime stage into two different steps +FROM node:16-alpine AS build WORKDIR /app - -# Copy package.json and package-lock.json to the working directory +# Install the project dependencies COPY package*.json ./ - -# Install project dependencies -RUN npm install - +RUN npm ci # Copy the rest of the application to the working directory COPY . . +# Build the static export with telemetry disabled (https://nextjs.org/telemetry) +RUN NEXT_TELEMETRY_DISABLED=1 npm run build -# Disable telemetry. Further details: https://nextjs.org/telemetry -ENV NEXT_TELEMETRY_DISABLED 1 - -# Build the Next.js app for production -RUN npm run build - -# Define the command to run the app -CMD [ "npm", "start" ] +# Copy the website from the previous container to a Nginx container +FROM nginxinc/nginx-unprivileged:alpine +EXPOSE 8080 +COPY --from=build /app/out /usr/share/nginx/html diff --git a/next.config.js b/next.config.js index 658404ac..8d7f01b5 100644 --- a/next.config.js +++ b/next.config.js @@ -1,4 +1,9 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + output: "export", + images: { + unoptimized: true, + }, +}; module.exports = nextConfig; diff --git a/src/app/dashboard/jobmonitor/[id]/page.tsx b/src/app/dashboard/jobmonitor/[id]/page.tsx deleted file mode 100644 index 01b7137e..00000000 --- a/src/app/dashboard/jobmonitor/[id]/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Page({ params }: { params: { id: string } }) { - return

Hello, Job Monitoring {params.id} Page!

; -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index aba44b2d..e4b1ce0a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,21 +1,17 @@ import "./globals.css"; import { Inter } from "next/font/google"; import { OIDCProvider } from "@/components/auth/OIDCUtils"; -import { OidcConfiguration } from "@axa-fr/react-oidc"; const inter = Inter({ subsets: ["latin"] }); export const metadata = { - title: "diracX", + title: "DiracX", description: "Distributed Infrastructure with Remote Agent Controller", }; -const configuration: OidcConfiguration = { - client_id: process.env.DIRACX_CLIENT_ID || "", - redirect_uri: process.env.REDIRECT_URI || "", - scope: process.env.DEFAULT_SCOPE || "", - authority: process.env.NEXT_PUBLIC_DIRACX_URL || "", -}; +// Force an error if any components use dynamic functions or uncached data +// as these won't work in the static export. +export const dynamic = "error"; export default function RootLayout({ children, @@ -25,7 +21,7 @@ export default function RootLayout({ return ( - {children} + {children} ); diff --git a/src/components/auth/OIDCUtils.tsx b/src/components/auth/OIDCUtils.tsx index 062a4b3e..1cf977fe 100644 --- a/src/components/auth/OIDCUtils.tsx +++ b/src/components/auth/OIDCUtils.tsx @@ -4,10 +4,10 @@ import { OidcProvider, OidcSecure, } from "@axa-fr/react-oidc"; -import React from "react"; +import React, { useState, useEffect } from "react"; +import { useDiracxUrl } from "@/hooks/utils"; interface OIDCProviderProps { - configuration: OidcConfiguration; children: React.ReactNode; } @@ -30,11 +30,32 @@ export function OIDCProvider(props: OIDCProviderProps) { }, }; }; + const diracxUrl = useDiracxUrl(); + const [configuration, setConfiguration] = useState( + null, + ); + + useEffect(() => { + if (diracxUrl !== null) { + setConfiguration((prevConfig) => ({ + authority: diracxUrl, + // TODO: Figure out how to get this. Hardcode? Get from a /.well-known/diracx-configuration endpoint? + client_id: "myDIRACClientID", + // TODO: Get this from the /.well-known/openid-configuration endpoint + scope: "vo:diracAdmin", + redirect_uri: `${diracxUrl}/#authentication-callback`, + })); + } + }, [diracxUrl]); + + if (configuration === null) { + return <>; + } return ( <>
{props.children}
diff --git a/src/hooks/jobs.tsx b/src/hooks/jobs.tsx index dfc2b474..d511273a 100644 --- a/src/hooks/jobs.tsx +++ b/src/hooks/jobs.tsx @@ -1,5 +1,6 @@ import { useOidcAccessToken } from "@axa-fr/react-oidc"; import useSWR from "swr"; +import { useDiracxUrl } from "./utils"; const fetcher = (args: any[]) => { const [url, accessToken] = args; @@ -14,10 +15,15 @@ const fetcher = (args: any[]) => { }; export function useJobs() { + const diracxUrl = useDiracxUrl(); const { accessToken } = useOidcAccessToken(); - const url = `${process.env.NEXT_PUBLIC_DIRACX_URL}/api/jobs/search?page=0&per_page=100`; + const url = `${diracxUrl}/api/jobs/search?page=0&per_page=100`; const { data, error } = useSWR([url, accessToken], fetcher); + if (diracxUrl === null) { + return { data: null, error: "diracxUrl is null", isLoading: false }; + } + return { data, error, diff --git a/src/hooks/utils.tsx b/src/hooks/utils.tsx new file mode 100644 index 00000000..12683886 --- /dev/null +++ b/src/hooks/utils.tsx @@ -0,0 +1,16 @@ +import { useEffect, useState } from "react"; + +export function useDiracxUrl() { + const [diracxUrl, setDiracxUrl] = useState(null); + + useEffect(() => { + // Ensure this runs on client side + if (typeof window !== "undefined") { + setDiracxUrl( + (prevConfig) => `${window.location.protocol}//${window.location.host}`, + ); + } + }, []); + + return diracxUrl; +}