This commit is contained in:
2025-08-31 00:33:57 -04:00
parent 9ec78ab51c
commit 279bbd3dcc
14 changed files with 598 additions and 76 deletions

View File

@ -1,26 +1,60 @@
import React, { useState } from 'react';
import { MantineProvider, AppShell, Title, Group, Badge, Text } from '@mantine/core';
import { Notifications } from '@mantine/notifications';
import { IconFunction } from '@tabler/icons-react';
import { Box, Title, Tabs, Stack, ActionIcon, Group, Select } from '@mantine/core';
import {
IconFunction,
IconPlayerPlay,
IconStar,
IconStarFilled
} from '@tabler/icons-react';
import { FunctionList } from './components/FunctionList';
import { FunctionForm } from './components/FunctionForm';
import { ExecutionModal } from './components/ExecutionModal';
import { FunctionDefinition } from './types';
// Default Mantine theme
const theme: any = {
colorScheme: 'light',
};
const App: React.FC = () => {
// Determine current route based on pathname
const getCurrentRoute = () => {
const path = window.location.pathname;
if (path.includes('/functions')) return 'functions';
if (path.includes('/executions')) return 'executions';
return 'functions';
};
const [currentRoute, setCurrentRoute] = useState(getCurrentRoute());
const [isFavorited, setIsFavorited] = useState(false);
const [selectedColor, setSelectedColor] = useState('');
const [functionFormOpened, setFunctionFormOpened] = useState(false);
const [executionModalOpened, setExecutionModalOpened] = useState(false);
const [editingFunction, setEditingFunction] = useState<FunctionDefinition | null>(null);
const [executingFunction, setExecutingFunction] = useState<FunctionDefinition | null>(null);
const [refreshKey, setRefreshKey] = useState(0);
// Listen for URL changes (for when the shell navigates)
React.useEffect(() => {
const handlePopState = () => {
setCurrentRoute(getCurrentRoute());
};
window.addEventListener('popstate', handlePopState);
return () => window.removeEventListener('popstate', handlePopState);
}, []);
const handleTabChange = (value: string | null) => {
if (value) {
// Use history.pushState to update URL and notify shell router
const basePath = '/app/faas';
const newPath = `${basePath}/${value}`;
// Update the URL and internal state
window.history.pushState(null, '', newPath);
setCurrentRoute(value);
// Dispatch a custom event so shell can respond if needed
window.dispatchEvent(new PopStateEvent('popstate', { state: null }));
}
};
const handleCreateFunction = () => {
console.log('handleCreateFunction called');
setEditingFunction(null);
setFunctionFormOpened(true);
};
@ -49,49 +83,121 @@ const App: React.FC = () => {
setExecutingFunction(null);
};
return (
<MantineProvider theme={theme}>
<Notifications />
<AppShell
header={{ height: 60 }}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md" justify="space-between">
<Group>
<IconFunction size={24} />
<Title order={3}>Function as a Service</Title>
<Badge variant="light" color="blue">FaaS</Badge>
</Group>
<Text size="sm" c="dimmed">
Serverless Functions Platform
</Text>
</Group>
</AppShell.Header>
const toggleFavorite = () => {
setIsFavorited(prev => !prev);
};
<AppShell.Main>
const colorOptions = [
{ value: 'red', label: 'Red' },
{ value: 'blue', label: 'Blue' },
{ value: 'green', label: 'Green' },
{ value: 'purple', label: 'Purple' },
{ value: 'orange', label: 'Orange' },
{ value: 'pink', label: 'Pink' },
{ value: 'teal', label: 'Teal' },
];
const renderContent = () => {
switch (currentRoute) {
case 'functions':
return (
<FunctionList
key={refreshKey}
onCreateFunction={handleCreateFunction}
onEditFunction={handleEditFunction}
onExecuteFunction={handleExecuteFunction}
/>
<FunctionForm
opened={functionFormOpened}
onClose={handleFormClose}
onSuccess={handleFormSuccess}
editFunction={editingFunction}
);
case 'executions':
return <div>Executions view coming soon...</div>;
default:
return (
<FunctionList
key={refreshKey}
onCreateFunction={handleCreateFunction}
onEditFunction={handleEditFunction}
onExecuteFunction={handleExecuteFunction}
/>
);
}
};
<ExecutionModal
opened={executionModalOpened}
onClose={handleExecutionClose}
function={executingFunction}
/>
</AppShell.Main>
</AppShell>
</MantineProvider>
return (
<Box w="100%" pos="relative">
<Stack gap="lg">
<div>
<Group justify="space-between" align="flex-start">
<div>
<Group align="center" gap="sm" mb="xs">
<Title order={1} size="h2">
Function as a Service
</Title>
<ActionIcon
variant="subtle"
size="lg"
onClick={toggleFavorite}
aria-label={isFavorited ? "Remove from favorites" : "Add to favorites"}
>
{isFavorited ? (
<IconStarFilled size={20} color="gold" />
) : (
<IconStar size={20} />
)}
</ActionIcon>
</Group>
</div>
{/* Right-side controls */}
<Group align="flex-start" gap="lg">
<div>
<Select
placeholder="Choose a color"
data={colorOptions}
value={selectedColor}
onChange={(value) => setSelectedColor(value || '')}
size="sm"
w={150}
/>
</div>
</Group>
</Group>
</div>
<Tabs value={currentRoute} onChange={handleTabChange}>
<Tabs.List>
<Tabs.Tab
value="functions"
leftSection={<IconFunction size={16} />}
>
Functions
</Tabs.Tab>
<Tabs.Tab
value="executions"
leftSection={<IconPlayerPlay size={16} />}
>
Executions
</Tabs.Tab>
</Tabs.List>
<Box pt="md">
{renderContent()}
</Box>
</Tabs>
</Stack>
<FunctionForm
opened={functionFormOpened}
onClose={handleFormClose}
onSuccess={handleFormSuccess}
editFunction={editingFunction}
/>
<ExecutionModal
opened={executionModalOpened}
onClose={handleExecutionClose}
function={executingFunction}
/>
</Box>
);
};