admin pages streamlined
This commit is contained in:
parent
932bc3e11b
commit
ff1caba925
14 changed files with 82 additions and 354 deletions
32
src/App.tsx
32
src/App.tsx
|
|
@ -43,15 +43,9 @@ import { GDPRPage } from './pages/GDPR';
|
|||
import { FeatureViewPage } from './pages/FeatureView';
|
||||
import { AccessManagementHub, AdminMandatesPage, AdminUsersPage, AdminUserMandatesPage, AdminFeatureAccessPage, AdminInvitationsPage, AdminMandateRolesPage, AdminFeatureRolesPage, AdminFeatureInstanceUsersPage, AdminMandateRolePermissionsPage, AdminUserAccessOverviewPage } from './pages/admin';
|
||||
|
||||
// Workflow Pages (global)
|
||||
import { PlaygroundPage, WorkflowsPage, AutomationsPage, AutomationTemplatesPage } from './pages/workflows';
|
||||
|
||||
// Basedata Pages (global)
|
||||
import { PromptsPage, FilesPage, ConnectionsPage } from './pages/basedata';
|
||||
|
||||
// Migrate Pages (temporary - to be migrated to feature instances)
|
||||
import { PekPage, SpeechPage } from './pages/migrate';
|
||||
|
||||
function App() {
|
||||
// Load saved theme preference and set app name on app mount
|
||||
useEffect(() => {
|
||||
|
|
@ -107,16 +101,6 @@ function App() {
|
|||
<Route path="settings" element={<SettingsPage />} />
|
||||
<Route path="gdpr" element={<GDPRPage />} />
|
||||
|
||||
{/* ============================================== */}
|
||||
{/* WORKFLOWS ROUTES (global) */}
|
||||
{/* ============================================== */}
|
||||
<Route path="workflows">
|
||||
<Route path="playground" element={<PlaygroundPage />} />
|
||||
<Route path="list" element={<WorkflowsPage />} />
|
||||
<Route path="automations" element={<AutomationsPage />} />
|
||||
<Route path="automation-templates" element={<AutomationTemplatesPage />} />
|
||||
</Route>
|
||||
|
||||
{/* ============================================== */}
|
||||
{/* BASISDATEN ROUTES (global) */}
|
||||
{/* ============================================== */}
|
||||
|
|
@ -126,13 +110,6 @@ function App() {
|
|||
<Route path="connections" element={<ConnectionsPage />} />
|
||||
</Route>
|
||||
|
||||
{/* ============================================== */}
|
||||
{/* MIGRATE TO FEATURES (temporary) */}
|
||||
{/* ============================================== */}
|
||||
<Route path="chatbot" element={<Navigate to="/" replace />} />
|
||||
<Route path="pek" element={<PekPage />} />
|
||||
<Route path="speech" element={<SpeechPage />} />
|
||||
|
||||
{/* ============================================== */}
|
||||
{/* FEATURE-INSTANZ ROUTES */}
|
||||
{/* /mandates/:mandateId/:featureCode/:instanceId */}
|
||||
|
|
@ -159,6 +136,15 @@ function App() {
|
|||
<Route path="projects" element={<FeatureViewPage view="projects" />} />
|
||||
<Route path="parcels" element={<FeatureViewPage view="parcels" />} />
|
||||
|
||||
{/* Chat Playground Feature Views */}
|
||||
<Route path="playground" element={<FeatureViewPage view="playground" />} />
|
||||
<Route path="workflows" element={<FeatureViewPage view="workflows" />} />
|
||||
|
||||
{/* Automation Feature Views */}
|
||||
<Route path="definitions" element={<FeatureViewPage view="definitions" />} />
|
||||
<Route path="templates" element={<FeatureViewPage view="templates" />} />
|
||||
<Route path="logs" element={<FeatureViewPage view="logs" />} />
|
||||
|
||||
{/* Catch-all für unbekannte Sub-Pfade */}
|
||||
<Route path="*" element={<FeatureViewPage view="not-found" />} />
|
||||
</Route>
|
||||
|
|
|
|||
|
|
@ -231,17 +231,18 @@ export async function fetchWorkflowLogs(
|
|||
|
||||
/**
|
||||
* Fetch unified chat data (messages, logs, stats, documents)
|
||||
* Endpoint: GET /api/chat/playground/{workflowId}/chatData
|
||||
* Endpoint: GET /api/chatplayground/{instanceId}/{workflowId}/chatData
|
||||
* Query params: afterTimestamp (optional) - fetch only data created after this time
|
||||
*/
|
||||
export async function fetchChatData(
|
||||
request: ApiRequestFunction,
|
||||
instanceId: string,
|
||||
workflowId: string,
|
||||
afterTimestamp?: number
|
||||
): Promise<ChatDataResponse> {
|
||||
const params = afterTimestamp ? { afterTimestamp: afterTimestamp.toString() } : undefined;
|
||||
const requestConfig = {
|
||||
url: `/api/chat/playground/${workflowId}/chatData`,
|
||||
url: `/api/chatplayground/${instanceId}/${workflowId}/chatData`,
|
||||
method: 'get' as const,
|
||||
params
|
||||
};
|
||||
|
|
@ -314,11 +315,12 @@ export async function fetchChatData(
|
|||
|
||||
/**
|
||||
* Start a new workflow or continue an existing one
|
||||
* Endpoint: POST /api/chat/playground/start
|
||||
* Query params: workflowId (optional), workflowMode (default: "Actionplan")
|
||||
* Endpoint: POST /api/chatplayground/{instanceId}/start
|
||||
* Query params: workflowId (optional), workflowMode (default: "Dynamic")
|
||||
*/
|
||||
export async function startWorkflowApi(
|
||||
request: ApiRequestFunction,
|
||||
instanceId: string,
|
||||
workflowData: StartWorkflowRequest,
|
||||
options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' }
|
||||
): Promise<StartWorkflowResponse> {
|
||||
|
|
@ -345,7 +347,7 @@ export async function startWorkflowApi(
|
|||
};
|
||||
|
||||
const requestConfig = {
|
||||
url: '/api/chat/playground/start',
|
||||
url: `/api/chatplayground/${instanceId}/start`,
|
||||
method: 'post' as const,
|
||||
data: requestBody,
|
||||
params: params // Always include workflowMode
|
||||
|
|
@ -368,14 +370,15 @@ export async function startWorkflowApi(
|
|||
|
||||
/**
|
||||
* Stop a running workflow
|
||||
* Endpoint: POST /api/chat/playground/{workflowId}/stop
|
||||
* Endpoint: POST /api/chatplayground/{instanceId}/{workflowId}/stop
|
||||
*/
|
||||
export async function stopWorkflowApi(
|
||||
request: ApiRequestFunction,
|
||||
instanceId: string,
|
||||
workflowId: string
|
||||
): Promise<void> {
|
||||
await request({
|
||||
url: `/api/chat/playground/${workflowId}/stop`,
|
||||
url: `/api/chatplayground/${instanceId}/${workflowId}/stop`,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export interface WorkflowFile {
|
|||
source?: 'user_uploaded' | 'ai_created';
|
||||
}
|
||||
|
||||
export function useDashboardInputForm() {
|
||||
export function useDashboardInputForm(instanceId: string) {
|
||||
const [inputValue, setInputValue] = useState<string>('');
|
||||
const [pendingFiles, setPendingFiles] = useState<WorkflowFile[]>([]);
|
||||
const [isFileAttachmentPopupOpen, setIsFileAttachmentPopupOpen] = useState(false);
|
||||
|
|
@ -54,7 +54,7 @@ export function useDashboardInputForm() {
|
|||
resetWorkflow,
|
||||
selectWorkflow,
|
||||
setWorkflowStatusOptimistic
|
||||
} = useWorkflowLifecycle();
|
||||
} = useWorkflowLifecycle(instanceId);
|
||||
|
||||
// Dashboard log tree hook
|
||||
const {
|
||||
|
|
@ -824,7 +824,7 @@ export function useDashboardInputForm() {
|
|||
};
|
||||
}
|
||||
|
||||
export function createDashboardHook() {
|
||||
return () => useDashboardInputForm();
|
||||
export function createDashboardHook(instanceId: string) {
|
||||
return () => useDashboardInputForm(instanceId);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ interface UnifiedChatDataItem {
|
|||
createdAt: number;
|
||||
}
|
||||
|
||||
export function useWorkflowLifecycle() {
|
||||
export function useWorkflowLifecycle(instanceId: string) {
|
||||
const [workflowId, setWorkflowId] = useState<string | null>(null);
|
||||
const [workflowStatus, setWorkflowStatus] = useState<string>('idle');
|
||||
const [currentRound, setCurrentRound] = useState<number | undefined>(undefined);
|
||||
|
|
@ -341,7 +341,7 @@ export function useWorkflowLifecycle() {
|
|||
}
|
||||
|
||||
// Fetch unified chat data
|
||||
const chatData = await fetchChatData(request, id, afterTimestamp);
|
||||
const chatData = await fetchChatData(request, instanceId, id, afterTimestamp);
|
||||
|
||||
console.log('📊 Processed chat data:', {
|
||||
messagesCount: chatData.messages?.length || 0,
|
||||
|
|
@ -419,7 +419,7 @@ export function useWorkflowLifecycle() {
|
|||
// Reset lastRenderedTimestamp to fetch all historical data
|
||||
lastRenderedTimestampRef.current = null;
|
||||
try {
|
||||
const chatData = await fetchChatData(request, id, undefined);
|
||||
const chatData = await fetchChatData(request, instanceId, id, undefined);
|
||||
console.log('📥 loadWorkflowData: Fetched unified chat data:', {
|
||||
messagesCount: chatData.messages?.length || 0,
|
||||
logsCount: chatData.logs?.length || 0
|
||||
|
|
@ -514,7 +514,7 @@ export function useWorkflowLifecycle() {
|
|||
options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' }
|
||||
) => {
|
||||
try {
|
||||
const result = await startWorkflow(workflowData, options);
|
||||
const result = await startWorkflow(instanceId, workflowData, options);
|
||||
|
||||
if (result.success && result.data) {
|
||||
const workflow = result.data as Workflow;
|
||||
|
|
@ -529,7 +529,7 @@ export function useWorkflowLifecycle() {
|
|||
} catch (error: any) {
|
||||
return { success: false, error: error.message || 'Failed to start workflow' };
|
||||
}
|
||||
}, [startWorkflow, updateWorkflowStatus]);
|
||||
}, [instanceId, startWorkflow, updateWorkflowStatus]);
|
||||
|
||||
const handleStopWorkflow = useCallback(async () => {
|
||||
if (!workflowId) {
|
||||
|
|
@ -537,7 +537,7 @@ export function useWorkflowLifecycle() {
|
|||
}
|
||||
|
||||
try {
|
||||
const result = await stopWorkflow(workflowId);
|
||||
const result = await stopWorkflow(instanceId, workflowId);
|
||||
|
||||
if (result.success) {
|
||||
updateWorkflowStatus('stopped');
|
||||
|
|
@ -548,7 +548,7 @@ export function useWorkflowLifecycle() {
|
|||
} catch (error: any) {
|
||||
return { success: false, error: error.message || 'Failed to stop workflow' };
|
||||
}
|
||||
}, [workflowId, stopWorkflow, updateWorkflowStatus]);
|
||||
}, [instanceId, workflowId, stopWorkflow, updateWorkflowStatus]);
|
||||
|
||||
const resetWorkflow = useCallback(() => {
|
||||
setWorkflowId(null);
|
||||
|
|
@ -597,7 +597,7 @@ export function useWorkflowLifecycle() {
|
|||
// Always fetch unified chat data to get all messages and logs (regardless of status)
|
||||
// This ensures completed workflows also show their logs
|
||||
try {
|
||||
const chatData = await fetchChatData(request, workflowIdToSelect, undefined);
|
||||
const chatData = await fetchChatData(request, instanceId, workflowIdToSelect, undefined);
|
||||
console.log('📥 selectWorkflow: Fetched unified chat data:', {
|
||||
messagesCount: chatData.messages?.length || 0,
|
||||
logsCount: chatData.logs?.length || 0,
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ export function useUserMandates() {
|
|||
}, []);
|
||||
|
||||
/**
|
||||
* Fetch all available roles (global and mandate-specific)
|
||||
* Fetch all available roles (global and mandate-specific, excluding feature-instance roles)
|
||||
*/
|
||||
const fetchRoles = useCallback(async (mandateId?: string): Promise<Role[]> => {
|
||||
try {
|
||||
|
|
@ -238,13 +238,15 @@ export function useUserMandates() {
|
|||
roles = response.data;
|
||||
}
|
||||
|
||||
// Filter to global roles and roles for this mandate
|
||||
// Filter to global roles and mandate-specific roles only
|
||||
// Exclude feature-instance roles (they have featureInstanceId set)
|
||||
if (mandateId) {
|
||||
return roles.filter(r =>
|
||||
!r.mandateId || r.mandateId === mandateId
|
||||
!r.featureInstanceId && (!r.mandateId || r.mandateId === mandateId)
|
||||
);
|
||||
}
|
||||
return roles;
|
||||
// Without mandateId, return only global roles (no mandateId and no featureInstanceId)
|
||||
return roles.filter(r => !r.mandateId && !r.featureInstanceId);
|
||||
} catch (err: any) {
|
||||
console.error('Error fetching roles:', err);
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ export function useWorkflowOperations() {
|
|||
};
|
||||
|
||||
const startWorkflow = async (
|
||||
instanceId: string,
|
||||
workflowData: StartWorkflowRequest,
|
||||
options?: { workflowId?: string; workflowMode?: 'Dynamic' | 'Automation' }
|
||||
) => {
|
||||
|
|
@ -439,7 +440,7 @@ export function useWorkflowOperations() {
|
|||
setStartingWorkflow(true);
|
||||
|
||||
try {
|
||||
const response = await startWorkflowApi(request, workflowData, options);
|
||||
const response = await startWorkflowApi(request, instanceId, workflowData, options);
|
||||
return { success: true, data: response };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.message || 'Failed to start workflow';
|
||||
|
|
@ -450,12 +451,12 @@ export function useWorkflowOperations() {
|
|||
}
|
||||
};
|
||||
|
||||
const stopWorkflow = async (workflowId: string) => {
|
||||
const stopWorkflow = async (instanceId: string, workflowId: string) => {
|
||||
setStopError(null);
|
||||
setStoppingWorkflows(prev => new Set(prev).add(workflowId));
|
||||
|
||||
try {
|
||||
await stopWorkflowApi(request, workflowId);
|
||||
await stopWorkflowApi(request, instanceId, workflowId);
|
||||
return { success: true };
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.message || 'Failed to stop workflow';
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ import { ChatbotConversationsView } from './views/chatbot/ChatbotConversationsVi
|
|||
// RealEstate Views
|
||||
import { RealEstatePekView, RealEstateProjectsView, RealEstateParcelsView, RealEstateInstanceRolesPlaceholder } from './views/realestate';
|
||||
|
||||
// Chat Playground Views (reusing existing workflow pages)
|
||||
import { PlaygroundPage, WorkflowsPage } from './workflows';
|
||||
|
||||
// Automation Views (reusing existing workflow pages)
|
||||
import { AutomationsPage, AutomationTemplatesPage } from './workflows';
|
||||
|
||||
import styles from './FeatureView.module.css';
|
||||
|
||||
// =============================================================================
|
||||
|
|
@ -103,6 +109,15 @@ const VIEW_COMPONENTS: Record<string, Record<string, ViewComponent>> = {
|
|||
parcels: RealEstateParcelsView,
|
||||
'instance-roles': RealEstateInstanceRolesPlaceholder,
|
||||
},
|
||||
chatplayground: {
|
||||
playground: PlaygroundPage,
|
||||
workflows: WorkflowsPage,
|
||||
},
|
||||
automation: {
|
||||
definitions: AutomationsPage,
|
||||
templates: AutomationTemplatesPage,
|
||||
logs: () => <PlaceholderView title="Execution Logs" description="Automatisierungs-Ausführungsprotokolle" />,
|
||||
},
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
|
|
|
|||
|
|
@ -1,223 +0,0 @@
|
|||
/* MigratePages.module.css - Styles for migrate-to-feature pages */
|
||||
|
||||
.page {
|
||||
padding: 2rem;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
height: calc(100vh - 4rem);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary, #1a1a2e);
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--color-text-secondary, #6b7280);
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.migrateTag {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: var(--color-warning-bg, #fef3c7);
|
||||
color: var(--color-warning, #d97706);
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
border-radius: 4px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Placeholder for migrate pages */
|
||||
.placeholder {
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
background: var(--color-surface, #ffffff);
|
||||
border: 2px dashed var(--color-border, #e5e7eb);
|
||||
border-radius: 12px;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.placeholderIcon {
|
||||
font-size: 4rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.placeholder h2 {
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--color-text-primary, #1a1a2e);
|
||||
}
|
||||
|
||||
.placeholder p {
|
||||
color: var(--color-text-secondary, #6b7280);
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-tertiary, #9ca3af);
|
||||
margin-top: 1rem !important;
|
||||
}
|
||||
|
||||
/* Chat container for ChatbotPage */
|
||||
.chatContainer {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--color-surface, #ffffff);
|
||||
border: 1px solid var(--color-border, #e5e7eb);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.messagesArea {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.emptyChat {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-text-secondary, #6b7280);
|
||||
}
|
||||
|
||||
.message {
|
||||
max-width: 70%;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
align-self: flex-end;
|
||||
background: var(--color-primary, #4f46e5);
|
||||
color: white;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
align-self: flex-start;
|
||||
background: var(--color-surface-secondary, #f3f4f6);
|
||||
color: var(--color-text-primary, #1a1a2e);
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
|
||||
.message.system {
|
||||
align-self: center;
|
||||
background: var(--color-warning-bg, #fef3c7);
|
||||
color: var(--color-warning, #d97706);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.messageContent {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.messageTime {
|
||||
font-size: 0.7rem;
|
||||
opacity: 0.7;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
/* Typing indicator */
|
||||
.typing {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.typing span {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--color-text-secondary, #6b7280);
|
||||
border-radius: 50%;
|
||||
animation: typing 1s infinite;
|
||||
}
|
||||
|
||||
.typing span:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.typing span:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
0%, 100% {
|
||||
opacity: 0.3;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Input area */
|
||||
.inputArea {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
border-top: 1px solid var(--color-border, #e5e7eb);
|
||||
background: var(--color-surface-secondary, #f9fafb);
|
||||
}
|
||||
|
||||
.chatInput {
|
||||
flex: 1;
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid var(--color-border, #e5e7eb);
|
||||
border-radius: 24px;
|
||||
font-size: 0.875rem;
|
||||
background: var(--color-surface, #ffffff);
|
||||
}
|
||||
|
||||
.chatInput:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary, #4f46e5);
|
||||
box-shadow: 0 0 0 3px var(--color-primary-light, rgba(79, 70, 229, 0.1));
|
||||
}
|
||||
|
||||
.sendButton {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: var(--color-primary, #4f46e5);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 24px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.sendButton:hover:not(:disabled) {
|
||||
background: var(--color-primary-dark, #4338ca);
|
||||
}
|
||||
|
||||
.sendButton:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
* PekPage
|
||||
*
|
||||
* PEK (Projekt-Entwicklungs-Koordination) page - temporary global page.
|
||||
* TODO: Migrate to feature instance.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import styles from './MigratePages.module.css';
|
||||
|
||||
export const PekPage: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<header className={styles.header}>
|
||||
<h1>PEK</h1>
|
||||
<p className={styles.subtitle}>
|
||||
<span className={styles.migrateTag}>MIGRATE TO FEATURE</span>
|
||||
Projekt-Entwicklungs-Koordination
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<main className={styles.content}>
|
||||
<div className={styles.placeholder}>
|
||||
<div className={styles.placeholderIcon}>📊</div>
|
||||
<h2>PEK-Modul</h2>
|
||||
<p>
|
||||
Dieses Modul wird zu einer Feature-Instanz migriert.
|
||||
</p>
|
||||
<p className={styles.hint}>
|
||||
Nach der Migration wird PEK als Feature pro Mandant verfügbar sein,
|
||||
mit instanz-spezifischen Daten und Berechtigungen.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PekPage;
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
* SpeechPage
|
||||
*
|
||||
* Speech recognition and transcription page - temporary global page.
|
||||
* TODO: Migrate to feature instance.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import styles from './MigratePages.module.css';
|
||||
|
||||
export const SpeechPage: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<header className={styles.header}>
|
||||
<h1>Speech</h1>
|
||||
<p className={styles.subtitle}>
|
||||
<span className={styles.migrateTag}>MIGRATE TO FEATURE</span>
|
||||
Spracherkennung und Transkription
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<main className={styles.content}>
|
||||
<div className={styles.placeholder}>
|
||||
<div className={styles.placeholderIcon}>🎤</div>
|
||||
<h2>Speech-Modul</h2>
|
||||
<p>
|
||||
Dieses Modul wird zu einer Feature-Instanz migriert.
|
||||
</p>
|
||||
<p className={styles.hint}>
|
||||
Nach der Migration wird Speech als Feature pro Mandant verfügbar sein,
|
||||
mit instanz-spezifischen Transkriptionen und Einstellungen.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SpeechPage;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { PekPage } from './PekPage';
|
||||
export { SpeechPage } from './SpeechPage';
|
||||
|
|
@ -426,7 +426,7 @@ export const AutomationsPage: React.FC = () => {
|
|||
|
||||
try {
|
||||
await request({
|
||||
url: `/api/chat/playground/${executionModal.workflowId}/stop`,
|
||||
url: `/api/workflows/${executionModal.workflowId}/stop`,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { useSearchParams } from 'react-router-dom';
|
|||
import { useDashboardInputForm } from '../../hooks/usePlayground';
|
||||
import { useResizablePanels } from '../../hooks/useResizablePanels';
|
||||
import { usePrompts } from '../../hooks/usePrompts';
|
||||
import { useCurrentInstance } from '../../hooks/useCurrentInstance';
|
||||
import { FaComment, FaTasks, FaPaperPlane, FaStop, FaFile, FaPlus, FaMicrophone, FaSquare, FaFileAlt } from 'react-icons/fa';
|
||||
import { useToast } from '../../contexts/ToastContext';
|
||||
import { useVoiceLanguage, VoiceLanguageSelect, Messages } from '../../components/UiComponents';
|
||||
|
|
@ -23,8 +24,12 @@ export const PlaygroundPage: React.FC = () => {
|
|||
const [searchParams] = useSearchParams();
|
||||
const urlWorkflowId = searchParams.get('workflowId');
|
||||
|
||||
// Get feature instance context
|
||||
const { instance } = useCurrentInstance();
|
||||
const instanceId = instance?.id || '';
|
||||
|
||||
// Main hook for input form and data
|
||||
const hookData = useDashboardInputForm();
|
||||
const hookData = useDashboardInputForm(instanceId);
|
||||
const {
|
||||
inputValue,
|
||||
onInputChange,
|
||||
|
|
|
|||
|
|
@ -240,6 +240,25 @@ export const FEATURE_REGISTRY: Record<string, FeatureConfig> = {
|
|||
{ code: 'instance-roles', label: { de: 'Rollen & Rechte', en: 'Roles & Permissions' }, path: 'instance-roles', adminOnly: true },
|
||||
]
|
||||
},
|
||||
chatplayground: {
|
||||
code: 'chatplayground',
|
||||
label: { de: 'Chat Playground', en: 'Chat Playground' },
|
||||
icon: 'message',
|
||||
views: [
|
||||
{ code: 'playground', label: { de: 'Playground', en: 'Playground' }, path: 'playground' },
|
||||
{ code: 'workflows', label: { de: 'Workflows', en: 'Workflows' }, path: 'workflows' },
|
||||
]
|
||||
},
|
||||
automation: {
|
||||
code: 'automation',
|
||||
label: { de: 'Automatisierung', en: 'Automation' },
|
||||
icon: 'settings',
|
||||
views: [
|
||||
{ code: 'definitions', label: { de: 'Definitionen', en: 'Definitions' }, path: 'definitions' },
|
||||
{ code: 'templates', label: { de: 'Vorlagen', en: 'Templates' }, path: 'templates' },
|
||||
{ code: 'logs', label: { de: 'Protokolle', en: 'Logs' }, path: 'logs' },
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
|
|
|
|||
Loading…
Reference in a new issue