diff --git a/bun.lock b/bun.lock index 5b3de5f68..d3d8be49b 100644 --- a/bun.lock +++ b/bun.lock @@ -67,7 +67,7 @@ "date-fns": "^4.1.0", "date-fns-tz": "^3.2.0", "deepmerge": "^4.3.1", - "e2b": "^2.7.0", + "e2b": "^2.10.2", "echarts": "^6.0.0", "echarts-for-react": "^3.0.2", "fast-xml-parser": "^4.5.1", @@ -157,11 +157,11 @@ }, }, "overrides": { - "@nodelib/fs.scandir": "2.1.5", - "@nodelib/fs.stat": "2.0.5", "@shikijs/core": "2.3.2", "@shikijs/themes": "2.3.2", "shiki": "2.3.2", + "@nodelib/fs.stat": "2.0.5", + "@nodelib/fs.scandir": "2.1.5", "whatwg-url": "^13", }, "packages": { @@ -1617,7 +1617,7 @@ "duplexify": ["duplexify@4.1.3", "", { "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", "stream-shift": "^1.0.2" } }, "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA=="], - "e2b": ["e2b@2.7.0", "", { "dependencies": { "@bufbuild/protobuf": "^2.6.2", "@connectrpc/connect": "2.0.0-rc.3", "@connectrpc/connect-web": "2.0.0-rc.3", "chalk": "^5.3.0", "compare-versions": "^6.1.0", "dockerfile-ast": "^0.7.1", "glob": "^11.0.3", "openapi-fetch": "^0.14.1", "platform": "^1.3.6", "tar": "^7.4.3" } }, "sha512-pbCbkkdkkY+yIhhtdSE7lM/vhIROtHNI0hNpj8lBphDILNH2qmmjhxU7/wam8/xWRbiWbfuQaOsv100lD32nag=="], + "e2b": ["e2b@2.10.2", "", { "dependencies": { "@bufbuild/protobuf": "^2.6.2", "@connectrpc/connect": "2.0.0-rc.3", "@connectrpc/connect-web": "2.0.0-rc.3", "chalk": "^5.3.0", "compare-versions": "^6.1.0", "dockerfile-ast": "^0.7.1", "glob": "^11.1.0", "openapi-fetch": "^0.14.1", "platform": "^1.3.6", "tar": "^7.5.2" } }, "sha512-lKwo5NZ+2v0mAWrqKGAEgSMP/ZPftq7uTtSdYVisVZi4JK9iITtS8SEQLKmRcG+T59/46b//JPvLwluFo1Qi7A=="], "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], diff --git a/package.json b/package.json index e579091b5..c51290eb2 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "date-fns": "^4.1.0", "date-fns-tz": "^3.2.0", "deepmerge": "^4.3.1", - "e2b": "^2.7.0", + "e2b": "^2.10.2", "echarts": "^6.0.0", "echarts-for-react": "^3.0.2", "fast-xml-parser": "^4.5.1", diff --git a/src/features/dashboard/templates/list/table-cells.tsx b/src/features/dashboard/templates/list/table-cells.tsx index 444922341..7072619b0 100644 --- a/src/features/dashboard/templates/list/table-cells.tsx +++ b/src/features/dashboard/templates/list/table-cells.tsx @@ -25,8 +25,9 @@ import { import { Loader } from '@/ui/primitives/loader_d' import { useMutation, useQueryClient } from '@tanstack/react-query' import { CellContext } from '@tanstack/react-table' -import { Lock, LockOpen, MoreVertical } from 'lucide-react' -import { useParams } from 'next/navigation' +import { Hammer, Lock, LockOpen, MoreVertical } from 'lucide-react' +import { useParams, useRouter } from 'next/navigation' +import { PROTECTED_URLS } from '@/configs/urls' import { useMemo, useState } from 'react' import ResourceUsage from '../../common/resource-usage' import { useDashboard } from '../../context' @@ -55,7 +56,9 @@ export function ActionsCell({ const { toast } = useToast() const trpc = useTRPC() const queryClient = useQueryClient() + const router = useRouter() const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false) + const [isRebuildDialogOpen, setIsRebuildDialogOpen] = useState(false) const updateTemplateMutation = useMutation( trpc.templates.updateTemplate.mutationOptions({ @@ -172,8 +175,40 @@ export function ActionsCell({ }) ) + const rebuildTemplateMutation = useMutation( + trpc.templates.rebuildTemplate.mutationOptions({ + onSuccess: async (data) => { + const templateName = template.aliases[0] || template.templateID + toast( + defaultSuccessToast( + <> + Rebuild started for template{' '} + {templateName}. + + ) + ) + + router.push( + PROTECTED_URLS.TEMPLATE_BUILD(teamIdOrSlug, data.templateID, data.buildID) + ) + }, + onError: (error) => { + const templateName = template.aliases[0] || template.templateID + toast( + defaultErrorToast( + error.message || `Failed to rebuild template ${templateName}.` + ) + ) + }, + onSettled: () => { + setIsRebuildDialogOpen(false) + }, + }) + ) + const isUpdating = updateTemplateMutation.isPending const isDeleting = deleteTemplateMutation.isPending + const isRebuilding = rebuildTemplateMutation.isPending const togglePublish = () => { updateTemplateMutation.mutate({ @@ -190,6 +225,15 @@ export function ActionsCell({ }) } + const rebuildTemplate = () => { + rebuildTemplateMutation.mutate({ + teamIdOrSlug: team.slug ?? team.id, + alias: template.aliases[0] || template.templateID, + cpuCount: template.cpuCount, + memoryMB: template.memoryMB, + }) + } + return ( <> + + You are about to rebuild the template{' '} + {template.aliases[0] && ( + <> + + {template.aliases[0]} + {' '} + ( + + )} + + {template.templateID} + + {template.aliases[0] && <>)}. This will create a new build with + the same configuration. + + } + confirm="Rebuild" + onConfirm={() => rebuildTemplate()} + confirmProps={{ + variant: 'default', + disabled: isRebuilding, + loading: isRebuilding, + }} + /> +