Commit 235859f8 authored by ajlarrosa's avatar ajlarrosa

hs-12 migracion a node.js 12, ajustes varios para interacción con cluster panel

parent 43415c9f
@echo off
echo ========================================
echo Paso 1: Instalando Statik
echo ========================================
echo.
echo Instalando statik...
go get github.com/rakyll/statik
if %ERRORLEVEL% EQU 0 (
echo.
echo OK: Statik instalado correctamente
echo.
) else (
echo.
echo ERROR: No se pudo instalar statik
echo Verifica que Go este instalado y en el PATH
echo.
pause
exit /b 1
)
pause
@echo off
echo ========================================
echo Paso 2: Ejecutando Statik
echo ========================================
echo.
echo Convirtiendo archivos estaticos de web/build en codigo Go...
echo.
statik --src=web/build
if %ERRORLEVEL% EQU 0 (
echo.
echo OK: Statik ejecutado correctamente
echo Los archivos estaticos fueron embebidos en el codigo Go
echo.
) else (
echo.
echo ERROR: No se pudo ejecutar statik
echo Verifica que:
echo 1. El directorio web/build existe y tiene contenido
echo 2. Statik este instalado (ejecuta 1-instalar-statik.bat primero)
echo.
pause
exit /b 1
)
pause
# Script para compilar web-console completamente
# Autor: Generado automaticamente
# Descripcion: Compila el frontend React, ejecuta statik y compila el servidor Go
$ErrorActionPreference = "Stop"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Script de Compilacion de Web-Console " -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Variables
$ROOT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
$WEB_DIR = Join-Path $ROOT_DIR "web"
$ENV_FILE = Join-Path $WEB_DIR ".env.local"
Write-Host "[1/5] Verificando directorios..." -ForegroundColor Yellow
if (-not (Test-Path $WEB_DIR)) {
Write-Host "ERROR: Directorio web no encontrado: $WEB_DIR" -ForegroundColor Red
exit 1
}
# Verificar o crear .env.local
Write-Host "[2/5] Configurando variables de entorno..." -ForegroundColor Yellow
if (-not (Test-Path $ENV_FILE)) {
Write-Host " Creando archivo .env.local..." -ForegroundColor Gray
$clusterUrl = Read-Host " Ingresa REACT_APP_CLUSTER_URL (ej: localhost o http://localhost:8080) [default: localhost]"
if ([string]::IsNullOrWhiteSpace($clusterUrl)) {
$clusterUrl = "localhost"
}
Set-Content -Path $ENV_FILE -Value "REACT_APP_CLUSTER_URL=$clusterUrl"
Write-Host " OK: Archivo .env.local creado con REACT_APP_CLUSTER_URL=$clusterUrl" -ForegroundColor Green
} else {
Write-Host " OK: Archivo .env.local ya existe" -ForegroundColor Green
$envContent = Get-Content $ENV_FILE -Raw
if ($envContent -match "REACT_APP_CLUSTER_URL") {
Write-Host " OK: REACT_APP_CLUSTER_URL esta configurado" -ForegroundColor Green
Write-Host " Contenido actual:" -ForegroundColor Gray
Get-Content $ENV_FILE | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
} else {
Write-Host " ADVERTENCIA: REACT_APP_CLUSTER_URL no encontrado en .env.local" -ForegroundColor Yellow
$clusterUrl = Read-Host " Ingresa REACT_APP_CLUSTER_URL (ej: localhost o http://localhost:8080) [default: localhost]"
if ([string]::IsNullOrWhiteSpace($clusterUrl)) {
$clusterUrl = "localhost"
}
Add-Content -Path $ENV_FILE -Value "`nREACT_APP_CLUSTER_URL=$clusterUrl"
Write-Host " OK: REACT_APP_CLUSTER_URL agregado: $clusterUrl" -ForegroundColor Green
}
}
# Verificar Node.js y yarn
Write-Host "[3/5] Verificando dependencias..." -ForegroundColor Yellow
try {
$nodeVersion = node --version 2>&1
Write-Host " OK: Node.js instalado: $nodeVersion" -ForegroundColor Green
} catch {
Write-Host " ERROR: Node.js no encontrado. Por favor instalalo primero." -ForegroundColor Red
exit 1
}
try {
$yarnVersion = yarn --version 2>&1
Write-Host " OK: Yarn instalado: v$yarnVersion" -ForegroundColor Green
} catch {
Write-Host " ERROR: Yarn no encontrado. Instalando yarn..." -ForegroundColor Yellow
npm install -g yarn
if ($LASTEXITCODE -ne 0) {
Write-Host " ERROR: Error al instalar yarn" -ForegroundColor Red
exit 1
}
Write-Host " OK: Yarn instalado" -ForegroundColor Green
}
try {
$goVersion = go version 2>&1
Write-Host " OK: Go instalado: $goVersion" -ForegroundColor Green
} catch {
Write-Host " ERROR: Go no encontrado. Por favor instalalo primero." -ForegroundColor Red
exit 1
}
# Compilar frontend React
Write-Host "[4/5] Compilando frontend React..." -ForegroundColor Yellow
Push-Location $WEB_DIR
try {
Write-Host " Instalando dependencias de Node.js (si es necesario)..." -ForegroundColor Gray
yarn install --silent 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host " ADVERTENCIA: Algunas advertencias durante yarn install (continuando...)" -ForegroundColor Yellow
}
Write-Host " Compilando con yarn build..." -ForegroundColor Gray
yarn build 2>&1 | ForEach-Object {
if ($_ -match "Compiled|error|Error|Failed|failed") {
$color = if ($_ -match "error|Error|Failed|failed") { "Red" } else { "Gray" }
Write-Host " $_" -ForegroundColor $color
}
}
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Frontend compilado exitosamente" -ForegroundColor Green
} else {
Write-Host " ERROR: Error al compilar el frontend" -ForegroundColor Red
Pop-Location
exit 1
}
} catch {
Write-Host " ERROR: Error durante la compilacion del frontend: $_" -ForegroundColor Red
Pop-Location
exit 1
}
Pop-Location
# Verificar que web/build existe
$BUILD_DIR = Join-Path $WEB_DIR "build"
if (-not (Test-Path $BUILD_DIR)) {
Write-Host " ERROR: Directorio web/build no encontrado despues de la compilacion" -ForegroundColor Red
exit 1
}
Write-Host " OK: Directorio web/build verificado" -ForegroundColor Green
# Instalar statik si no esta instalado
Write-Host "[5/5] Preparando statik..." -ForegroundColor Yellow
Push-Location $ROOT_DIR
try {
Write-Host " Verificando si statik esta instalado..." -ForegroundColor Gray
$statikInstalled = Get-Command statik -ErrorAction SilentlyContinue
if (-not $statikInstalled) {
Write-Host " Instalando statik..." -ForegroundColor Gray
go get github.com/rakyll/statik 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Statik instalado" -ForegroundColor Green
} else {
Write-Host " ADVERTENCIA: No se pudo instalar statik automaticamente" -ForegroundColor Yellow
Write-Host " Intenta manualmente: go get github.com/rakyll/statik" -ForegroundColor Yellow
}
} else {
Write-Host " OK: Statik ya esta instalado" -ForegroundColor Green
}
Write-Host " Ejecutando statik --src=web/build..." -ForegroundColor Gray
statik --src=web/build 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Statik ejecutado exitosamente" -ForegroundColor Green
} else {
Write-Host " ERROR: Error al ejecutar statik" -ForegroundColor Red
Write-Host " Verifica que el directorio web/build exista y tenga contenido" -ForegroundColor Yellow
Pop-Location
exit 1
}
Write-Host " Compilando servidor Go..." -ForegroundColor Gray
go build -o ssh-web-console.exe 2>&1 | ForEach-Object {
if ($_ -match "error|Error") {
Write-Host " $_" -ForegroundColor Red
}
}
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Servidor Go compilado exitosamente" -ForegroundColor Green
$exePath = Join-Path $ROOT_DIR "ssh-web-console.exe"
if (Test-Path $exePath) {
Write-Host " OK: Ejecutable creado: $exePath" -ForegroundColor Green
}
} else {
Write-Host " ERROR: Error al compilar el servidor Go" -ForegroundColor Red
Pop-Location
exit 1
}
} catch {
Write-Host " ERROR: Error durante la compilacion: $_" -ForegroundColor Red
Pop-Location
exit 1
}
Pop-Location
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " OK: Compilacion completada exitosamente " -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Para ejecutar web-console:" -ForegroundColor Yellow
Write-Host " cd C:\wamp64\www\web-console" -ForegroundColor Gray
Write-Host " .\ssh-web-console.exe" -ForegroundColor Gray
Write-Host ""
Write-Host "El servidor escuchara en: http://localhost:2222" -ForegroundColor Gray
Write-Host ""
No preview for this file type
[{"C:\\ProgramasGO\\web-console\\web\\src\\index.tsx":"1","C:\\ProgramasGO\\web-console\\web\\src\\serviceWorkerRegistration.ts":"2","C:\\ProgramasGO\\web-console\\web\\src\\reportWebVitals.ts":"3","C:\\ProgramasGO\\web-console\\web\\src\\config\\config.ts":"4","C:\\ProgramasGO\\web-console\\web\\src\\locales\\i18n.ts":"5","C:\\ProgramasGO\\web-console\\web\\src\\App.tsx":"6","C:\\ProgramasGO\\web-console\\web\\src\\locales\\locales.ts":"7","C:\\ProgramasGO\\web-console\\web\\src\\components\\Console.tsx":"8","C:\\ProgramasGO\\web-console\\web\\src\\components\\Home.tsx":"9","C:\\ProgramasGO\\web-console\\web\\src\\config\\api_routers.ts":"10","C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\term_theme.ts":"11","C:\\ProgramasGO\\web-console\\web\\src\\libs\\terminal-resize.ts":"12","C:\\ProgramasGO\\web-console\\web\\src\\libs\\utils.ts":"13","C:\\ProgramasGO\\web-console\\web\\src\\libs\\sshwebsocket.ts":"14","C:\\ProgramasGO\\web-console\\web\\src\\libs\\string_format.ts":"15","C:\\ProgramasGO\\web-console\\web\\src\\components\\FileTrans.tsx":"16","C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\XTerm.tsx":"17","C:\\ProgramasGO\\web-console\\web\\src\\components\\layout\\Header.tsx":"18","C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\files_types.ts":"19","C:\\ProgramasGO\\web-console\\web\\src\\components\\SftpUpload.tsx":"20","C:\\ProgramasGO\\web-console\\web\\src\\components\\PathNav.tsx":"21","C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\GridFileItem.tsx":"22","C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\DownloadingFile.tsx":"23","C:\\ProgramasGO\\web-console\\web\\src\\components\\Signin.tsx":"24"},{"size":1034,"mtime":1650139214522,"results":"25","hashOfConfig":"26"},{"size":5435,"mtime":1630760757965,"results":"27","hashOfConfig":"26"},{"size":440,"mtime":1630760788779,"results":"28","hashOfConfig":"26"},{"size":1657,"mtime":1630324302839,"results":"29","hashOfConfig":"26"},{"size":1628,"mtime":1630324329302,"results":"30","hashOfConfig":"26"},{"size":405,"mtime":1631155881829,"results":"31","hashOfConfig":"26"},{"size":6835,"mtime":1630324344127,"results":"32","hashOfConfig":"26"},{"size":8120,"mtime":1632867133431,"results":"33","hashOfConfig":"26"},{"size":1593,"mtime":1633120989408,"results":"34","hashOfConfig":"26"},{"size":670,"mtime":1630324289991,"results":"35","hashOfConfig":"26"},{"size":1154,"mtime":1630324391856,"results":"36","hashOfConfig":"26"},{"size":675,"mtime":1630324268633,"results":"37","hashOfConfig":"26"},{"size":1412,"mtime":1630324319263,"results":"38","hashOfConfig":"26"},{"size":1919,"mtime":1630324271105,"results":"39","hashOfConfig":"26"},{"size":357,"mtime":1630324270079,"results":"40","hashOfConfig":"26"},{"size":14281,"mtime":1630290983845,"results":"41","hashOfConfig":"26"},{"size":7409,"mtime":1630324390675,"results":"42","hashOfConfig":"26"},{"size":684,"mtime":1630290955236,"results":"43","hashOfConfig":"26"},{"size":586,"mtime":1630324355567,"results":"44","hashOfConfig":"26"},{"size":4049,"mtime":1630291005021,"results":"45","hashOfConfig":"26"},{"size":2017,"mtime":1630290993235,"results":"46","hashOfConfig":"26"},{"size":5416,"mtime":1630290947773,"results":"47","hashOfConfig":"26"},{"size":1508,"mtime":1630291088613,"results":"48","hashOfConfig":"26"},{"size":4459,"mtime":1653648858832,"results":"49","hashOfConfig":"26"},{"filePath":"50","messages":"51","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},"1b6yqyj",{"filePath":"53","messages":"54","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"55","messages":"56","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"57","messages":"58","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"59","messages":"60","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"61","messages":"62","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"63","messages":"64","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"65","messages":"66","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"67","usedDeprecatedRules":"52"},{"filePath":"68","messages":"69","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"70","usedDeprecatedRules":"52"},{"filePath":"71","messages":"72","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"73","messages":"74","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"75","messages":"76","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"77","messages":"78","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"79","messages":"80","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"81","messages":"82","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"83","messages":"84","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"85","messages":"86","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"87","messages":"88","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"89","messages":"90","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"91","messages":"92","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"93","messages":"94","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"95","messages":"96","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},{"filePath":"97","messages":"98","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"99"},{"filePath":"100","messages":"101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"52"},"C:\\ProgramasGO\\web-console\\web\\src\\index.tsx",[],[],"C:\\ProgramasGO\\web-console\\web\\src\\serviceWorkerRegistration.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\reportWebVitals.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\config\\config.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\locales\\i18n.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\App.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\locales\\locales.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\Console.tsx",["102"],"import React, { useEffect, useRef, useState } from 'react';\r\nimport {\r\n Pane,\r\n Text,\r\n Heading,\r\n Badge,\r\n Menu,\r\n Popover,\r\n Position,\r\n Avatar,\r\n Button,\r\n toaster,\r\n CornerDialog,\r\n} from 'evergreen-ui';\r\nimport {\r\n FullCircleIcon,\r\n UngroupObjectsIcon,\r\n ErrorIcon,\r\n DisableIcon,\r\n} from 'evergreen-ui';\r\nimport { RouteComponentProps } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { FitAddon } from 'xterm-addon-fit';\r\nimport { WebLinksAddon } from 'xterm-addon-web-links';\r\n\r\nimport XTerm from './term/XTerm';\r\nimport theme from './term/term_theme';\r\nimport FileTrans, { NodeConfig, ConnStatus } from './FileTrans';\r\nimport sshWebSocket from '../libs/sshwebsocket';\r\nimport terminalResize from '../libs/terminal-resize';\r\nimport Util from '../libs/utils';\r\nimport apiRouters from '../config/api_routers';\r\nimport Config from '../config/config';\r\nimport stringFormat from '../libs/string_format';\r\n\r\nimport './console.less';\r\n\r\ntype ConnStatusProps = {\r\n host: string;\r\n status: ConnStatus;\r\n};\r\n\r\nconst ConnectionStatus = (props: ConnStatusProps) => {\r\n if (props.status === ConnStatus.Connecting) {\r\n return (\r\n <>\r\n <UngroupObjectsIcon\r\n verticalAlign=\"baseline\"\r\n size={10}\r\n color=\"info\"\r\n marginRight={8}\r\n />\r\n <Badge isInteractive textTransform=\"lowercase\" color=\"blue\">\r\n waiting connection\r\n </Badge>\r\n </>\r\n );\r\n } else if (props.status === ConnStatus.ConnectionLost) {\r\n return (\r\n <>\r\n <DisableIcon\r\n verticalAlign=\"baseline\"\r\n size={10}\r\n color=\"#FAE2E2\"\r\n marginRight={8}\r\n />\r\n <Badge isInteractive color=\"red\">\r\n connection lost\r\n </Badge>\r\n </>\r\n );\r\n } else {\r\n return (\r\n <>\r\n <FullCircleIcon\r\n verticalAlign=\"baseline\"\r\n size={10}\r\n color=\"success\"\r\n marginRight={8}\r\n />\r\n <Badge isInteractive textTransform=\"lowercase\" color=\"green\">\r\n {props.host}\r\n </Badge>\r\n </>\r\n );\r\n }\r\n};\r\n\r\nconst Console = (props: RouteComponentProps) => {\r\n const [isSideSheetShown, setSideSheetShwon] = useState<boolean>(false);\r\n const terminalRef = useRef<XTerm>(null);\r\n const { t } = useTranslation(['translation', 'console']);\r\n const [fitAddon] = useState<FitAddon>(new FitAddon());\r\n const [webLinksAddon] = useState<WebLinksAddon>(new WebLinksAddon());\r\n const [fullscreen, setFullscreen] = useState<boolean>(false);\r\n const [connecting, setConnecting] = useState<ConnStatus>(\r\n ConnStatus.Connecting,\r\n );\r\n const [nodeConfig, setNodeConfig] = useState<NodeConfig>({\r\n host: 'waiting connection',\r\n username: 'Loading',\r\n });\r\n const [showCornerDialog, setShowCornerDialog] = useState<boolean>(false);\r\n\r\n let ws: WebSocket | null = null;\r\n\r\n useEffect(() => {\r\n const lhost = window.localStorage.getItem('user.host');\r\n const luname = window.localStorage.getItem('user.username');\r\n if (lhost === null) {\r\n return;\r\n }\r\n if (luname === null) {\r\n return;\r\n }\r\n setNodeConfig({ host: lhost, username: luname });\r\n }, []);\r\n\r\n useEffect(() => {\r\n // Once the terminal is loaded write a new line to it.\r\n const term = terminalRef.current!.terminal;\r\n fitAddon.fit();\r\n term.writeln('Welcome to SSH web-console!');\r\n\r\n const _t = sessionStorage.getItem(Config.jwt.tokenName);\r\n if (_t === null) {\r\n toaster.danger(t('console:web_socket_expire'));\r\n props.history.push('/signin');\r\n return;\r\n }\r\n\r\n ws = new WebSocket(\r\n Util.loadWebSocketUrl(\r\n apiRouters.router.ws_ssh,\r\n stringFormat.format(\r\n apiRouters.params.ws_ssh,\r\n term.cols + '',\r\n term.rows + '',\r\n _t,\r\n ),\r\n ),\r\n );\r\n ws.binaryType = 'arraybuffer';\r\n ws.onopen = () => {\r\n setConnecting(ConnStatus.ConnectionAlive);\r\n };\r\n\r\n ws.onclose = (ev) => {\r\n term.setOption('cursorBlink', false);\r\n sessionStorage.removeItem(Config.jwt.tokenName);\r\n setConnecting(ConnStatus.ConnectionLost);\r\n setShowCornerDialog(true);\r\n\r\n send(ev);\r\n };\r\n\r\n const send = (e: CloseEvent) => {\r\n e.preventDefault();\r\n\r\n if (window && window.parent) {\r\n window.parent.postMessage(\r\n {\r\n message: 'close',\r\n },\r\n '*',\r\n );\r\n }\r\n };\r\n\r\n sshWebSocket.bindTerminal(term, ws!, true, -1);\r\n terminalResize.bindTerminalResize(term, ws!);\r\n return () => {\r\n if (ws !== null) {\r\n ws.close();\r\n }\r\n };\r\n }, []);\r\n\r\n useEffect(() => {\r\n fitAddon.fit();\r\n }, [fullscreen]);\r\n\r\n const onWindowResize = () => {\r\n fitAddon.fit();\r\n };\r\n const closeWindowListener = (ev: BeforeUnloadEvent) => {\r\n ev.preventDefault();\r\n ev.returnValue = t('console:make_sure_to_leave');\r\n };\r\n\r\n useEffect(() => {\r\n window.addEventListener('resize', onWindowResize);\r\n window.addEventListener('beforeunload', closeWindowListener);\r\n return () => {\r\n window.removeEventListener('resize', onWindowResize);\r\n window.removeEventListener('beforeunload', closeWindowListener);\r\n };\r\n }, []);\r\n\r\n return (\r\n <Pane height=\"100vh\" display=\"flex\" flexDirection=\"column\" borderRadius={3}>\r\n <Pane\r\n display=\"flex\"\r\n flexDirection=\"row\"\r\n alignItems=\"center\"\r\n background=\"rgba(27,33,47,0.86)\">\r\n <Heading padding={18} color=\"white\">\r\n {' '}\r\n {t('title')}\r\n </Heading>\r\n <Pane\r\n padding={18}\r\n flex={1}\r\n alignItems=\"center\"\r\n alignContent=\"center\"\r\n textAlign=\"center\">\r\n <ConnectionStatus status={connecting} host={nodeConfig.host} />\r\n </Pane>\r\n <Popover\r\n position={Position.BOTTOM_LEFT}\r\n content={\r\n <Menu>\r\n <Menu.Group>\r\n <Menu.Item>\r\n {'@'} {nodeConfig.username}{' '}\r\n </Menu.Item>\r\n </Menu.Group>\r\n <Menu.Divider />\r\n </Menu>\r\n }>\r\n <Avatar\r\n isSolid\r\n name={nodeConfig.username}\r\n size={36}\r\n marginRight={36}\r\n cursor=\"pointer\"\r\n />\r\n </Popover>\r\n </Pane>\r\n <Pane flex={1} overflowY=\"hidden\">\r\n <XTerm\r\n className={\r\n fullscreen ? 'term-container fullscreen' : 'term-container'\r\n }\r\n options={{\r\n cursorBlink: true,\r\n bellStyle: 'sound',\r\n theme: theme.default_theme,\r\n }}\r\n addons={[fitAddon, webLinksAddon]}\r\n ref={terminalRef}\r\n />\r\n </Pane>\r\n <Pane display=\"flex\" alignItems=\"center\">\r\n <FileTrans\r\n isShown={isSideSheetShown}\r\n node={{ host: nodeConfig.host, username: nodeConfig.username }}\r\n sshStatus={connecting}\r\n hideSideSheeeet={() => {\r\n setSideSheetShwon(false);\r\n }}\r\n />\r\n <Button intent=\"success\" onClick={() => setSideSheetShwon(true)}>\r\n SFTP\r\n </Button>\r\n <Pane flex=\"1\"></Pane>\r\n <Text marginRight=\"0.4rem\">active time: 0:00:00</Text>\r\n </Pane>\r\n <CornerDialog\r\n title={\r\n <Text size={500} color=\"danger\" alignItems=\"center\" display=\"flex\">\r\n <ErrorIcon marginRight=\"0.2rem\" />{' '}\r\n {t('console:ssh_disconn_dialog_title')}\r\n </Text>\r\n }\r\n isShown={showCornerDialog}\r\n hasClose={false}\r\n cancelLabel={t('console:ssh_disconn_dialog_cancel_btn')}\r\n confirmLabel={t('console:ssh_disconn_dialog_confirm_btn')}\r\n onConfirm={() => {\r\n props.history.push('/signin');\r\n }}\r\n containerProps={{ zIndex: 20 }}\r\n onCloseComplete={() => setShowCornerDialog(false)}>\r\n {t('console:ssh_disconn_dialog_text')}\r\n </CornerDialog>\r\n </Pane>\r\n );\r\n};\r\n\r\nexport default Console;\r\n","C:\\ProgramasGO\\web-console\\web\\src\\components\\Home.tsx",["103"],"import React from 'react';\r\nimport { NavLink, Route, Switch } from 'react-router-dom';\r\nimport { Button, Pane, Heading } from 'evergreen-ui';\r\nimport { useTranslation } from 'react-i18next';\r\n\r\nimport Header from './layout/Header';\r\nimport Signin from './Signin';\r\n\r\nimport './home.less';\r\nimport headerLogo from '../assets/ssh.png';\r\n\r\nconst MainPage = () => {\r\n const { t } = useTranslation(['home']);\r\n return (\r\n <>\r\n <Pane\r\n alignItems=\"center\"\r\n justifyContent=\"center\"\r\n display=\"flex\"\r\n flexDirection=\"column\">\r\n <div\r\n style={{\r\n minHeight: '360px',\r\n marginTop: '10rem',\r\n textAlign: 'center',\r\n }}>\r\n <img src={headerLogo} className=\"App-logo\" alt=\"logo\" />\r\n <Heading marginBottom=\"0.6rem\" marginTop=\"0.6rem\" size={700}>\r\n {t('home:welcome')}\r\n </Heading>\r\n <div>\r\n <NavLink to=\"/signin\" className=\"focus-ring-link\">\r\n <Button appearance=\"primary\"> {t('home:goto_signin')} </Button>\r\n </NavLink>\r\n </div>\r\n </div>\r\n </Pane>\r\n </>\r\n );\r\n};\r\n\r\nconst Home = () => {\r\n return (\r\n <div className=\"home-container\">\r\n <header className=\"home-content-header\">\r\n <Header />\r\n </header>\r\n <main className=\"home-content-main main-content-container\">\r\n <Switch>\r\n <Route exact path={`/`} component={Signin} />\r\n <Route path={`/signin`} component={Signin} />\r\n </Switch>\r\n </main>\r\n </div>\r\n );\r\n};\r\n\r\nexport default Home;\r\n","C:\\ProgramasGO\\web-console\\web\\src\\config\\api_routers.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\term_theme.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\terminal-resize.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\utils.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\sshwebsocket.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\string_format.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\FileTrans.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\XTerm.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\layout\\Header.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\files_types.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\SftpUpload.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\PathNav.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\GridFileItem.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\DownloadingFile.tsx",[],[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\Signin.tsx",[],{"ruleId":"104","severity":1,"message":"105","line":95,"column":22,"nodeType":"106","messageId":"107","endLine":95,"endColumn":35},{"ruleId":"104","severity":1,"message":"108","line":12,"column":7,"nodeType":"106","messageId":"107","endLine":12,"endColumn":15},"@typescript-eslint/no-unused-vars","'setFullscreen' is assigned a value but never used.","Identifier","unusedVar","'MainPage' is assigned a value but never used."]
\ No newline at end of file
[{"C:\\ProgramasGO\\web-console\\web\\src\\index.tsx":"1","C:\\ProgramasGO\\web-console\\web\\src\\serviceWorkerRegistration.ts":"2","C:\\ProgramasGO\\web-console\\web\\src\\reportWebVitals.ts":"3","C:\\ProgramasGO\\web-console\\web\\src\\config\\config.ts":"4","C:\\ProgramasGO\\web-console\\web\\src\\locales\\i18n.ts":"5","C:\\ProgramasGO\\web-console\\web\\src\\App.tsx":"6","C:\\ProgramasGO\\web-console\\web\\src\\locales\\locales.ts":"7","C:\\ProgramasGO\\web-console\\web\\src\\components\\Console.tsx":"8","C:\\ProgramasGO\\web-console\\web\\src\\components\\Home.tsx":"9","C:\\ProgramasGO\\web-console\\web\\src\\config\\api_routers.ts":"10","C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\term_theme.ts":"11","C:\\ProgramasGO\\web-console\\web\\src\\libs\\terminal-resize.ts":"12","C:\\ProgramasGO\\web-console\\web\\src\\libs\\utils.ts":"13","C:\\ProgramasGO\\web-console\\web\\src\\libs\\sshwebsocket.ts":"14","C:\\ProgramasGO\\web-console\\web\\src\\libs\\string_format.ts":"15","C:\\ProgramasGO\\web-console\\web\\src\\components\\FileTrans.tsx":"16","C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\XTerm.tsx":"17","C:\\ProgramasGO\\web-console\\web\\src\\components\\layout\\Header.tsx":"18","C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\files_types.ts":"19","C:\\ProgramasGO\\web-console\\web\\src\\components\\SftpUpload.tsx":"20","C:\\ProgramasGO\\web-console\\web\\src\\components\\PathNav.tsx":"21","C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\GridFileItem.tsx":"22","C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\DownloadingFile.tsx":"23","C:\\ProgramasGO\\web-console\\web\\src\\components\\Signin.tsx":"24","C:\\wamp64\\www\\web-console\\web\\src\\index.tsx":"25","C:\\wamp64\\www\\web-console\\web\\src\\serviceWorkerRegistration.ts":"26","C:\\wamp64\\www\\web-console\\web\\src\\reportWebVitals.ts":"27","C:\\wamp64\\www\\web-console\\web\\src\\config\\config.ts":"28","C:\\wamp64\\www\\web-console\\web\\src\\locales\\i18n.ts":"29","C:\\wamp64\\www\\web-console\\web\\src\\App.tsx":"30","C:\\wamp64\\www\\web-console\\web\\src\\locales\\locales.ts":"31","C:\\wamp64\\www\\web-console\\web\\src\\components\\Console.tsx":"32","C:\\wamp64\\www\\web-console\\web\\src\\components\\Home.tsx":"33","C:\\wamp64\\www\\web-console\\web\\src\\config\\api_routers.ts":"34","C:\\wamp64\\www\\web-console\\web\\src\\components\\term\\term_theme.ts":"35","C:\\wamp64\\www\\web-console\\web\\src\\libs\\sshwebsocket.ts":"36","C:\\wamp64\\www\\web-console\\web\\src\\libs\\terminal-resize.ts":"37","C:\\wamp64\\www\\web-console\\web\\src\\libs\\utils.ts":"38","C:\\wamp64\\www\\web-console\\web\\src\\libs\\string_format.ts":"39","C:\\wamp64\\www\\web-console\\web\\src\\components\\FileTrans.tsx":"40","C:\\wamp64\\www\\web-console\\web\\src\\components\\Signin.tsx":"41","C:\\wamp64\\www\\web-console\\web\\src\\components\\term\\XTerm.tsx":"42","C:\\wamp64\\www\\web-console\\web\\src\\components\\layout\\Header.tsx":"43","C:\\wamp64\\www\\web-console\\web\\src\\components\\files\\files_types.ts":"44","C:\\wamp64\\www\\web-console\\web\\src\\components\\PathNav.tsx":"45","C:\\wamp64\\www\\web-console\\web\\src\\components\\SftpUpload.tsx":"46","C:\\wamp64\\www\\web-console\\web\\src\\components\\files\\GridFileItem.tsx":"47","C:\\wamp64\\www\\web-console\\web\\src\\components\\files\\DownloadingFile.tsx":"48"},{"size":1034,"mtime":1650139214522,"results":"49","hashOfConfig":"50"},{"size":5435,"mtime":1630760757965,"results":"51","hashOfConfig":"50"},{"size":440,"mtime":1630760788779,"results":"52","hashOfConfig":"50"},{"size":1657,"mtime":1630324302839,"results":"53","hashOfConfig":"50"},{"size":1628,"mtime":1630324329302,"results":"54","hashOfConfig":"50"},{"size":405,"mtime":1631155881829,"results":"55","hashOfConfig":"50"},{"size":6835,"mtime":1630324344127,"results":"56","hashOfConfig":"50"},{"size":8120,"mtime":1632867133431,"results":"57","hashOfConfig":"50"},{"size":1593,"mtime":1633120989408,"results":"58","hashOfConfig":"50"},{"size":670,"mtime":1630324289991,"results":"59","hashOfConfig":"50"},{"size":1154,"mtime":1630324391856,"results":"60","hashOfConfig":"50"},{"size":675,"mtime":1630324268633,"results":"61","hashOfConfig":"50"},{"size":1412,"mtime":1630324319263,"results":"62","hashOfConfig":"50"},{"size":1919,"mtime":1630324271105,"results":"63","hashOfConfig":"50"},{"size":357,"mtime":1630324270079,"results":"64","hashOfConfig":"50"},{"size":14281,"mtime":1630290983845,"results":"65","hashOfConfig":"50"},{"size":7409,"mtime":1630324390675,"results":"66","hashOfConfig":"50"},{"size":684,"mtime":1630290955236,"results":"67","hashOfConfig":"50"},{"size":586,"mtime":1630324355567,"results":"68","hashOfConfig":"50"},{"size":4049,"mtime":1630291005021,"results":"69","hashOfConfig":"50"},{"size":2017,"mtime":1630290993235,"results":"70","hashOfConfig":"50"},{"size":5416,"mtime":1630290947773,"results":"71","hashOfConfig":"50"},{"size":1508,"mtime":1630291088613,"results":"72","hashOfConfig":"50"},{"size":4459,"mtime":1653648858832,"results":"73","hashOfConfig":"50"},{"size":1034,"mtime":1763674775437,"results":"74","hashOfConfig":"75"},{"size":5435,"mtime":1763674775442,"results":"76","hashOfConfig":"75"},{"size":440,"mtime":1763674775441,"results":"77","hashOfConfig":"75"},{"size":1657,"mtime":1763674775435,"results":"78","hashOfConfig":"75"},{"size":1628,"mtime":1763674775440,"results":"79","hashOfConfig":"75"},{"size":405,"mtime":1763674775424,"results":"80","hashOfConfig":"75"},{"size":6835,"mtime":1763674775440,"results":"81","hashOfConfig":"75"},{"size":8120,"mtime":1763674775425,"results":"82","hashOfConfig":"75"},{"size":1593,"mtime":1763674775427,"results":"83","hashOfConfig":"75"},{"size":670,"mtime":1763674775435,"results":"84","hashOfConfig":"75"},{"size":1154,"mtime":1763674775434,"results":"85","hashOfConfig":"75"},{"size":1919,"mtime":1763674775437,"results":"86","hashOfConfig":"75"},{"size":675,"mtime":1763674775438,"results":"87","hashOfConfig":"75"},{"size":1412,"mtime":1763674775439,"results":"88","hashOfConfig":"75"},{"size":357,"mtime":1763674775438,"results":"89","hashOfConfig":"75"},{"size":14281,"mtime":1763674775426,"results":"90","hashOfConfig":"75"},{"size":4488,"mtime":1763761637241,"results":"91","hashOfConfig":"75"},{"size":7409,"mtime":1763674775434,"results":"92","hashOfConfig":"75"},{"size":684,"mtime":1763674775432,"results":"93","hashOfConfig":"75"},{"size":586,"mtime":1763674775431,"results":"94","hashOfConfig":"75"},{"size":2017,"mtime":1763674775427,"results":"95","hashOfConfig":"75"},{"size":4049,"mtime":1763674775428,"results":"96","hashOfConfig":"75"},{"size":5416,"mtime":1763674775430,"results":"97","hashOfConfig":"75"},{"size":1508,"mtime":1763674775430,"results":"98","hashOfConfig":"75"},{"filePath":"99","messages":"100","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},"1b6yqyj",{"filePath":"102","messages":"103","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"104","messages":"105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"106","messages":"107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"108","messages":"109","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"110","messages":"111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"112","messages":"113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"114","messages":"115","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"116","usedDeprecatedRules":"101"},{"filePath":"117","messages":"118","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"119","usedDeprecatedRules":"101"},{"filePath":"120","messages":"121","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"122","messages":"123","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"124","messages":"125","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"126","messages":"127","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"128","messages":"129","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"130","messages":"131","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"132","messages":"133","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"134","messages":"135","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"136","messages":"137","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"138","messages":"139","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"140","messages":"141","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"142","messages":"143","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"144","messages":"145","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"146","messages":"147","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"148"},{"filePath":"149","messages":"150","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"101"},{"filePath":"151","messages":"152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"u24llo",{"filePath":"153","messages":"154","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"155","messages":"156","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"157","messages":"158","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"159","messages":"160","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"161","messages":"162","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"163","messages":"164","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"165","messages":"166","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"116"},{"filePath":"167","messages":"168","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"119"},{"filePath":"169","messages":"170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"171","messages":"172","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"173","messages":"174","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"175","messages":"176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"177","messages":"178","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"179","messages":"180","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"181","messages":"182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"183","messages":"184","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"185","messages":"186","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"187","messages":"188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"189","messages":"190","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"191","messages":"192","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"193","messages":"194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"195","messages":"196","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"197","messages":"198","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\ProgramasGO\\web-console\\web\\src\\index.tsx",[],[],"C:\\ProgramasGO\\web-console\\web\\src\\serviceWorkerRegistration.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\reportWebVitals.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\config\\config.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\locales\\i18n.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\App.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\locales\\locales.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\Console.tsx",["199"],"import React, { useEffect, useRef, useState } from 'react';\r\nimport {\r\n Pane,\r\n Text,\r\n Heading,\r\n Badge,\r\n Menu,\r\n Popover,\r\n Position,\r\n Avatar,\r\n Button,\r\n toaster,\r\n CornerDialog,\r\n} from 'evergreen-ui';\r\nimport {\r\n FullCircleIcon,\r\n UngroupObjectsIcon,\r\n ErrorIcon,\r\n DisableIcon,\r\n} from 'evergreen-ui';\r\nimport { RouteComponentProps } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { FitAddon } from 'xterm-addon-fit';\r\nimport { WebLinksAddon } from 'xterm-addon-web-links';\r\n\r\nimport XTerm from './term/XTerm';\r\nimport theme from './term/term_theme';\r\nimport FileTrans, { NodeConfig, ConnStatus } from './FileTrans';\r\nimport sshWebSocket from '../libs/sshwebsocket';\r\nimport terminalResize from '../libs/terminal-resize';\r\nimport Util from '../libs/utils';\r\nimport apiRouters from '../config/api_routers';\r\nimport Config from '../config/config';\r\nimport stringFormat from '../libs/string_format';\r\n\r\nimport './console.less';\r\n\r\ntype ConnStatusProps = {\r\n host: string;\r\n status: ConnStatus;\r\n};\r\n\r\nconst ConnectionStatus = (props: ConnStatusProps) => {\r\n if (props.status === ConnStatus.Connecting) {\r\n return (\r\n <>\r\n <UngroupObjectsIcon\r\n verticalAlign=\"baseline\"\r\n size={10}\r\n color=\"info\"\r\n marginRight={8}\r\n />\r\n <Badge isInteractive textTransform=\"lowercase\" color=\"blue\">\r\n waiting connection\r\n </Badge>\r\n </>\r\n );\r\n } else if (props.status === ConnStatus.ConnectionLost) {\r\n return (\r\n <>\r\n <DisableIcon\r\n verticalAlign=\"baseline\"\r\n size={10}\r\n color=\"#FAE2E2\"\r\n marginRight={8}\r\n />\r\n <Badge isInteractive color=\"red\">\r\n connection lost\r\n </Badge>\r\n </>\r\n );\r\n } else {\r\n return (\r\n <>\r\n <FullCircleIcon\r\n verticalAlign=\"baseline\"\r\n size={10}\r\n color=\"success\"\r\n marginRight={8}\r\n />\r\n <Badge isInteractive textTransform=\"lowercase\" color=\"green\">\r\n {props.host}\r\n </Badge>\r\n </>\r\n );\r\n }\r\n};\r\n\r\nconst Console = (props: RouteComponentProps) => {\r\n const [isSideSheetShown, setSideSheetShwon] = useState<boolean>(false);\r\n const terminalRef = useRef<XTerm>(null);\r\n const { t } = useTranslation(['translation', 'console']);\r\n const [fitAddon] = useState<FitAddon>(new FitAddon());\r\n const [webLinksAddon] = useState<WebLinksAddon>(new WebLinksAddon());\r\n const [fullscreen, setFullscreen] = useState<boolean>(false);\r\n const [connecting, setConnecting] = useState<ConnStatus>(\r\n ConnStatus.Connecting,\r\n );\r\n const [nodeConfig, setNodeConfig] = useState<NodeConfig>({\r\n host: 'waiting connection',\r\n username: 'Loading',\r\n });\r\n const [showCornerDialog, setShowCornerDialog] = useState<boolean>(false);\r\n\r\n let ws: WebSocket | null = null;\r\n\r\n useEffect(() => {\r\n const lhost = window.localStorage.getItem('user.host');\r\n const luname = window.localStorage.getItem('user.username');\r\n if (lhost === null) {\r\n return;\r\n }\r\n if (luname === null) {\r\n return;\r\n }\r\n setNodeConfig({ host: lhost, username: luname });\r\n }, []);\r\n\r\n useEffect(() => {\r\n // Once the terminal is loaded write a new line to it.\r\n const term = terminalRef.current!.terminal;\r\n fitAddon.fit();\r\n term.writeln('Welcome to SSH web-console!');\r\n\r\n const _t = sessionStorage.getItem(Config.jwt.tokenName);\r\n if (_t === null) {\r\n toaster.danger(t('console:web_socket_expire'));\r\n props.history.push('/signin');\r\n return;\r\n }\r\n\r\n ws = new WebSocket(\r\n Util.loadWebSocketUrl(\r\n apiRouters.router.ws_ssh,\r\n stringFormat.format(\r\n apiRouters.params.ws_ssh,\r\n term.cols + '',\r\n term.rows + '',\r\n _t,\r\n ),\r\n ),\r\n );\r\n ws.binaryType = 'arraybuffer';\r\n ws.onopen = () => {\r\n setConnecting(ConnStatus.ConnectionAlive);\r\n };\r\n\r\n ws.onclose = (ev) => {\r\n term.setOption('cursorBlink', false);\r\n sessionStorage.removeItem(Config.jwt.tokenName);\r\n setConnecting(ConnStatus.ConnectionLost);\r\n setShowCornerDialog(true);\r\n\r\n send(ev);\r\n };\r\n\r\n const send = (e: CloseEvent) => {\r\n e.preventDefault();\r\n\r\n if (window && window.parent) {\r\n window.parent.postMessage(\r\n {\r\n message: 'close',\r\n },\r\n '*',\r\n );\r\n }\r\n };\r\n\r\n sshWebSocket.bindTerminal(term, ws!, true, -1);\r\n terminalResize.bindTerminalResize(term, ws!);\r\n return () => {\r\n if (ws !== null) {\r\n ws.close();\r\n }\r\n };\r\n }, []);\r\n\r\n useEffect(() => {\r\n fitAddon.fit();\r\n }, [fullscreen]);\r\n\r\n const onWindowResize = () => {\r\n fitAddon.fit();\r\n };\r\n const closeWindowListener = (ev: BeforeUnloadEvent) => {\r\n ev.preventDefault();\r\n ev.returnValue = t('console:make_sure_to_leave');\r\n };\r\n\r\n useEffect(() => {\r\n window.addEventListener('resize', onWindowResize);\r\n window.addEventListener('beforeunload', closeWindowListener);\r\n return () => {\r\n window.removeEventListener('resize', onWindowResize);\r\n window.removeEventListener('beforeunload', closeWindowListener);\r\n };\r\n }, []);\r\n\r\n return (\r\n <Pane height=\"100vh\" display=\"flex\" flexDirection=\"column\" borderRadius={3}>\r\n <Pane\r\n display=\"flex\"\r\n flexDirection=\"row\"\r\n alignItems=\"center\"\r\n background=\"rgba(27,33,47,0.86)\">\r\n <Heading padding={18} color=\"white\">\r\n {' '}\r\n {t('title')}\r\n </Heading>\r\n <Pane\r\n padding={18}\r\n flex={1}\r\n alignItems=\"center\"\r\n alignContent=\"center\"\r\n textAlign=\"center\">\r\n <ConnectionStatus status={connecting} host={nodeConfig.host} />\r\n </Pane>\r\n <Popover\r\n position={Position.BOTTOM_LEFT}\r\n content={\r\n <Menu>\r\n <Menu.Group>\r\n <Menu.Item>\r\n {'@'} {nodeConfig.username}{' '}\r\n </Menu.Item>\r\n </Menu.Group>\r\n <Menu.Divider />\r\n </Menu>\r\n }>\r\n <Avatar\r\n isSolid\r\n name={nodeConfig.username}\r\n size={36}\r\n marginRight={36}\r\n cursor=\"pointer\"\r\n />\r\n </Popover>\r\n </Pane>\r\n <Pane flex={1} overflowY=\"hidden\">\r\n <XTerm\r\n className={\r\n fullscreen ? 'term-container fullscreen' : 'term-container'\r\n }\r\n options={{\r\n cursorBlink: true,\r\n bellStyle: 'sound',\r\n theme: theme.default_theme,\r\n }}\r\n addons={[fitAddon, webLinksAddon]}\r\n ref={terminalRef}\r\n />\r\n </Pane>\r\n <Pane display=\"flex\" alignItems=\"center\">\r\n <FileTrans\r\n isShown={isSideSheetShown}\r\n node={{ host: nodeConfig.host, username: nodeConfig.username }}\r\n sshStatus={connecting}\r\n hideSideSheeeet={() => {\r\n setSideSheetShwon(false);\r\n }}\r\n />\r\n <Button intent=\"success\" onClick={() => setSideSheetShwon(true)}>\r\n SFTP\r\n </Button>\r\n <Pane flex=\"1\"></Pane>\r\n <Text marginRight=\"0.4rem\">active time: 0:00:00</Text>\r\n </Pane>\r\n <CornerDialog\r\n title={\r\n <Text size={500} color=\"danger\" alignItems=\"center\" display=\"flex\">\r\n <ErrorIcon marginRight=\"0.2rem\" />{' '}\r\n {t('console:ssh_disconn_dialog_title')}\r\n </Text>\r\n }\r\n isShown={showCornerDialog}\r\n hasClose={false}\r\n cancelLabel={t('console:ssh_disconn_dialog_cancel_btn')}\r\n confirmLabel={t('console:ssh_disconn_dialog_confirm_btn')}\r\n onConfirm={() => {\r\n props.history.push('/signin');\r\n }}\r\n containerProps={{ zIndex: 20 }}\r\n onCloseComplete={() => setShowCornerDialog(false)}>\r\n {t('console:ssh_disconn_dialog_text')}\r\n </CornerDialog>\r\n </Pane>\r\n );\r\n};\r\n\r\nexport default Console;\r\n","C:\\ProgramasGO\\web-console\\web\\src\\components\\Home.tsx",["200"],"import React from 'react';\r\nimport { NavLink, Route, Switch } from 'react-router-dom';\r\nimport { Button, Pane, Heading } from 'evergreen-ui';\r\nimport { useTranslation } from 'react-i18next';\r\n\r\nimport Header from './layout/Header';\r\nimport Signin from './Signin';\r\n\r\nimport './home.less';\r\nimport headerLogo from '../assets/ssh.png';\r\n\r\nconst MainPage = () => {\r\n const { t } = useTranslation(['home']);\r\n return (\r\n <>\r\n <Pane\r\n alignItems=\"center\"\r\n justifyContent=\"center\"\r\n display=\"flex\"\r\n flexDirection=\"column\">\r\n <div\r\n style={{\r\n minHeight: '360px',\r\n marginTop: '10rem',\r\n textAlign: 'center',\r\n }}>\r\n <img src={headerLogo} className=\"App-logo\" alt=\"logo\" />\r\n <Heading marginBottom=\"0.6rem\" marginTop=\"0.6rem\" size={700}>\r\n {t('home:welcome')}\r\n </Heading>\r\n <div>\r\n <NavLink to=\"/signin\" className=\"focus-ring-link\">\r\n <Button appearance=\"primary\"> {t('home:goto_signin')} </Button>\r\n </NavLink>\r\n </div>\r\n </div>\r\n </Pane>\r\n </>\r\n );\r\n};\r\n\r\nconst Home = () => {\r\n return (\r\n <div className=\"home-container\">\r\n <header className=\"home-content-header\">\r\n <Header />\r\n </header>\r\n <main className=\"home-content-main main-content-container\">\r\n <Switch>\r\n <Route exact path={`/`} component={Signin} />\r\n <Route path={`/signin`} component={Signin} />\r\n </Switch>\r\n </main>\r\n </div>\r\n );\r\n};\r\n\r\nexport default Home;\r\n","C:\\ProgramasGO\\web-console\\web\\src\\config\\api_routers.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\term_theme.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\terminal-resize.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\utils.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\sshwebsocket.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\libs\\string_format.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\FileTrans.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\term\\XTerm.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\layout\\Header.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\files_types.ts",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\SftpUpload.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\PathNav.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\GridFileItem.tsx",[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\files\\DownloadingFile.tsx",[],[],"C:\\ProgramasGO\\web-console\\web\\src\\components\\Signin.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\index.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\serviceWorkerRegistration.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\reportWebVitals.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\config\\config.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\locales\\i18n.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\App.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\locales\\locales.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\Console.tsx",["201"],"C:\\wamp64\\www\\web-console\\web\\src\\components\\Home.tsx",["202"],"C:\\wamp64\\www\\web-console\\web\\src\\config\\api_routers.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\term\\term_theme.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\libs\\sshwebsocket.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\libs\\terminal-resize.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\libs\\utils.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\libs\\string_format.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\FileTrans.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\Signin.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\term\\XTerm.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\layout\\Header.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\files\\files_types.ts",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\PathNav.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\SftpUpload.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\files\\GridFileItem.tsx",[],"C:\\wamp64\\www\\web-console\\web\\src\\components\\files\\DownloadingFile.tsx",[],{"ruleId":"203","severity":1,"message":"204","line":95,"column":22,"nodeType":"205","messageId":"206","endLine":95,"endColumn":35},{"ruleId":"203","severity":1,"message":"207","line":12,"column":7,"nodeType":"205","messageId":"206","endLine":12,"endColumn":15},{"ruleId":"203","severity":1,"message":"204","line":95,"column":22,"nodeType":"205","messageId":"206","endLine":95,"endColumn":35},{"ruleId":"203","severity":1,"message":"207","line":12,"column":7,"nodeType":"205","messageId":"206","endLine":12,"endColumn":15},"@typescript-eslint/no-unused-vars","'setFullscreen' is assigned a value but never used.","Identifier","unusedVar","'MainPage' is assigned a value but never used."]
\ No newline at end of file
const { override, addLessLoader } = require('customize-cra');
// Función que ajusta PostCSS Loader DESPUÉS de que addLessLoader lo configura
const fixPostCSSLoaderAfterLess = (config) => {
// Función recursiva para encontrar y ajustar PostCSS Loader en toda la configuración
const fixPostCSSInRules = (rules) => {
if (!rules || !Array.isArray(rules)) return;
rules.forEach((rule) => {
if (rule.oneOf) {
fixPostCSSInRules(rule.oneOf);
}
if (rule.use) {
const processUse = (use) => {
if (Array.isArray(use)) {
use.forEach((item) => {
if (typeof item === 'object' && item !== null && item.loader) {
if (item.loader.includes('postcss-loader') && item.options) {
// Si tiene plugins directamente (API antigua), moverlos a postcssOptions
if (item.options.plugins && !item.options.postcssOptions) {
item.options = {
postcssOptions: {
plugins: item.options.plugins
}
};
}
}
}
});
} else if (typeof use === 'object' && use !== null && use.loader) {
if (use.loader.includes('postcss-loader') && use.options) {
if (use.options.plugins && !use.options.postcssOptions) {
use.options = {
postcssOptions: {
plugins: use.options.plugins
}
};
}
}
}
};
processUse(rule.use);
}
});
};
if (config.module && config.module.rules) {
fixPostCSSInRules(config.module.rules);
}
return config;
};
module.exports = override(
addLessLoader({
lessOptions: {
javascriptEnabled: true,
}
})
}),
fixPostCSSLoaderAfterLess // Aplicar el fix DESPUÉS de addLessLoader
)
......@@ -11,23 +11,21 @@
"dependencies": {
"@rottitime/react-hook-message-event": "^1.0.8",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^16.9.53",
"@types/react-dom": "^16.9.8",
"@types/node": "^18.17.0",
"axios": "^0.21.1",
"evergreen-ui": "^6.4.0",
"file-saver": "^2.0.5",
"i18next": "^19.8.4",
"js-base64": "2.5.1",
"js-base64": "^3.0.0",
"react-dropzone": "^11.2.4",
"react-i18next": "^11.7.4",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1",
"react-scripts": "^5.0.1",
"typescript": "^4.0.3",
"web-vitals": "^0.2.4",
"web-vitals": "^2.1.4",
"workbox-background-sync": "^5.1.3",
"workbox-broadcast-update": "^5.1.3",
"workbox-cacheable-response": "^5.1.3",
......@@ -46,7 +44,7 @@
},
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject",
"format": "prettier --config .prettierrc --write 'src/*'"
......@@ -81,11 +79,13 @@
"@babel/core": "^7.13.0",
"@types/file-saver": "^2.0.1",
"@types/js-base64": "^3.0.0",
"@types/react-router-dom": "^5.1.6",
"@typescript-eslint/eslint-plugin": "^4.6.1",
"@typescript-eslint/parser": "^4.6.1",
"@types/react-router-dom": "^5.3.3",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"babel-plugin-import": "^1.13.1",
"cross-env": "^7.0.3",
"customize-cra": "^1.0.0",
"react-app-rewired": "^2.2.1",
"eslint": "^7.32.0",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-prettier": "^3.1.4",
......@@ -95,8 +95,9 @@
"less-loader": "^7.1.0",
"lint-staged": "^10.5.1",
"prettier": "^2.2.1",
"react": "^17.0.2",
"react-app-rewired": "^2.1.6",
"react-dom": "^17.0.2"
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0"
}
}
......@@ -4,12 +4,18 @@ import Console from './components/Console';
import Home from './components/Home';
function App() {
// Type assertions needed for React 18 compatibility with react-router-dom v5 types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const SwitchComponent = Switch as any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const RouteComponent = Route as any;
return (
<div className="App">
<Switch>
<Route path="/console" exact component={Console} />
<Route path="/" component={Home} />
</Switch>
<SwitchComponent>
<RouteComponent path="/console" exact component={Console} />
<RouteComponent path="/" component={Home} />
</SwitchComponent>
</div>
);
}
......
......@@ -92,7 +92,7 @@ const Console = (props: RouteComponentProps) => {
const { t } = useTranslation(['translation', 'console']);
const [fitAddon] = useState<FitAddon>(new FitAddon());
const [webLinksAddon] = useState<WebLinksAddon>(new WebLinksAddon());
const [fullscreen, setFullscreen] = useState<boolean>(false);
const [fullscreen] = useState<boolean>(false);
const [connecting, setConnecting] = useState<ConnStatus>(
ConnStatus.Connecting,
);
......@@ -206,7 +206,7 @@ const Console = (props: RouteComponentProps) => {
background="rgba(27,33,47,0.86)">
<Heading padding={18} color="white">
{' '}
{t('title')}
{t('title') as string}
</Heading>
<Pane
padding={18}
......
import React from 'react';
import { NavLink, Route, Switch } from 'react-router-dom';
import { Button, Pane, Heading } from 'evergreen-ui';
import { useTranslation } from 'react-i18next';
import { Route, Switch } from 'react-router-dom';
import Header from './layout/Header';
import Signin from './Signin';
import './home.less';
import headerLogo from '../assets/ssh.png';
const MainPage = () => {
const { t } = useTranslation(['home']);
return (
<>
<Pane
alignItems="center"
justifyContent="center"
display="flex"
flexDirection="column">
<div
style={{
minHeight: '360px',
marginTop: '10rem',
textAlign: 'center',
}}>
<img src={headerLogo} className="App-logo" alt="logo" />
<Heading marginBottom="0.6rem" marginTop="0.6rem" size={700}>
{t('home:welcome')}
</Heading>
<div>
<NavLink to="/signin" className="focus-ring-link">
<Button appearance="primary"> {t('home:goto_signin')} </Button>
</NavLink>
</div>
</div>
</Pane>
</>
);
};
const Home = () => {
// Type assertions needed for React 18 compatibility with react-router-dom v5 types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const SwitchComponent = Switch as any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const RouteComponent = Route as any;
return (
<div className="home-container">
<header className="home-content-header">
<Header />
</header>
<main className="home-content-main main-content-container">
<Switch>
<Route exact path={`/`} component={Signin} />
<Route path={`/signin`} component={Signin} />
</Switch>
<SwitchComponent>
<RouteComponent exact path={`/`} component={Signin} />
<RouteComponent path={`/signin`} component={Signin} />
</SwitchComponent>
</main>
</div>
);
......
......@@ -9,28 +9,139 @@ import apiRouters from '../config/api_routers';
const Signin = (props: RouteComponentProps) => {
React.useEffect(() => {
window.addEventListener('message', (event) => {
const baseUrl = process.env.REACT_APP_CLUSTER_URL as string;
console.log(event.origin);
console.log(process.env.REACT_APP_CLUSTER_URL);
console.log('-----');
console.log(!event.origin.includes(baseUrl));
console.log('-----');
console.log(event.data);
console.log('-----');
if (!event.origin.includes(process.env.REACT_APP_CLUSTER_URL!)) return;
doSignin(event.data);
});
const handleMessage = (event: MessageEvent) => {
console.log('Signin.tsx - Message received:', event);
console.log('Origin:', event.origin);
console.log('Data:', event.data);
// Validar que el mensaje tenga los datos necesarios
if (!event.data || typeof event.data !== 'object') {
console.log('Signin.tsx - Invalid message format');
return;
}
// Validar origen: REACT_APP_CLUSTER_URL debe estar contenido en el origen recibido
const clusterUrl = process.env.REACT_APP_CLUSTER_URL;
if (!clusterUrl) {
console.log(
'Signin.tsx - REACT_APP_CLUSTER_URL not configured, rejecting message',
);
return;
}
// Normalizar origen: quitar protocolo y puerto para comparación flexible
const normalizeOrigin = (url: string) => {
try {
// Si ya es una URL completa, extraer el hostname
if (url.includes('://')) {
const urlObj = new URL(url);
return urlObj.hostname.toLowerCase();
}
// Si es solo hostname, devolverlo en lowercase y limpiar
return url
.toLowerCase()
.replace(/^https?:\/\//, '')
.replace(/:\d+$/, '')
.split('/')[0]
.trim();
} catch {
// Si falla el parsing, intentar limpiar manualmente
return url
.toLowerCase()
.replace(/^https?:\/\//, '')
.replace(/:\d+$/, '')
.split('/')[0]
.trim();
}
};
const originHostname = normalizeOrigin(event.origin);
const clusterHostname = normalizeOrigin(clusterUrl);
console.log('Signin.tsx - Origin validation:', {
originalOrigin: event.origin,
normalizedOrigin: originHostname,
originalClusterUrl: clusterUrl,
normalizedClusterUrl: clusterHostname,
});
if (originHostname !== clusterHostname) {
console.log(
'Signin.tsx - Origin not allowed:',
event.origin,
'(normalized:',
originHostname,
')',
'Expected:',
clusterUrl,
'(normalized:',
clusterHostname,
')',
);
return;
}
console.log(
'Signin.tsx - Origin allowed:',
event.origin,
'Matches:',
clusterUrl,
);
// Verificar que el mensaje tenga los campos necesarios
if (event.data.host && event.data.username && event.data.password) {
console.log('Signin.tsx - Valid message received, processing...');
doSignin(event.data);
} else {
console.log('Signin.tsx - Message missing required fields');
}
};
window.addEventListener('message', handleMessage);
// Cleanup
return () => {
window.removeEventListener('message', handleMessage);
};
}, []);
const { t } = useTranslation(['signin']);
const doSignin = (data: Record<string, string>) => {
console.log('Signin.tsx - Received data:', data);
// Normalizar datos recibidos (lowercase, trim)
const normalizedData = {
host: String(data.host || '')
.toLowerCase()
.trim(),
port: String(data.port || '22').trim(),
username: String(data.username || '').trim(),
passwd: String(data.password || '').trim(),
};
console.log('Signin.tsx - Normalized data:', {
...normalizedData,
passwd: '***',
});
// Validar que todos los campos requeridos estén presentes
if (
!normalizedData.host ||
!normalizedData.username ||
!normalizedData.passwd
) {
console.error('Signin.tsx - Missing required fields:', normalizedData);
toaster.danger(t('signin:form_has_error'));
return;
}
Utils.axiosInstance
.post(Utils.loadUrl(apiRouters.router.sign_in, null), {
host: data.host,
port: data.port,
username: data.username,
passwd: data.password,
host: normalizedData.host,
port: normalizedData.port,
username: normalizedData.username,
passwd: normalizedData.passwd,
})
.then((response) => {
console.log(response);
......@@ -76,8 +187,8 @@ const Signin = (props: RouteComponentProps) => {
props.history.push('/');
} else {
toaster.success(t('signin:signin_success'));
localStorage.setItem('user.host', data.host);
localStorage.setItem('user.username', data.username);
localStorage.setItem('user.host', normalizedData.host);
localStorage.setItem('user.username', normalizedData.username);
sessionStorage.setItem(
Config.jwt.tokenName,
response.data.addition,
......@@ -87,7 +198,8 @@ const Signin = (props: RouteComponentProps) => {
}
}
} catch (e) {
console.log(e.message);
const errorMessage = e instanceof Error ? e.message : String(e);
console.log(errorMessage);
toaster.danger(t('signin:form_error_ssh_login'));
if (window && window.parent) {
console.log('Send Message Error 1');
......@@ -101,9 +213,10 @@ const Signin = (props: RouteComponentProps) => {
props.history.push('/');
}
})
.catch((e: Error) => {
console.log(e.message);
toaster.danger(t('signin:form_error_ssh_login') + ': ' + e.message);
.catch((e: unknown) => {
const errorMessage = e instanceof Error ? e.message : String(e);
console.log(errorMessage);
toaster.danger(t('signin:form_error_ssh_login') + ': ' + errorMessage);
if (window && window.parent) {
console.log('Send Message Error 2');
window.parent.postMessage(
......
......@@ -17,7 +17,7 @@ const Header = () => {
<Pane flex={1} alignItems="center" display="flex">
<Heading size={600}>
<Link to="/" className="focus-ring-link">
{t('title')}
{t('title') as string}
</Link>
</Heading>
</Pane>
......
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import './index.less';
import App from './App';
......@@ -9,13 +9,20 @@ import reportWebVitals from './reportWebVitals';
import config from './config/config';
import './locales/i18n';
ReactDOM.render(
const container = document.getElementById('root');
if (!container) {
throw new Error('Failed to find the root element');
}
const root = createRoot(container);
// Type assertion needed for React 18 compatibility with react-router-dom v5 types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const RouterComponent = BrowserRouter as any;
root.render(
<React.StrictMode>
<Router basename={config.router.basepath}>
<RouterComponent basename={config.router.basepath}>
<App />
</Router>
</RouterComponent>
</React.StrictMode>,
document.getElementById('root'),
);
// If you want your app to work offline and load faster, you can change
......
......@@ -8,12 +8,19 @@ interface TermSize {
const resize = {
bindTerminalResize: function (term: Terminal, websocket: WebSocket) {
const onTermResize = (size: TermSize) => {
websocket.send(
JSON.stringify({
type: 'resize',
data: { rows: size.rows, cols: size.cols },
}),
);
// Verificar que el WebSocket esté conectado antes de enviar datos
if (websocket.readyState === WebSocket.OPEN) {
try {
websocket.send(
JSON.stringify({
type: 'resize',
data: { rows: size.rows, cols: size.cols },
}),
);
} catch (error) {
console.error('Error sending resize message:', error);
}
}
};
// register resize event.
const resizeListener = term.onResize(onTermResize);
......
......@@ -50,14 +50,15 @@ registerRoute(
// Return true to signal that we want to use the handler.
return true;
},
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html'),
);
// An example runtime caching route for requests that aren't handled by the
// precache, in this case same-origin .png requests like those from in public/
registerRoute(
// Add in any other file extensions or routing criteria as needed.
({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'),
({ url }) =>
url.origin === self.location.origin && url.pathname.endsWith('.png'),
// Customize this strategy as needed, e.g., by changing to CacheFirst.
new StaleWhileRevalidate({
cacheName: 'images',
......@@ -66,7 +67,7 @@ registerRoute(
// least-recently used images are removed.
new ExpirationPlugin({ maxEntries: 50 }),
],
})
}),
);
// This allows the web app to trigger skipWaiting via
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment