feat: Add OIDC authentication with Authentik integration
- Add OIDC login flow with Authentik provider - Implement session-based auth with Redis store - Add avatar display from OIDC claims - Fix input field performance with react-textarea-autosize - Stabilize callbacks to prevent unnecessary re-renders - Fix history loading to skip empty session files - Add 2-row default height for input textarea 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||
import { MessageList } from './MessageList';
|
||||
import { ChatInput } from './ChatInput';
|
||||
import { StatusBar } from './StatusBar';
|
||||
@@ -94,25 +94,36 @@ const ErrorBanner = memo(function ErrorBanner({ error, onClear }) {
|
||||
|
||||
// Use a separate hook that memoizes everything to prevent unnecessary re-renders
|
||||
function useMemoizedSession(sessionId) {
|
||||
const manager = useSessionManager();
|
||||
const session = manager.sessions[sessionId];
|
||||
const messages = manager.sessionMessages[sessionId] || [];
|
||||
const {
|
||||
sessions,
|
||||
sessionMessages,
|
||||
startClaudeSession,
|
||||
stopClaudeSession,
|
||||
sendMessage,
|
||||
stopGeneration,
|
||||
clearMessages,
|
||||
changePermissionMode,
|
||||
respondToPermission,
|
||||
} = useSessionManager();
|
||||
|
||||
const session = sessions[sessionId];
|
||||
const messages = sessionMessages[sessionId] || [];
|
||||
|
||||
// Memoize the combined session object
|
||||
const sessionWithMessages = useMemo(() => {
|
||||
return session ? { ...session, messages } : null;
|
||||
}, [session, messages]);
|
||||
|
||||
// Memoize all action functions
|
||||
// Memoize all action functions - use individual functions as deps, not the whole manager
|
||||
const actions = useMemo(() => ({
|
||||
start: () => manager.startClaudeSession(sessionId),
|
||||
stop: () => manager.stopClaudeSession(sessionId),
|
||||
send: (msg, attachments) => manager.sendMessage(sessionId, msg, attachments),
|
||||
stopGeneration: () => manager.stopGeneration(sessionId),
|
||||
clearMessages: () => manager.clearMessages(sessionId),
|
||||
changePermissionMode: (mode) => manager.changePermissionMode(sessionId, mode),
|
||||
respondToPermission: (reqId, allow) => manager.respondToPermission(sessionId, reqId, allow),
|
||||
}), [sessionId, manager]);
|
||||
start: () => startClaudeSession(sessionId),
|
||||
stop: () => stopClaudeSession(sessionId),
|
||||
send: (msg, attachments) => sendMessage(sessionId, msg, attachments),
|
||||
stopGeneration: () => stopGeneration(sessionId),
|
||||
clearMessages: () => clearMessages(sessionId),
|
||||
changePermissionMode: (mode) => changePermissionMode(sessionId, mode),
|
||||
respondToPermission: (reqId, allow) => respondToPermission(sessionId, reqId, allow),
|
||||
}), [sessionId, startClaudeSession, stopClaudeSession, sendMessage, stopGeneration, clearMessages, changePermissionMode, respondToPermission]);
|
||||
|
||||
return { session: sessionWithMessages, ...actions };
|
||||
}
|
||||
@@ -134,11 +145,22 @@ export const ChatPanel = memo(function ChatPanel({ sessionId }) {
|
||||
// For now, errors auto-clear on next action
|
||||
}, []);
|
||||
|
||||
// Use refs for callbacks to keep them stable across re-renders
|
||||
const sendRef = useRef(send);
|
||||
sendRef.current = send;
|
||||
const stopGenerationRef = useRef(stopGeneration);
|
||||
stopGenerationRef.current = stopGeneration;
|
||||
|
||||
// These callbacks never change identity, preventing ChatInput re-renders
|
||||
const handleSendMessage = useCallback((message, attachments = []) => {
|
||||
if (message.trim() || attachments.length > 0) {
|
||||
send(message, attachments);
|
||||
sendRef.current(message, attachments);
|
||||
}
|
||||
}, [send]);
|
||||
}, []);
|
||||
|
||||
const handleStopGeneration = useCallback(() => {
|
||||
stopGenerationRef.current();
|
||||
}, []);
|
||||
|
||||
if (!session) {
|
||||
return (
|
||||
@@ -178,7 +200,7 @@ export const ChatPanel = memo(function ChatPanel({ sessionId }) {
|
||||
{/* Input - memoized props to prevent re-renders during streaming */}
|
||||
<MemoizedChatInput
|
||||
onSend={handleSendMessage}
|
||||
onStop={stopGeneration}
|
||||
onStop={handleStopGeneration}
|
||||
disabled={!session.active}
|
||||
isProcessing={session.isProcessing}
|
||||
sessionId={session.claudeSessionId}
|
||||
|
||||
Reference in New Issue
Block a user