Skip to content

Commit

Permalink
fix: Ensure that the pro provider process is terminated before discon… (
Browse files Browse the repository at this point in the history
loft-sh#1426)

* fix: Ensure that the pro provider process is terminated before disconnecting it

* fix: Remove unnecessary effect dependencies
  • Loading branch information
PRTTMPRPHT authored Nov 27, 2024
1 parent 449d511 commit 3392134
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 59 deletions.
3 changes: 2 additions & 1 deletion desktop/src/client/pro/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export class ProClient implements TDebuggable {

// Don't await here, we want to return the unsubscribe function
return () => {
cmd.cancel()
// Still, return the promise so someone can choose to await if necessary.
return cmd.cancel()
}
}

Expand Down
127 changes: 72 additions & 55 deletions desktop/src/contexts/DevPodContext/Pro/ContextSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Close, Connect, DevpodWordmark, Ellipsis, Folder } from "@/icons"
import { getDisplayName, useLoginProModal } from "@/lib"
import { getDisplayName, Result, useLoginProModal } from "@/lib"
import { TProInstance } from "@/types"
import { useDeleteProviderModal } from "@/views/Providers"
import { ArrowUpDownIcon, CheckIcon } from "@chakra-ui/icons"
Expand All @@ -24,6 +24,7 @@ import {
Text,
VStack,
Tooltip,
Spinner,
} from "@chakra-ui/react"
import { ManagementV1Project } from "@loft-enterprise/client/gen/models/managementV1Project"
import { ReactNode, useMemo } from "react"
Expand All @@ -37,13 +38,17 @@ type THostPickerProps = Readonly<{
currentProject: ManagementV1Project
projects: readonly ManagementV1Project[]
onProjectChange: (newProject: ManagementV1Project) => void
onCancelWatch?: () => Promise<Result<undefined>>
waitingForCancel: boolean
}>
export function ContextSwitcher({
currentHost,
projects,
currentProject,
onProjectChange,
onHostChange,
onCancelWatch,
waitingForCancel,
}: THostPickerProps) {
const [[rawProInstances]] = useProInstances()
const proInstances = useMemo(() => {
Expand Down Expand Up @@ -89,59 +94,66 @@ export function ContextSwitcher({
<Portal>
<PopoverContent minWidth={"25rem"}>
<PopoverBody p="0">
<List>
{proInstances.map(({ host, authenticated, image }) => (
<ListItem key={host}>
<PlatformDetails
currentHost={currentHost}
host={host!}
image={image}
authenticated={authenticated}
onConnect={handleConnectPlatform}
onClick={() => onHostChange(host!)}
/>
{host === currentHost && (
<VStack
w="full"
align="start"
pb="4"
pt="2"
pl="2"
borderBottomWidth="thin"
borderBottomStyle="solid">
<Heading pl="4" size="xs" color="gray.500" textTransform="uppercase">
Projects
</Heading>
<List w="full">
{projects.map((project) => (
<ListItem key={project.metadata!.name}>
<Button
_hover={{ bgColor: "gray.100" }}
variant="unstyled"
w="full"
display="flex"
justifyContent="start"
alignItems="center"
leftIcon={<Folder boxSize={5} />}
pl="4"
color="gray.600"
fontWeight="normal"
rightIcon={
project.metadata?.name === currentProject.metadata?.name ? (
<CheckIcon />
) : undefined
}
onClick={() => onProjectChange(project)}>
{getDisplayName(project)}
</Button>
</ListItem>
))}
</List>
</VStack>
)}
</ListItem>
))}
</List>
{waitingForCancel ? (
<HStack alignItems={"center"} justifyContent={"center"} paddingY={"4"}>
<Spinner />
</HStack>
) : (
<List>
{proInstances.map(({ host, authenticated, image }) => (
<ListItem key={host}>
<PlatformDetails
currentHost={currentHost}
host={host!}
image={image}
onCancelWatch={onCancelWatch}
authenticated={authenticated}
onConnect={handleConnectPlatform}
onClick={() => onHostChange(host!)}
/>
{host === currentHost && (
<VStack
w="full"
align="start"
pb="4"
pt="2"
pl="2"
borderBottomWidth="thin"
borderBottomStyle="solid">
<Heading pl="4" size="xs" color="gray.500" textTransform="uppercase">
Projects
</Heading>
<List w="full">
{projects.map((project) => (
<ListItem key={project.metadata!.name}>
<Button
_hover={{ bgColor: "gray.100" }}
variant="unstyled"
w="full"
display="flex"
justifyContent="start"
alignItems="center"
leftIcon={<Folder boxSize={5} />}
pl="4"
color="gray.600"
fontWeight="normal"
rightIcon={
project.metadata?.name === currentProject.metadata?.name ? (
<CheckIcon />
) : undefined
}
onClick={() => onProjectChange(project)}>
{getDisplayName(project)}
</Button>
</ListItem>
))}
</List>
</VStack>
)}
</ListItem>
))}
</List>
)}
</PopoverBody>
</PopoverContent>
</Portal>
Expand All @@ -158,6 +170,7 @@ type TPlatformDetailsProps = Readonly<{
authenticated?: boolean | null
onClick: VoidFunction
onConnect: VoidFunction
onCancelWatch?: () => Promise<Result<undefined>>
}>
function PlatformDetails({
host,
Expand All @@ -166,13 +179,17 @@ function PlatformDetails({
authenticated,
onClick,
onConnect,
onCancelWatch,
}: TPlatformDetailsProps) {
const [, { disconnect }] = useProInstances()
const { modal: deleteProviderModal, open: openDeleteProviderModal } = useDeleteProviderModal(
host,
"Pro instance",
"disconnect",
() => disconnect.run({ id: host })
async () => {
await onCancelWatch?.()
disconnect.run({ id: host })
}
)

return (
Expand Down
23 changes: 20 additions & 3 deletions desktop/src/contexts/DevPodContext/Pro/ProProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ProClient, client as globalClient } from "@/client"
import { ToolbarActions, ToolbarTitle } from "@/components"
import { Annotations } from "@/lib"
import { Annotations, Result } from "@/lib"
import { Routes } from "@/routes"
import { Text } from "@chakra-ui/react"
import { ManagementV1Project } from "@loft-enterprise/client/gen/models/managementV1Project"
Expand Down Expand Up @@ -47,6 +47,12 @@ export function ProProvider({ host, children }: { host: string; children: ReactN
return projectsQuery.data?.[0]
}, [projectsQuery, selectedProject])

const [cancelWatch, setCancelWatch] = useState<
{ fn: () => Promise<Result<undefined>> } | undefined
>(undefined)

const [waitingForCancel, setWaitingForCancel] = useState<boolean>(false)

useEffect(() => {
if (!currentProject?.metadata?.name) {
return
Expand Down Expand Up @@ -77,9 +83,18 @@ export function ProProvider({ host, children }: { host: string; children: ReactN
}, 1_000)
})

return () => {
const canceler = () => {
canceled = true
toCancel()
setCancelWatch(undefined)
setWaitingForCancel(true)

return toCancel().finally(() => setWaitingForCancel(false))
}

setCancelWatch({ fn: canceler })

return () => {
canceler()
}
}, [client, store, currentProject])

Expand Down Expand Up @@ -123,6 +138,8 @@ export function ProProvider({ host, children }: { host: string; children: ReactN
projects={projectsQuery.data ?? []}
currentProject={currentProject!}
onProjectChange={handleProjectChanged}
onCancelWatch={cancelWatch?.fn}
waitingForCancel={waitingForCancel}
/>
</ToolbarActions>
{children}
Expand Down

0 comments on commit 3392134

Please sign in to comment.