import * as React from 'react'; import { connect } from 'react-redux'; import * as _ from 'lodash'; import { Icon, Input, Select, Button, Tooltip, message } from 'antd'; import { Actions } from '../redux/redux'; import { usePortForward, PORT_FORWARD_STATE } from '../hooks/usePortForward'; import * as actions from '../redux/actions'; import { Service, Port } from '../types/*'; const stateColorMap = { [PORT_FORWARD_STATE.IDLE]: 'rgba(0,0,0,0.25)', [PORT_FORWARD_STATE.EXECUTING]: '#1890ff', [PORT_FORWARD_STATE.RUNNING]: '#52c41a', [PORT_FORWARD_STATE.ERROR]: '#ff4d4f', }; const stateIconMap = { [PORT_FORWARD_STATE.IDLE]: 'swap', [PORT_FORWARD_STATE.EXECUTING]: 'loading', [PORT_FORWARD_STATE.RUNNING]: 'swap', [PORT_FORWARD_STATE.ERROR]: 'reload', }; const stateTooltipMap = { [PORT_FORWARD_STATE.IDLE]: 'Click to start', [PORT_FORWARD_STATE.EXECUTING]: 'Executing...', [PORT_FORWARD_STATE.RUNNING]: 'Click to stop', [PORT_FORWARD_STATE.ERROR]: 'Click to reload', }; export interface ServiceItemPortForwardProps { service: Service; description: any; updateProfileService: (service: Service) => void; } function ServiceItemPortForward({ service, description, updateProfileService }: ServiceItemPortForwardProps) { const { name, context, namespace, localPort: initialLocalPort, remotePort: initialRemotePort } = service; const ports = (description ? description.spec.ports : []) as Port[]; const [remotePort, setRemotePort] = React.useState(initialRemotePort || ports[0].port); const [localPort, setLocalPort] = React.useState(initialLocalPort || remotePort); const [showLogs, setShowLogs] = React.useState(false); const toggleLogs = React.useCallback(() => { setShowLogs(prev => !prev); }, [setShowLogs]); const onChangeLocalPort = React.useCallback( (e: any) => { const port = parseInt(e.target.value, 10); setLocalPort(port); updateProfileService({ context, namespace, name, localPort: port, }); }, [setLocalPort], ); const onChangeRemotePort = React.useCallback( (value: string) => { const port = parseInt(value, 10); setRemotePort(port); updateProfileService({ context, namespace, name, remotePort: port, }); }, [setRemotePort], ); const { error, stdout, stderr, logs, restart, kill, state } = usePortForward({ service: { ...service, remotePort, localPort: localPort || remotePort, }, }); const handlePortForward = React.useCallback(() => { switch (state) { case PORT_FORWARD_STATE.IDLE: restart(); break; case PORT_FORWARD_STATE.EXECUTING: break; case PORT_FORWARD_STATE.RUNNING: kill(); message.info(`[port-forward]${name}: exited.`); break; case PORT_FORWARD_STATE.ERROR: restart(); break; } }, [state]); const disabled = React.useMemo(() => !remotePort || state === PORT_FORWARD_STATE.EXECUTING, [remotePort, state]); React.useEffect(() => { switch (state) { case PORT_FORWARD_STATE.IDLE: break; case PORT_FORWARD_STATE.EXECUTING: break; case PORT_FORWARD_STATE.RUNNING: message.success(`[port-forward]${name}: established.`); break; case PORT_FORWARD_STATE.ERROR: message.error( `[port-forward]${name}: failed to establish connection from remote:${remotePort} to local:${localPort}`, ); break; } }, [state]); return ( port-forward {ports.map(({ name, port, protocol, targetPort }) => ( {port} ))} {state === PORT_FORWARD_STATE.IDLE && ( Please click to start... )} {state !== PORT_FORWARD_STATE.IDLE && logs.map((log, idx) => {log})} ); } export default connect( undefined, (dispatch: React.Dispatch) => ({ updateProfileService: (service: Service) => { dispatch(actions.updateProfileService(service)); }, }), )(ServiceItemPortForward);