Merge branch 'main' into reporting

This commit is contained in:
Darren Clarke 2025-02-13 09:49:55 +01:00
commit 5a1be0de94
19 changed files with 2058 additions and 230 deletions

View file

@ -29,6 +29,8 @@
"@link-stack/ui": "*"
},
"devDependencies": {
"@link-stack/eslint-config": "*",
"@link-stack/typescript-config": "*",
"@types/node": "^22",
"@types/pg": "^8.11.11",
"@types/react": "^19",

View file

@ -12,6 +12,7 @@ import {
import {
Apple as AppleIcon,
Google as GoogleIcon,
Microsoft as MicrosoftIcon,
Key as KeyIcon,
} from "@mui/icons-material";
import { signIn, getProviders } from "next-auth/react";
@ -183,6 +184,21 @@ export const Login: FC<LoginProps> = ({ session }) => {
</IconButton>
</Grid>
)}
{provider === "azure-ad" && (
<Grid item sx={{ width: "100%" }}>
<IconButton
sx={buttonStyles}
onClick={() =>
signIn("azure-ad", {
callbackUrl: `${origin}`,
})
}
>
<MicrosoftIcon sx={{ mr: 1 }} />
Sign in with Azure
</IconButton>
</Grid>
)}
{provider === "credentials" && (
<Grid item container spacing={3}>
<Grid item sx={{ width: "100%" }}>

View file

@ -477,14 +477,6 @@ export const Sidebar: FC<SidebarProps> = ({
/>
</List>
</Collapse>
<MenuItem
name="Knowledge Base"
href="/knowledge"
Icon={SchoolIcon}
iconSize={20}
selected={pathname.endsWith("/knowledge")}
open={open}
/>
<MenuItem
name="Documentation"
href="/docs"
@ -567,14 +559,6 @@ export const Sidebar: FC<SidebarProps> = ({
/>
</List>
</Collapse>
<MenuItem
name="Profile"
href="/profile"
Icon={PersonIcon}
iconSize={20}
selected={pathname.endsWith("/profile")}
open={open}
/>
{roles.includes("admin") && (
<>
<MenuItem
@ -641,36 +625,10 @@ export const Sidebar: FC<SidebarProps> = ({
/>
</List>
</Collapse>
<MenuItem
name="Zammad Settings"
href="/admin/zammad"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/admin/zammad")}
open={open}
/>
{roles.includes("label_studio") && (
<MenuItem
name="Label Studio"
href="/admin/label-studio"
Icon={FeaturedPlayListIcon}
iconSize={0}
selected={pathname.endsWith("/admin/label-studio")}
open={open}
/>
)}
</List>
</Collapse>
</>
)}
<MenuItem
name="Zammad Interface"
href="/zammad"
Icon={DvrIcon}
iconSize={20}
open={open}
target="_blank"
/>
<MenuItem
name="Logout"
href="/logout"

View file

@ -20,7 +20,7 @@ export const MultiProvider: FC<PropsWithChildren> = ({ children }) => {
const locale = "en";
return (
<SessionProvider>
<SessionProvider basePath="/link/api/auth">
<CssBaseline />
<ZammadLoginProvider>
<CookiesProvider>

View file

@ -11,6 +11,7 @@ import Google from "next-auth/providers/google";
import Credentials from "next-auth/providers/credentials";
import Apple from "next-auth/providers/apple";
import { Redis } from "ioredis";
import AzureADProvider from "next-auth/providers/azure-ad";
const headers = { Authorization: `Token ${process.env.ZAMMAD_API_TOKEN}` };
@ -86,6 +87,18 @@ if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) {
clientSecret: process.env.APPLE_CLIENT_SECRET,
}),
);
} else if (
process.env.AZURE_AD_CLIENT_ID &&
process.env.AZURE_AD_CLIENT_SECRET &&
process.env.AZURE_AD_TENANT_ID
) {
providers.push(
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
}),
);
} else {
providers.push(
Credentials({

View file

@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { withAuth, NextRequestWithAuth } from "next-auth/middleware";
/*
const rewriteURL = (
request: NextRequestWithAuth,
originBaseURL: string,
@ -27,7 +28,7 @@ const rewriteURL = (
request: { headers: requestHeaders },
});
};
*/
const checkRewrites = async (request: NextRequestWithAuth) => {
const linkBaseURL = process.env.LINK_URL ?? "http://localhost:3000";
const zammadURL = process.env.ZAMMAD_URL ?? "http://zammad-nginx:8080";
@ -86,30 +87,29 @@ const checkRewrites = async (request: NextRequestWithAuth) => {
frame-ancestors 'self';
upgrade-insecure-requests;
`;
const contentSecurityPolicyHeaderValue = cspHeader
.replace(/\s{2,}/g, " ")
.trim();
const contentSecurityPolicyHeaderValue = cspHeader
.replace(/\s{2,}/g, " ")
.trim();
const requestHeaders = new Headers(request.headers);
requestHeaders.set("x-nonce", nonce);
requestHeaders.set(
"Content-Security-Policy",
contentSecurityPolicyHeaderValue,
);
const requestHeaders = new Headers(request.headers);
requestHeaders.set("x-nonce", nonce);
requestHeaders.set(
"Content-Security-Policy",
contentSecurityPolicyHeaderValue,
);
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
});
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
});
response.headers.set(
"Content-Security-Policy",
contentSecurityPolicyHeaderValue,
);
response.headers.set(
"Content-Security-Policy",
contentSecurityPolicyHeaderValue,
);
return response;
}
return response;
};
export default withAuth(checkRewrites, {

View file

@ -1,5 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: '/link',
poweredByHeader: false,
transpilePackages: [
"@link-stack/leafcutter-ui",
@ -30,20 +31,6 @@ const nextConfig = {
},
];
},
rewrites: async () => {
return {
beforeFiles: [
{
source: "/api/v1/:path*",
destination: `${process.env.ZAMMAD_URL ?? "http://zammad-nginx:8080"}/api/v1/:path*`,
},
{
source: "/ws",
destination: `${process.env.ZAMMAD_URL ?? "http://zammad-nginx:8080"}/ws`,
},
],
};
},
};
export default nextConfig;