({
host,
workspace,
template,
agent,
})
| 69 | } |
| 70 | |
| 71 | export const PortForwardButton: FC<PortForwardButtonProps> = ({ |
| 72 | host, |
| 73 | workspace, |
| 74 | template, |
| 75 | agent, |
| 76 | }) => { |
| 77 | const { entitlements } = useDashboard(); |
| 78 | |
| 79 | const { data: listeningPorts } = useQuery({ |
| 80 | queryKey: ["portForward", agent.id], |
| 81 | queryFn: () => API.getAgentListeningPorts(agent.id), |
| 82 | enabled: agent.status === "connected", |
| 83 | refetchInterval: 5_000, |
| 84 | select: (res) => res.ports, |
| 85 | }); |
| 86 | |
| 87 | const { data: sharedPorts, refetch: refetchSharedPorts } = useQuery({ |
| 88 | ...workspacePortShares(workspace.id), |
| 89 | enabled: agent.status === "connected", |
| 90 | select: (res) => res.shares, |
| 91 | }); |
| 92 | |
| 93 | return ( |
| 94 | <Popover> |
| 95 | <PopoverTrigger asChild> |
| 96 | <Button disabled={!listeningPorts} size="sm" variant="subtle"> |
| 97 | <Spinner loading={!listeningPorts}> |
| 98 | <span css={styles.portCount}>{listeningPorts?.length}</span> |
| 99 | </Spinner> |
| 100 | Open ports |
| 101 | <ChevronDownIcon /> |
| 102 | </Button> |
| 103 | </PopoverTrigger> |
| 104 | <PopoverContent |
| 105 | align="end" |
| 106 | className="p-0 w-[404px] mt-1 text-content-secondary bg-surface-secondary border-surface-quaternary" |
| 107 | > |
| 108 | <PortForwardPopoverView |
| 109 | host={host} |
| 110 | agent={agent} |
| 111 | workspace={workspace} |
| 112 | template={template} |
| 113 | sharedPorts={sharedPorts ?? []} |
| 114 | listeningPorts={listeningPorts ?? []} |
| 115 | portSharingControlsEnabled={ |
| 116 | entitlements.features.control_shared_ports.enabled |
| 117 | } |
| 118 | refetchSharedPorts={refetchSharedPorts} |
| 119 | /> |
| 120 | </PopoverContent> |
| 121 | </Popover> |
| 122 | ); |
| 123 | }; |
| 124 | |
| 125 | const openPortSchema = (): Yup.AnyObjectSchema => |
| 126 | Yup.object({ |
nothing calls this directly
no test coverage detected