added functionality to see all users as a user

This commit is contained in:
idittrich-valueon 2025-06-19 19:09:26 +02:00
parent b827c3e00b
commit 8ca6f28bcd
12 changed files with 256 additions and 53 deletions

View file

@ -11,7 +11,7 @@ import { AuthProvider } from './auth/authProvider';
import { ProtectedRoute } from './auth/ProtectedRoute';
import Home from './pages/Home';
import Dateien from './pages/Dateien/Dateien';
import TeamBereich from './pages/Mitglieder/TeamBereich';
import TeamBereich from './pages/TeamBereich/TeamBereich';
import Dashboard from './pages/Dashboard';
import Einstellungen from './pages/Einstellungen/Einstellungen';
// Import the global light theme CSS variables as default

View file

@ -7,11 +7,34 @@ const WorkflowStatusDisplay: React.FC<WorkflowStatusDisplayProps> = ({
currentWorkflowId,
workflowStatus,
workflowCompleted,
onStartNewWorkflow
onStartNewWorkflow,
handleRetry,
shouldShowRetryButton
}) => {
return (
<AnimatePresence>
{currentWorkflowId && !workflowCompleted && (
{currentWorkflowId && shouldShowRetryButton() && (
<motion.div
className={styles.workflow_status}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.3, ease: "easeOut" }}
>
<div className={styles.retry_container}>
<span className={styles.failed_message}>
Workflow failed.
</span>
<button
onClick={handleRetry}
className={styles.retry_button}
>
Nochmal versuchen
</button>
</div>
</motion.div>
)}
{currentWorkflowId && !workflowCompleted && !shouldShowRetryButton() && (
<motion.div
className={styles.workflow_status}
initial={{ opacity: 0, scale: 0.8 }}

View file

@ -328,20 +328,62 @@
.workflow_status {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
color: var(--color-secondary);
align-items: center;
padding: 10px;
margin: 5px 0;
}
.workflow_status p {
margin: 0;
color: var(--color-secondary);
font-size: 13px;
font-style: italic;
font-size: 14px;
color: var(--color-gray);
font-family: var(--font-family);
}
.retry_container {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background-color: var(--color-red-disabled);
border: 1px solid var(--color-red);
border-radius: 12px;
}
.failed_message {
font-size: 14px;
color: var(--color-red);
font-family: var(--font-family);
font-weight: 500;
}
.retry_button {
background-color: var(--color-primary);
color: var(--color-bg);
border: none;
border-radius: 8px;
padding: 8px 16px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
font-family: var(--font-family);
transition: background-color 0.2s ease, transform 0.2s ease;
white-space: nowrap;
}
.retry_button:hover {
background-color: var(--color-primary-hover);
transform: translateY(-1px);
}
.retry_button:disabled {
background-color: var(--color-gray-disabled);
cursor: not-allowed;
transform: none;
opacity: 0.6;
}
.completion_message {
padding: 10px 12px;
background-color: var(--color-secondary-disabled);

View file

@ -40,10 +40,12 @@ const DashboardChatArea: React.FC<DashboardChatAreaProps> = ({
handleFileAttach,
handleFileRemove,
handleFilesSelect,
handleRetry,
// Workflow state
isWorkflowRunning,
isStoppingWorkflow
isStoppingWorkflow,
shouldShowRetryButton
} = useChatLogic({
selectedPrompt,
onPromptUsed,
@ -73,6 +75,8 @@ const DashboardChatArea: React.FC<DashboardChatAreaProps> = ({
messagesLoading={messagesLoading}
onStartNewWorkflow={startNewWorkflow}
messagesEndRef={messagesEndRef}
handleRetry={handleRetry}
shouldShowRetryButton={shouldShowRetryButton}
/>
<ChatInput
inputValue={inputValue}

View file

@ -15,7 +15,9 @@ const MessageList: React.FC<MessageListProps> = ({
messagesError,
messagesLoading,
onStartNewWorkflow,
messagesEndRef
messagesEndRef,
handleRetry,
shouldShowRetryButton
}) => {
return (
<motion.div
@ -65,6 +67,8 @@ const MessageList: React.FC<MessageListProps> = ({
workflowStatus={workflowStatus}
workflowCompleted={workflowCompleted}
onStartNewWorkflow={onStartNewWorkflow}
handleRetry={handleRetry}
shouldShowRetryButton={shouldShowRetryButton}
/>
<div ref={messagesEndRef} />

View file

@ -229,6 +229,55 @@ export const useChatLogic = ({
const isStoppingWorkflow = currentWorkflowId ? stoppingWorkflows.has(currentWorkflowId) : false;
const handleRetry = async () => {
if (!currentWorkflowId || !messages.length) {
console.error('No workflow ID or messages available for retry');
return;
}
// Find the last user message to retry
const userMessages = messages.filter(msg => msg.role === 'user');
const lastUserMessage = userMessages[userMessages.length - 1];
if (!lastUserMessage) {
console.error('No user message found to retry');
return;
}
console.log('Retrying workflow with last user message:', lastUserMessage.content);
try {
// Extract file IDs if available from the message
const fileIds = lastUserMessage.fileIds || [];
// Start the workflow again with the same prompt and files
const result = await startWorkflow({
prompt: lastUserMessage.content,
listFileId: fileIds
}, currentWorkflowId);
if (result.success) {
console.log('Workflow retry started successfully');
// Reset workflow completion state to resume polling
setWorkflowCompleted(false);
} else {
console.error('Failed to retry workflow:', result.error);
}
} catch (error) {
console.error('Error retrying workflow:', error);
}
};
const shouldShowRetryButton = () => {
if (!workflowStatus) return false;
const statusLower = workflowStatus.status.toLowerCase();
return statusLower === 'error' ||
statusLower === 'failed' ||
statusLower === 'stopped' ||
statusLower === 'cancelled';
};
return {
// State
inputValue,
@ -257,9 +306,11 @@ export const useChatLogic = ({
handleFileAttach,
handleFileRemove,
handleFilesSelect,
handleRetry,
// Workflow state
isWorkflowRunning,
isStoppingWorkflow
isStoppingWorkflow,
shouldShowRetryButton
};
};

View file

@ -62,6 +62,8 @@ export interface MessageListProps {
messagesLoading: boolean;
onStartNewWorkflow: () => void;
messagesEndRef: React.RefObject<HTMLDivElement | null>;
handleRetry: () => Promise<void>;
shouldShowRetryButton: () => boolean;
}
export interface WorkflowStatusDisplayProps {
@ -69,4 +71,6 @@ export interface WorkflowStatusDisplayProps {
workflowStatus: WorkflowStatus | null;
workflowCompleted: boolean;
onStartNewWorkflow: () => void;
handleRetry: () => Promise<void>;
shouldShowRetryButton: () => boolean;
}

View file

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { FaArrowRight } from 'react-icons/fa';
import { AiOutlineDelete } from 'react-icons/ai';
import { motion } from 'framer-motion';
import { useWorkflowOperations, useWorkflowMessages, Workflow } from '../../../../hooks/useWorkflows';
import styles from './DashboardChatHistoryItem.module.css';
@ -50,16 +51,8 @@ function DashboardChatHistoryItem({ workflow, onDelete, onResume }: DashboardCha
const getStatusColor = (status: string) => {
switch (status.toLowerCase()) {
case 'completed':
case 'finished':
case 'done':
return 'var(--color-secondary)';
case 'running':
case 'processing':
return 'var(--color-gray)';
case 'error':
case 'failed':
return 'var(--color-red)';
case 'stopped':
case 'cancelled':
return 'var(--color-red)';
@ -70,13 +63,6 @@ function DashboardChatHistoryItem({ workflow, onDelete, onResume }: DashboardCha
const getStatusBackgroundColor = (status: string) => {
switch (status.toLowerCase()) {
case 'completed':
case 'finished':
case 'done':
return 'var(--color-secondary-disabled)';
case 'running':
case 'processing':
return 'var(--color-gray-disabled)';
case 'error':
case 'failed':
case 'stopped':
@ -87,6 +73,59 @@ function DashboardChatHistoryItem({ workflow, onDelete, onResume }: DashboardCha
}
};
const shouldShowStatus = (status: string) => {
const statusLower = status.toLowerCase();
return statusLower === 'error' ||
statusLower === 'failed' ||
statusLower === 'stopped' ||
statusLower === 'cancelled';
};
const isRunning = (status: string) => {
const statusLower = status.toLowerCase();
return statusLower === 'running' || statusLower === 'processing';
};
const renderStatusIndicator = () => {
if (isRunning(workflow.status)) {
return (
<motion.div
className={styles.loadingSpinner}
animate={{ rotate: 360 }}
transition={{
duration: 1,
repeat: Infinity,
ease: "linear"
}}
style={{
width: '16px',
height: '16px',
border: '2px solid var(--color-gray-disabled)',
borderTop: '2px solid var(--color-secondary)',
borderRadius: '50%',
display: 'inline-block'
}}
/>
);
}
if (shouldShowStatus(workflow.status)) {
return (
<span
className={styles.workflowStatus}
style={{
color: getStatusColor(workflow.status),
backgroundColor: getStatusBackgroundColor(workflow.status)
}}
>
{workflow.status.toUpperCase()}
</span>
);
}
return null;
};
const truncateMessage = (message: string, maxLength: number = 150) => {
if (message.length <= maxLength) return message;
return message.substring(0, maxLength) + '...';
@ -101,15 +140,7 @@ function DashboardChatHistoryItem({ workflow, onDelete, onResume }: DashboardCha
Workflow {workflow.id.substring(0, 8)}...
</h3>
<div className={styles.workflowMeta}>
<span
className={styles.workflowStatus}
style={{
color: getStatusColor(workflow.status),
backgroundColor: getStatusBackgroundColor(workflow.status)
}}
>
{workflow.status.toUpperCase()}
</span>
{renderStatusIndicator()}
{workflow.currentRound && (
<span className={styles.workflowRound}>
Round {workflow.currentRound}

View file

@ -5,7 +5,6 @@
flex-direction: column;
align-self: stretch;
border-radius: 30px;
border: 1px solid var(--color-gray-disabled);
background: var(--color-bg);
position: relative;
box-shadow: 0px 2px 6px 0px rgba(194, 194, 194, 0.10);

View file

@ -1,15 +0,0 @@
import styles from './TeamBereich.module.css'
import MitgliederItem from '../../components/Mitglieder/MitgliederItem';
import { IoPersonAddSharp } from "react-icons/io5";
import { useOrgUsers } from '../../hooks/useUsers';
function TeamBereich () {
return (
<h1>Team-Bereich</h1>
);
}
export default TeamBereich;

View file

@ -66,7 +66,7 @@
.membersList {
list-style: none;
padding: 0;
margin: 0;
margin-top: 30px;
width: 100%;
overflow-y: auto; /* Enable vertical scrolling */
/* Space for the header line */

View file

@ -0,0 +1,60 @@
import styles from './TeamBereich.module.css'
import MitgliederItem from '../../components/Mitglieder/MitgliederItem';
import { IoPersonAddSharp } from "react-icons/io5";
import { useOrgUsers } from '../../hooks/useUsers';
function TeamBereich () {
const { users, loading, error, refetch } = useOrgUsers();
if (loading) {
return (
<div className={styles.mitgliederContainer}>
<div className={styles.header}>
<h1>Team-Bereich</h1>
</div>
<p>Lade Mitglieder...</p>
</div>
);
}
if (error) {
return (
<div className={styles.mitgliederContainer}>
<div className={styles.header}>
<h1>Team-Bereich</h1>
</div>
<p>Fehler beim Laden der Mitglieder: {error}</p>
</div>
);
}
return (
<div className={styles.mitgliederContainer}>
<div className={styles.header}>
<h1>Team-Bereich</h1>
<button className={styles.mitglieder_hinzufügen_button}>
<IoPersonAddSharp className={styles.add_icon} />
Mitglied hinzufügen
</button>
</div>
<div className={styles.horizontalLineLight}></div>
<ul className={styles.membersList}>
{users.map((user) => (
<MitgliederItem
key={user.id}
user={user}
refetchUsers={refetch}
totalUsers={users.length}
/>
))}
</ul>
{users.length === 0 && (
<p>Keine Mitglieder gefunden.</p>
)}
</div>
);
}
export default TeamBereich;