cleaning
This commit is contained in:
parent
3b81ad058a
commit
a4412c081a
@ -15,13 +15,15 @@ const menuItems: Record<string, string> = {
|
||||
dossiers: process.env.NEXT_PUBLIC_IFRAME_DRIVE_URL || '',
|
||||
'the-message': process.env.NEXT_PUBLIC_IFRAME_THEMESSAGE_URL || '',
|
||||
qg: process.env.NEXT_PUBLIC_IFRAME_MISSIONVIEW_URL || '',
|
||||
// Keep any existing custom ones
|
||||
board: "https://example.com/board",
|
||||
chapter: "https://example.com/chapter",
|
||||
flow: "https://example.com/flow",
|
||||
design: "https://example.com/design",
|
||||
// Use environment variables for these items too
|
||||
board: process.env.NEXT_PUBLIC_IFRAME_BOARD_URL || '',
|
||||
chapter: process.env.NEXT_PUBLIC_IFRAME_CHAPTER_URL || '',
|
||||
flow: process.env.NEXT_PUBLIC_IFRAME_FLOW_URL || '',
|
||||
design: process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '',
|
||||
artlab: process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '',
|
||||
// External URLs
|
||||
gitlab: "https://gitlab.com",
|
||||
missions: "https://example.com/missions"
|
||||
missions: process.env.NEXT_PUBLIC_IFRAME_MISSIONSBOARD_URL || ''
|
||||
}
|
||||
|
||||
// Using a different approach for metadata that doesn't directly access params.section
|
||||
|
||||
@ -82,25 +82,13 @@ export const authOptions: NextAuthOptions = {
|
||||
},
|
||||
callbacks: {
|
||||
async jwt({ token, account, profile, user }: any) {
|
||||
// Debug input parameters to understand what's available
|
||||
console.log('JWT callback - input parameters:', {
|
||||
hasAccount: !!account,
|
||||
hasProfile: !!profile,
|
||||
hasUser: !!user,
|
||||
hasToken: !!token,
|
||||
tokenSub: token?.sub,
|
||||
tokenAccessToken: token?.accessToken ? '[exists]' : undefined
|
||||
});
|
||||
|
||||
// Initial sign in
|
||||
if (account && account.access_token) {
|
||||
console.log('JWT callback - NEW SIGN IN with access token detected');
|
||||
token.accessToken = account.access_token;
|
||||
token.refreshToken = account.refresh_token;
|
||||
|
||||
// Process the raw profile data if available
|
||||
if (user && user.raw_profile) {
|
||||
console.log('JWT callback - Raw profile data found, extracting roles');
|
||||
const rawProfile = user.raw_profile;
|
||||
|
||||
// Extract roles from all possible sources
|
||||
@ -108,7 +96,6 @@ export const authOptions: NextAuthOptions = {
|
||||
|
||||
// Get roles from realm_access
|
||||
if (rawProfile.realm_access && Array.isArray(rawProfile.realm_access.roles)) {
|
||||
console.log('Found realm_access roles:', rawProfile.realm_access.roles);
|
||||
roles = roles.concat(rawProfile.realm_access.roles);
|
||||
}
|
||||
|
||||
@ -118,14 +105,12 @@ export const authOptions: NextAuthOptions = {
|
||||
if (clientId &&
|
||||
rawProfile.resource_access[clientId] &&
|
||||
Array.isArray(rawProfile.resource_access[clientId].roles)) {
|
||||
console.log('Found client-specific roles:', rawProfile.resource_access[clientId].roles);
|
||||
roles = roles.concat(rawProfile.resource_access[clientId].roles);
|
||||
}
|
||||
|
||||
// Also check resource_access roles under 'account'
|
||||
if (rawProfile.resource_access.account &&
|
||||
Array.isArray(rawProfile.resource_access.account.roles)) {
|
||||
console.log('Found account roles:', rawProfile.resource_access.account.roles);
|
||||
roles = roles.concat(rawProfile.resource_access.account.roles);
|
||||
}
|
||||
}
|
||||
@ -138,18 +123,13 @@ export const authOptions: NextAuthOptions = {
|
||||
// Always ensure user has basic user role
|
||||
const finalRoles = [...new Set([...cleanedRoles, 'user'])];
|
||||
|
||||
// Add the application-specific roles for testing
|
||||
finalRoles.push('admin', 'dataintelligence', 'coding', 'expression', 'mediation');
|
||||
|
||||
// Store roles in token
|
||||
token.role = [...new Set(finalRoles)]; // Ensure uniqueness
|
||||
console.log('JWT callback - Extracted roles:', token.role);
|
||||
// Map Keycloak roles to application roles
|
||||
token.role = mapToApplicationRoles(finalRoles);
|
||||
} else if (user && user.role) {
|
||||
console.log('JWT callback - Using roles from user object:', user.role);
|
||||
token.role = Array.isArray(user.role) ? user.role : [user.role];
|
||||
} else {
|
||||
console.log('JWT callback - No profile data, setting default roles');
|
||||
token.role = ['user', 'admin', 'dataintelligence', 'coding', 'expression', 'mediation'];
|
||||
// Default roles if no profile data available
|
||||
token.role = ['user'];
|
||||
}
|
||||
|
||||
// Store user information
|
||||
@ -159,30 +139,14 @@ export const authOptions: NextAuthOptions = {
|
||||
token.last_name = user.last_name || '';
|
||||
}
|
||||
}
|
||||
// Token exists but no roles, add default roles for testing
|
||||
// Token exists but no roles, add default user role
|
||||
else if (token && !token.role) {
|
||||
console.log('JWT callback - Token exists but no roles, adding defaults');
|
||||
// For testing purposes, add all roles
|
||||
token.role = ['user', 'admin', 'dataintelligence', 'coding', 'expression', 'mediation'];
|
||||
token.role = ['user'];
|
||||
}
|
||||
|
||||
// Log the token roles
|
||||
console.log('JWT token structure:', JSON.stringify({
|
||||
sub: token.sub,
|
||||
role: token.role,
|
||||
username: token.username
|
||||
}, null, 2));
|
||||
console.log('JWT token roles:', token.role);
|
||||
return token;
|
||||
},
|
||||
async session({ session, token }: any) {
|
||||
console.log('Session callback - input parameters:', {
|
||||
hasSession: !!session,
|
||||
hasToken: !!token,
|
||||
tokenRole: token?.role,
|
||||
tokenSub: token?.sub
|
||||
});
|
||||
|
||||
// Pass necessary info to the session
|
||||
session.accessToken = token.accessToken;
|
||||
if (session.user) {
|
||||
@ -194,18 +158,13 @@ export const authOptions: NextAuthOptions = {
|
||||
session.user.username = token.username || '';
|
||||
session.user.first_name = token.first_name || '';
|
||||
session.user.last_name = token.last_name || '';
|
||||
console.log('Session callback - using token roles:', token.role);
|
||||
} else {
|
||||
// Fallback roles - ENSURE ALL REQUIRED ROLES ARE INCLUDED
|
||||
session.user.role = ["user", "admin", "dataintelligence", "coding", "expression", "mediation"];
|
||||
// Fallback roles
|
||||
session.user.role = ["user"];
|
||||
session.user.username = '';
|
||||
session.user.first_name = '';
|
||||
session.user.last_name = '';
|
||||
console.log('Session callback - no token roles, using fallback');
|
||||
}
|
||||
|
||||
// Log the session user roles
|
||||
console.log('Session user roles:', session.user.role);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
@ -225,7 +184,7 @@ export const authOptions: NextAuthOptions = {
|
||||
},
|
||||
},
|
||||
},
|
||||
debug: true, // Enable debug logs to help with troubleshooting
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
};
|
||||
|
||||
/**
|
||||
@ -250,39 +209,21 @@ function mapToApplicationRoles(keycloakRoles: string[]): string[] {
|
||||
// Add more mappings as needed
|
||||
};
|
||||
|
||||
// Convert all keycloak roles to lowercase for case-insensitive matching
|
||||
const lowerKeycloakRoles = keycloakRoles.map(role => role.toLowerCase());
|
||||
// Map each role and flatten the result
|
||||
let appRoles: string[] = ['user']; // Always include 'user' role
|
||||
|
||||
// Map roles based on the defined mappings
|
||||
let applicationRoles: string[] = [];
|
||||
|
||||
// Check all Keycloak roles for matches in our mapping
|
||||
for (const role of lowerKeycloakRoles) {
|
||||
if (mappings[role]) {
|
||||
applicationRoles = applicationRoles.concat(mappings[role]);
|
||||
}
|
||||
|
||||
// Handle any role that contains certain keywords
|
||||
if (role.includes('admin')) {
|
||||
applicationRoles.push('admin', 'dataintelligence', 'coding', 'expression', 'mediation');
|
||||
} else if (role.includes('developer') || role.includes('dev')) {
|
||||
applicationRoles.push('coding', 'dataintelligence');
|
||||
} else if (role.includes('design')) {
|
||||
applicationRoles.push('expression');
|
||||
} else if (role.includes('data')) {
|
||||
applicationRoles.push('dataintelligence');
|
||||
} else if (role.includes('mediat')) {
|
||||
applicationRoles.push('mediation');
|
||||
for (const role of keycloakRoles) {
|
||||
const mappedRoles = mappings[role.toLowerCase()];
|
||||
if (mappedRoles) {
|
||||
appRoles = [...appRoles, ...mappedRoles];
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure user always has basic access
|
||||
applicationRoles.push('user');
|
||||
|
||||
// Return unique application roles
|
||||
return [...new Set(applicationRoles)];
|
||||
// Remove duplicates and return
|
||||
return [...new Set(appRoles)];
|
||||
}
|
||||
|
||||
const handler = NextAuth(authOptions);
|
||||
|
||||
export { handler as GET, handler as POST };
|
||||
|
||||
|
||||
@ -10,14 +10,14 @@ export default async function ArtlabPage() {
|
||||
redirect("/signin");
|
||||
}
|
||||
|
||||
// Get the direct URL from environment variable
|
||||
const iframeUrl = process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '';
|
||||
// Get the design URL from environment variable - intentionally shares URL with design section
|
||||
const designIframeUrl = process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '';
|
||||
|
||||
return (
|
||||
<main className="w-full h-screen bg-black">
|
||||
<div className="w-full h-full px-4 pt-12 pb-4">
|
||||
<ResponsiveIframe
|
||||
src={iframeUrl}
|
||||
src={designIframeUrl}
|
||||
allowFullScreen={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -27,7 +27,6 @@ const SERVICE_URLS: Record<string, string> = {
|
||||
'the-message': process.env.NEXT_PUBLIC_IFRAME_THEMESSAGE_URL || '',
|
||||
'qg': process.env.NEXT_PUBLIC_IFRAME_MISSIONVIEW_URL || '',
|
||||
'design': process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || '',
|
||||
'artlab': process.env.NEXT_PUBLIC_IFRAME_DESIGN_URL || ''
|
||||
};
|
||||
|
||||
export default function ResponsiveIframe({
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
|
||||
export function Todo() {
|
||||
const todos = [
|
||||
{ text: "send e-mails", done: false },
|
||||
{ text: "do the visuals", done: false },
|
||||
{ text: "write the contract", done: false },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card className='transition-transform duration-500 ease-in-out transform hover:scale-105'>
|
||||
<CardHeader>
|
||||
<CardTitle>Todo</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className='space-y-4'>
|
||||
{todos.map((todo, i) => (
|
||||
<div key={i} className='flex items-center space-x-2'>
|
||||
<Checkbox id={`todo-${i}`} />
|
||||
<label
|
||||
htmlFor={`todo-${i}`}
|
||||
className='text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
|
||||
>
|
||||
{todo.text}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
<Button className='w-full mt-4' variant='secondary'>
|
||||
Add Todo
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -473,7 +473,17 @@ export const useEmailState = () => {
|
||||
const newFlaggedStatus = !email.flags.flagged;
|
||||
logEmailOp('TOGGLE_STAR', `Setting starred status to ${newFlaggedStatus} for email ${emailId}`);
|
||||
|
||||
// TODO: Implement optimistic update
|
||||
// Implement optimistic update
|
||||
dispatch({
|
||||
type: 'UPDATE_EMAIL_FLAGS',
|
||||
payload: {
|
||||
emailId,
|
||||
flags: {
|
||||
flagged: newFlaggedStatus
|
||||
},
|
||||
accountId: email.accountId
|
||||
}
|
||||
});
|
||||
|
||||
// Make API call
|
||||
const response = await fetch(`/api/courrier/${emailId}/flag`, {
|
||||
|
||||
@ -52,6 +52,7 @@ export type EmailAction =
|
||||
| { type: 'UPDATE_UNREAD_COUNT', payload: { accountId: string, folder: string, count: number } }
|
||||
| { type: 'SET_UNREAD_COUNTS', payload: Record<string, Record<string, number>> }
|
||||
| { type: 'TOGGLE_SHOW_FOLDERS', payload: boolean }
|
||||
| { type: 'UPDATE_EMAIL_FLAGS', payload: { emailId: string, flags: { flagged: boolean }, accountId?: string } }
|
||||
| { type: 'MARK_EMAIL_AS_READ', payload: { emailId: string, isRead: boolean, accountId?: string } };
|
||||
|
||||
// Initial state
|
||||
@ -420,6 +421,30 @@ export function emailReducer(state: EmailState, action: EmailAction): EmailState
|
||||
showFolders: action.payload
|
||||
};
|
||||
|
||||
case 'UPDATE_EMAIL_FLAGS': {
|
||||
const { emailId, flags, accountId } = action.payload;
|
||||
|
||||
// Update emails list
|
||||
const updatedEmails = state.emails.map(email =>
|
||||
(email.id === emailId && (!accountId || email.accountId === accountId))
|
||||
? { ...email, flags: { ...email.flags, ...flags } }
|
||||
: email
|
||||
);
|
||||
|
||||
// Update selected email if it matches
|
||||
const updatedSelectedEmail = state.selectedEmail &&
|
||||
state.selectedEmail.id === emailId &&
|
||||
(!accountId || state.selectedEmail.accountId === accountId)
|
||||
? { ...state.selectedEmail, flags: { ...state.selectedEmail.flags, ...flags } }
|
||||
: state.selectedEmail;
|
||||
|
||||
return {
|
||||
...state,
|
||||
emails: updatedEmails,
|
||||
selectedEmail: updatedSelectedEmail
|
||||
};
|
||||
}
|
||||
|
||||
case 'MARK_EMAIL_AS_READ': {
|
||||
const { emailId, isRead, accountId } = action.payload;
|
||||
|
||||
|
||||
@ -12,6 +12,33 @@ const nextConfig = {
|
||||
}
|
||||
return config;
|
||||
},
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
experimental: {
|
||||
webpackBuildWorker: true,
|
||||
parallelServerBuildTraces: true,
|
||||
parallelServerCompiles: true,
|
||||
},
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: '/:path*',
|
||||
headers: [
|
||||
{
|
||||
key: 'Content-Security-Policy',
|
||||
value: "frame-ancestors 'self' https://espace.slm-lab.net https://connect.slm-lab.net"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
@ -1,61 +0,0 @@
|
||||
let userConfig;
|
||||
try {
|
||||
userConfig = await import("./v0-user-next.config");
|
||||
} catch (e) {
|
||||
// ignore error
|
||||
}
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
experimental: {
|
||||
webpackBuildWorker: true,
|
||||
parallelServerBuildTraces: true,
|
||||
parallelServerCompiles: true,
|
||||
},
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: '/:path*',
|
||||
headers: [
|
||||
{
|
||||
key: 'Content-Security-Policy',
|
||||
value: "frame-ancestors 'self' https://espace.slm-lab.net https://connect.slm-lab.net"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
mergeConfig(nextConfig, userConfig);
|
||||
|
||||
function mergeConfig(nextConfig, userConfig) {
|
||||
if (!userConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key in userConfig) {
|
||||
if (
|
||||
typeof nextConfig[key] === "object" &&
|
||||
!Array.isArray(nextConfig[key])
|
||||
) {
|
||||
nextConfig[key] = {
|
||||
...nextConfig[key],
|
||||
...userConfig[key],
|
||||
};
|
||||
} else {
|
||||
nextConfig[key] = userConfig[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default nextConfig;
|
||||
Loading…
Reference in New Issue
Block a user