-
This commit is contained in:
@ -1,21 +1,21 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
Card,
|
|
||||||
Group,
|
|
||||||
Text,
|
|
||||||
Badge,
|
|
||||||
Stack,
|
|
||||||
Table,
|
Table,
|
||||||
Button,
|
Button,
|
||||||
|
Stack,
|
||||||
|
Title,
|
||||||
|
Modal,
|
||||||
Select,
|
Select,
|
||||||
TextInput,
|
TextInput,
|
||||||
Pagination,
|
Pagination,
|
||||||
Container,
|
Group,
|
||||||
Alert,
|
|
||||||
Loader,
|
|
||||||
Code,
|
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Modal,
|
Badge,
|
||||||
|
Card,
|
||||||
|
Text,
|
||||||
|
Loader,
|
||||||
|
Alert,
|
||||||
|
Code,
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
Flex,
|
Flex,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
@ -183,138 +183,162 @@ const ExecutionList: React.FC = () => {
|
|||||||
|
|
||||||
if (loading && executions.length === 0) {
|
if (loading && executions.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Container size="xl">
|
<Stack gap="lg">
|
||||||
<Flex justify="center" align="center" h={200}>
|
<Group justify="space-between">
|
||||||
|
<Title order={2}>Function Executions</Title>
|
||||||
|
<Button
|
||||||
|
leftSection={<IconRefresh size={16} />}
|
||||||
|
onClick={handleRefresh}
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Stack align="center" justify="center" h={200}>
|
||||||
<Loader size="lg" />
|
<Loader size="lg" />
|
||||||
</Flex>
|
<Text>Loading executions...</Text>
|
||||||
</Container>
|
</Stack>
|
||||||
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container size="xl">
|
<Stack gap="lg">
|
||||||
<Stack gap="md">
|
<Group justify="space-between">
|
||||||
<Card>
|
<Title order={2}>Function Executions</Title>
|
||||||
<Group justify="space-between" mb="md">
|
<Button
|
||||||
<Group>
|
leftSection={<IconRefresh size={16} />}
|
||||||
<TextInput
|
onClick={handleRefresh}
|
||||||
placeholder="Search executions..."
|
loading={loading}
|
||||||
value={searchTerm}
|
>
|
||||||
onChange={(event) => setSearchTerm(event.currentTarget.value)}
|
Refresh
|
||||||
leftSection={<IconSearch size={16} />}
|
</Button>
|
||||||
style={{ width: 300 }}
|
</Group>
|
||||||
/>
|
|
||||||
<Select
|
|
||||||
placeholder="All Functions"
|
|
||||||
data={functions.map(f => ({ value: f.id, label: f.name }))}
|
|
||||||
value={selectedFunction}
|
|
||||||
onChange={(value) => {
|
|
||||||
setSelectedFunction(value || '');
|
|
||||||
setPage(1);
|
|
||||||
}}
|
|
||||||
clearable
|
|
||||||
style={{ width: 200 }}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
<Button leftSection={<IconRefresh size={16} />} onClick={handleRefresh} loading={loading}>
|
|
||||||
Refresh
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
{error && (
|
<Group>
|
||||||
<Alert color="red" mb="md">
|
<TextInput
|
||||||
{error}
|
placeholder="Search executions..."
|
||||||
</Alert>
|
value={searchTerm}
|
||||||
)}
|
onChange={(event) => setSearchTerm(event.currentTarget.value)}
|
||||||
|
leftSection={<IconSearch size={16} />}
|
||||||
|
style={{ width: 300 }}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
placeholder="All Functions"
|
||||||
|
data={functions.map(f => ({ value: f.id, label: f.name }))}
|
||||||
|
value={selectedFunction}
|
||||||
|
onChange={(value) => {
|
||||||
|
setSelectedFunction(value || '');
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
|
clearable
|
||||||
|
style={{ width: 200 }}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
|
||||||
{filteredExecutions.length === 0 ? (
|
{error && (
|
||||||
<Text c="dimmed" ta="center" py="xl">
|
<Alert color="red" title="Error">
|
||||||
No executions found
|
{error}
|
||||||
</Text>
|
</Alert>
|
||||||
) : (
|
)}
|
||||||
<ScrollArea>
|
|
||||||
<Table striped highlightOnHover>
|
|
||||||
<Table.Thead>
|
|
||||||
<Table.Tr>
|
|
||||||
<Table.Th>Function</Table.Th>
|
|
||||||
<Table.Th>Status</Table.Th>
|
|
||||||
<Table.Th>Duration</Table.Th>
|
|
||||||
<Table.Th>Memory</Table.Th>
|
|
||||||
<Table.Th>Started</Table.Th>
|
|
||||||
<Table.Th>Actions</Table.Th>
|
|
||||||
</Table.Tr>
|
|
||||||
</Table.Thead>
|
|
||||||
<Table.Tbody>
|
|
||||||
{filteredExecutions.map((execution) => (
|
|
||||||
<Table.Tr key={execution.id}>
|
|
||||||
<Table.Td>
|
|
||||||
<Stack gap={2}>
|
|
||||||
<Text fw={500}>{getFunctionName(execution.function_id)}</Text>
|
|
||||||
<Code size="xs">{execution.id.slice(0, 8)}...</Code>
|
|
||||||
</Stack>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Badge color={getStatusColor(execution.status)} variant="filled">
|
|
||||||
{execution.status}
|
|
||||||
</Badge>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Group gap="xs">
|
|
||||||
<IconClock size={14} />
|
|
||||||
<Text size="sm">{formatDuration(execution.duration)}</Text>
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Group gap="xs">
|
|
||||||
{/* <IconMemory size={14} /> */}
|
|
||||||
<Text size="sm">{formatMemory(execution.memory_used)}</Text>
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Text size="sm">{formatDate(execution.created_at)}</Text>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Group gap="xs">
|
|
||||||
<ActionIcon
|
|
||||||
size="sm"
|
|
||||||
variant="subtle"
|
|
||||||
onClick={() => handleViewLogs(execution)}
|
|
||||||
title="View Logs"
|
|
||||||
>
|
|
||||||
<IconEye size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
{(execution.status === 'running' || execution.status === 'pending') && (
|
|
||||||
<ActionIcon
|
|
||||||
size="sm"
|
|
||||||
variant="subtle"
|
|
||||||
color="red"
|
|
||||||
onClick={() => handleCancelExecution(execution.id)}
|
|
||||||
title="Cancel Execution"
|
|
||||||
>
|
|
||||||
<IconX size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
)}
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
|
||||||
))}
|
|
||||||
</Table.Tbody>
|
|
||||||
</Table>
|
|
||||||
</ScrollArea>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{totalPages > 1 && (
|
{filteredExecutions.length === 0 ? (
|
||||||
<Group justify="center" mt="md">
|
<Card shadow="sm" radius="md" withBorder p="xl">
|
||||||
<Pagination
|
<Stack align="center" gap="md">
|
||||||
value={page}
|
<IconClock size={48} color="gray" />
|
||||||
onChange={setPage}
|
<div style={{ textAlign: 'center' }}>
|
||||||
total={totalPages}
|
<Text fw={500} mb="xs">
|
||||||
size="sm"
|
No executions found
|
||||||
/>
|
</Text>
|
||||||
</Group>
|
<Text size="sm" c="dimmed">
|
||||||
)}
|
There are no function executions matching your current filters
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
</Stack>
|
) : (
|
||||||
|
<Card shadow="sm" radius="md" withBorder>
|
||||||
|
<Table>
|
||||||
|
<Table.Thead>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th>Function</Table.Th>
|
||||||
|
<Table.Th>Status</Table.Th>
|
||||||
|
<Table.Th>Duration</Table.Th>
|
||||||
|
<Table.Th>Memory</Table.Th>
|
||||||
|
<Table.Th>Started</Table.Th>
|
||||||
|
<Table.Th>Actions</Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
<Table.Tbody>
|
||||||
|
{filteredExecutions.map((execution) => (
|
||||||
|
<Table.Tr key={execution.id}>
|
||||||
|
<Table.Td>
|
||||||
|
<Stack gap={2}>
|
||||||
|
<Text fw={500}>{getFunctionName(execution.function_id)}</Text>
|
||||||
|
<Code style={{ fontSize: '12px' }}>{execution.id.slice(0, 8)}...</Code>
|
||||||
|
</Stack>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Badge color={getStatusColor(execution.status)} variant="light">
|
||||||
|
{execution.status}
|
||||||
|
</Badge>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Group gap="xs">
|
||||||
|
<IconClock size={14} />
|
||||||
|
<Text size="sm">{formatDuration(execution.duration)}</Text>
|
||||||
|
</Group>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Group gap="xs">
|
||||||
|
{/* <IconMemory size={14} /> */}
|
||||||
|
<Text size="sm">{formatMemory(execution.memory_used)}</Text>
|
||||||
|
</Group>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Text size="sm">{formatDate(execution.created_at)}</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Group gap="xs">
|
||||||
|
<ActionIcon
|
||||||
|
size="sm"
|
||||||
|
variant="subtle"
|
||||||
|
onClick={() => handleViewLogs(execution)}
|
||||||
|
title="View Logs"
|
||||||
|
>
|
||||||
|
<IconEye size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
{(execution.status === 'running' || execution.status === 'pending') && (
|
||||||
|
<ActionIcon
|
||||||
|
size="sm"
|
||||||
|
variant="subtle"
|
||||||
|
color="red"
|
||||||
|
onClick={() => handleCancelExecution(execution.id)}
|
||||||
|
title="Cancel Execution"
|
||||||
|
>
|
||||||
|
<IconX size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<Group justify="center">
|
||||||
|
<Pagination
|
||||||
|
value={page}
|
||||||
|
onChange={setPage}
|
||||||
|
total={totalPages}
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Logs Modal */}
|
{/* Logs Modal */}
|
||||||
<Modal
|
<Modal
|
||||||
@ -378,8 +402,8 @@ const ExecutionList: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
</Container>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ExecutionList;
|
export default ExecutionList;
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
Badge,
|
|
||||||
Button,
|
Button,
|
||||||
Group,
|
Stack,
|
||||||
Text,
|
|
||||||
ActionIcon,
|
|
||||||
Menu,
|
|
||||||
Paper,
|
|
||||||
Title,
|
Title,
|
||||||
Alert,
|
Group,
|
||||||
|
ActionIcon,
|
||||||
|
Badge,
|
||||||
|
Card,
|
||||||
|
Text,
|
||||||
Loader,
|
Loader,
|
||||||
Center,
|
Alert,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
Menu,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
IconPlayerPlay,
|
IconPlayerPlay,
|
||||||
@ -114,40 +114,50 @@ export const FunctionList: React.FC<FunctionListProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading && functions.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Center py={60}>
|
<Stack gap="lg">
|
||||||
<Loader size="lg" />
|
<Group justify="space-between">
|
||||||
</Center>
|
<Title order={2}>Functions</Title>
|
||||||
);
|
<Group>
|
||||||
}
|
<Button
|
||||||
|
leftSection={<IconRefresh size={16} />}
|
||||||
|
onClick={loadFunctions}
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
leftSection={<IconPlus size={16} />}
|
||||||
|
onClick={onCreateFunction}
|
||||||
|
>
|
||||||
|
Create Function
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
|
||||||
if (error) {
|
<Stack align="center" justify="center" h={200}>
|
||||||
return (
|
<Loader size="lg" />
|
||||||
<Alert icon={<IconExclamationCircle size={16} />} title="Error" color="red" mb="md">
|
<Text>Loading functions...</Text>
|
||||||
{error}
|
</Stack>
|
||||||
<Button variant="light" size="xs" mt="sm" onClick={loadFunctions}>
|
</Stack>
|
||||||
Retry
|
|
||||||
</Button>
|
|
||||||
</Alert>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper shadow="xs" p="md">
|
<Stack gap="lg">
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between">
|
||||||
<Title order={2}>Functions</Title>
|
<Title order={2}>Functions</Title>
|
||||||
<Group>
|
<Group>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconRefresh size={14} />}
|
leftSection={<IconRefresh size={16} />}
|
||||||
variant="light"
|
|
||||||
onClick={loadFunctions}
|
onClick={loadFunctions}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
Refresh
|
Refresh
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={14} />}
|
leftSection={<IconPlus size={16} />}
|
||||||
onClick={onCreateFunction}
|
onClick={onCreateFunction}
|
||||||
>
|
>
|
||||||
Create Function
|
Create Function
|
||||||
@ -155,121 +165,129 @@ export const FunctionList: React.FC<FunctionListProps> = ({
|
|||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<Alert color="red" title="Error">
|
||||||
|
{error}
|
||||||
|
<Button variant="light" size="xs" mt="sm" onClick={loadFunctions}>
|
||||||
|
Retry
|
||||||
|
</Button>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
{functions.length === 0 ? (
|
{functions.length === 0 ? (
|
||||||
<Center py={40}>
|
<Card shadow="sm" radius="md" withBorder p="xl">
|
||||||
<div style={{ textAlign: 'center' }}>
|
<Stack align="center" gap="md">
|
||||||
<IconCode size={48} color="gray" />
|
<IconCode size={48} color="gray" />
|
||||||
<Text size="lg" mt="md" c="dimmed">
|
<div style={{ textAlign: 'center' }}>
|
||||||
No functions found
|
<Text fw={500} mb="xs">
|
||||||
</Text>
|
No functions found
|
||||||
<Text size="sm" c="dimmed" mb="md">
|
</Text>
|
||||||
Create your first serverless function to get started
|
<Text size="sm" c="dimmed">
|
||||||
</Text>
|
Create your first serverless function to get started
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={14} />}
|
leftSection={<IconPlus size={16} />}
|
||||||
onClick={onCreateFunction}
|
onClick={onCreateFunction}
|
||||||
>
|
>
|
||||||
Create Function
|
Create Function
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</Stack>
|
||||||
</Center>
|
</Card>
|
||||||
) : (
|
) : (
|
||||||
<Table striped>
|
<Card shadow="sm" radius="md" withBorder>
|
||||||
<Table.Thead>
|
<Table>
|
||||||
<Table.Tr>
|
<Table.Thead>
|
||||||
<Table.Th>Name</Table.Th>
|
<Table.Tr>
|
||||||
<Table.Th>Runtime</Table.Th>
|
<Table.Th>Name</Table.Th>
|
||||||
<Table.Th>Image</Table.Th>
|
<Table.Th>Runtime</Table.Th>
|
||||||
<Table.Th>Memory</Table.Th>
|
<Table.Th>Image</Table.Th>
|
||||||
<Table.Th>Timeout</Table.Th>
|
<Table.Th>Memory</Table.Th>
|
||||||
<Table.Th>Owner</Table.Th>
|
<Table.Th>Timeout</Table.Th>
|
||||||
<Table.Th>Created</Table.Th>
|
<Table.Th>Owner</Table.Th>
|
||||||
<Table.Th>Actions</Table.Th>
|
<Table.Th>Created</Table.Th>
|
||||||
</Table.Tr>
|
<Table.Th>Actions</Table.Th>
|
||||||
</Table.Thead>
|
|
||||||
<Table.Tbody>
|
|
||||||
{functions.map((func) => (
|
|
||||||
<Table.Tr key={func.id}>
|
|
||||||
<Table.Td>
|
|
||||||
<Text fw={500}>{func.name}</Text>
|
|
||||||
<Text size="xs" c="dimmed">{func.handler}</Text>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Badge color={getRuntimeColor(func.runtime)} variant="light">
|
|
||||||
{func.runtime}
|
|
||||||
</Badge>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{func.image}
|
|
||||||
</Text>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Text size="sm">{func.memory} MB</Text>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Text size="sm">{func.timeout}</Text>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Text size="sm">
|
|
||||||
{func.owner?.name || 'Unknown'}
|
|
||||||
{func.owner?.type && (
|
|
||||||
<Text size="xs" c="dimmed">({func.owner.type})</Text>
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Text size="sm">
|
|
||||||
{func.created_at ? new Date(func.created_at).toLocaleDateString() : 'N/A'}
|
|
||||||
</Text>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Group gap="xs">
|
|
||||||
<Tooltip label="Execute Function">
|
|
||||||
<ActionIcon
|
|
||||||
variant="light"
|
|
||||||
color="green"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => onExecuteFunction(func)}
|
|
||||||
>
|
|
||||||
<IconPlayerPlay size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
<Menu position="bottom-end">
|
|
||||||
<Menu.Target>
|
|
||||||
<ActionIcon variant="light" size="sm">
|
|
||||||
<IconDots size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Menu.Target>
|
|
||||||
<Menu.Dropdown>
|
|
||||||
<Menu.Item
|
|
||||||
leftSection={<IconSettings size={16} />}
|
|
||||||
onClick={() => onEditFunction(func)}
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
leftSection={<IconRocket size={16} />}
|
|
||||||
onClick={() => handleDeploy(func)}
|
|
||||||
>
|
|
||||||
Deploy
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
leftSection={<IconTrash size={16} />}
|
|
||||||
color="red"
|
|
||||||
onClick={() => handleDelete(func)}
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu.Dropdown>
|
|
||||||
</Menu>
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
))}
|
</Table.Thead>
|
||||||
</Table.Tbody>
|
<Table.Tbody>
|
||||||
</Table>
|
{functions.map((func) => (
|
||||||
|
<Table.Tr key={func.id}>
|
||||||
|
<Table.Td>
|
||||||
|
<Text fw={500}>{func.name}</Text>
|
||||||
|
<Text size="xs" c="dimmed">{func.description || ''}</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Badge color={getRuntimeColor(func.runtime)} variant="light">
|
||||||
|
{func.runtime}
|
||||||
|
</Badge>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Text size="sm" c="dimmed">
|
||||||
|
{func.image || ''}
|
||||||
|
</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Text size="sm">{func.memoryLimit || 'N/A'} MB</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Text size="sm">{func.timeout || 'N/A'}</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Text size="sm">N/A</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Text size="sm">
|
||||||
|
{func.createdAt ? new Date(func.createdAt).toLocaleDateString() : 'N/A'}
|
||||||
|
</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Group gap="xs">
|
||||||
|
<Tooltip label="Execute Function">
|
||||||
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
color="green"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => onExecuteFunction(func)}
|
||||||
|
>
|
||||||
|
<IconPlayerPlay size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
<Menu position="bottom-end">
|
||||||
|
<Menu.Target>
|
||||||
|
<ActionIcon variant="subtle" size="sm">
|
||||||
|
<IconDots size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Menu.Target>
|
||||||
|
<Menu.Dropdown>
|
||||||
|
<Menu.Item
|
||||||
|
leftSection={<IconSettings size={16} />}
|
||||||
|
onClick={() => onEditFunction(func)}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
leftSection={<IconRocket size={16} />}
|
||||||
|
onClick={() => handleDeploy(func)}
|
||||||
|
>
|
||||||
|
Deploy
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
leftSection={<IconTrash size={16} />}
|
||||||
|
color="red"
|
||||||
|
onClick={() => handleDelete(func)}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.Dropdown>
|
||||||
|
</Menu>
|
||||||
|
</Group>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
)}
|
)}
|
||||||
</Paper>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -75,16 +75,16 @@ services:
|
|||||||
- ./migrations:/app/migrations:ro,Z
|
- ./migrations:/app/migrations:ro,Z
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
frontend:
|
# frontend:
|
||||||
build:
|
# build:
|
||||||
context: ./kms-frontend
|
# context: ./kms-frontend
|
||||||
dockerfile: Dockerfile
|
# dockerfile: Dockerfile
|
||||||
container_name: kms-frontend
|
# container_name: kms-frontend
|
||||||
ports:
|
# ports:
|
||||||
- "3000:80"
|
# - "3000:80"
|
||||||
networks:
|
# networks:
|
||||||
- kms-network
|
# - kms-network
|
||||||
restart: unless-stopped
|
# restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
|||||||
Reference in New Issue
Block a user