added functionality to see all users as a user
This commit is contained in:
parent
b827c3e00b
commit
8ca6f28bcd
12 changed files with 256 additions and 53 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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} />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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 */
|
||||
60
src/pages/TeamBereich/TeamBereich.tsx
Normal file
60
src/pages/TeamBereich/TeamBereich.tsx
Normal 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;
|
||||
|
||||
Loading…
Reference in a new issue