From 5e9226f89351d6347b6788c00f2a0e48cf071b5f Mon Sep 17 00:00:00 2001 From: Johns Gresham Date: Tue, 23 Apr 2024 10:24:00 -0700 Subject: [PATCH 01/11] Feat: erigon client ethereum and minor fixes (#537) (#550) * feat: add erigon execution client ethereum * fix: node requirements and node http cors regression from electron vite upgrade * fix(cid): add break-system-packages to mac gha pip install * fix(cid): turn off checkForUpdates automatically in test env --- .github/workflows/e2e-test-mac.yml | 2 +- .github/workflows/package.yml | 2 +- .github/workflows/prod-publish.yml | 2 +- .github/workflows/staging-publish.yml | 2 +- .husky/pre-commit | 1 + biome.jsonc | 66 ++-- .../NodeSpecs/erigon/erigon-v1.0.0.json | 297 +++++++++++++++++- .../NodeSpecs/ethereum/ethereum-v1.0.0.json | 2 +- src/common/NodeSpecs/geth/geth-v1.0.0.json | 2 +- .../NodeSpecs/nimbus/nimbus-v1.0.0.json | 7 +- src/common/node.ts | 8 + src/main/corsMiddleware.ts | 3 +- src/main/files.ts | 4 +- src/main/main.ts | 4 +- src/main/nodeLibraryManager.ts | 2 + src/main/podman/install/install.ts | 2 +- src/main/podman/podman.ts | 10 +- .../AddNodeStepper/mergeNodeRequirements.ts | 1 - .../assets/images/nodeBackgrounds/index.tsx | 2 +- .../assets/images/nodeIcons/index.tsx | 2 +- 20 files changed, 369 insertions(+), 52 deletions(-) diff --git a/.github/workflows/e2e-test-mac.yml b/.github/workflows/e2e-test-mac.yml index 0356fcb40..341d9f2eb 100644 --- a/.github/workflows/e2e-test-mac.yml +++ b/.github/workflows/e2e-test-mac.yml @@ -18,7 +18,7 @@ jobs: steps: # https://github.com/electron/forge/issues/2807 - if: ${{ matrix.os == 'macos-latest' }} - run: python3 -m pip install setuptools + run: python3 -m pip install setuptools --break-system-packages - uses: actions/checkout@v4 - name: ๐Ÿ’š Use Node.js ${{ matrix.node-version }} diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index eef14ba0b..248ba20e8 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -17,7 +17,7 @@ jobs: steps: # https://github.com/electron/forge/issues/2807 - if: ${{ matrix.os == 'macos-latest' }} - run: python3 -m pip install setuptools + run: python3 -m pip install setuptools --break-system-packages - name: Check out Git repository uses: actions/checkout@v4 diff --git a/.github/workflows/prod-publish.yml b/.github/workflows/prod-publish.yml index e0536511c..fb6e01740 100644 --- a/.github/workflows/prod-publish.yml +++ b/.github/workflows/prod-publish.yml @@ -25,7 +25,7 @@ jobs: # https://github.com/electron/forge/issues/2807 - if: ${{ matrix.os == 'macos-latest' }} - run: python3 -m pip install setuptools + run: python3 -m pip install setuptools --break-system-packages - name: Used variables run: | diff --git a/.github/workflows/staging-publish.yml b/.github/workflows/staging-publish.yml index 4928cb0d0..bb7000f4e 100644 --- a/.github/workflows/staging-publish.yml +++ b/.github/workflows/staging-publish.yml @@ -20,7 +20,7 @@ jobs: steps: # https://github.com/electron/forge/issues/2807 - if: ${{ matrix.os == 'macos-latest' }} - run: python3 -m pip install setuptools + run: python3 -m pip install setuptools --break-system-packages - if: matrix.os == 'ubuntu-latest' name: Install packages for building diff --git a/.husky/pre-commit b/.husky/pre-commit index 934dcc22c..c86d986cd 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,6 @@ #!/usr/bin/env sh +npm run safeFix npm run lint # npm exec tsc npm run package diff --git a/biome.jsonc b/biome.jsonc index 165d885be..f89f00e76 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -1,33 +1,37 @@ { - "$schema": "https://biomejs.dev/schemas/1.6.4/schema.json", - "organizeImports": { - "enabled": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true, - "suspicious": { - "noImplicitAnyLet": "off", - "noExplicitAny": "off" - }, - "complexity": { - "noForEach": "off" - }, - "correctness": { - "useExhaustiveDependencies": "off" - } - } - }, - "formatter": { - "indentStyle": "space" - }, - "javascript": { - "formatter": { - "quoteStyle": "single" - } - }, - "files": { - "ignore": ["src/renderer/ethers.js", "src/main/util/*.js"] - } + "$schema": "https://biomejs.dev/schemas/1.6.4/schema.json", + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noImplicitAnyLet": "off", + "noExplicitAny": "off" + }, + "complexity": { + "noForEach": "off" + }, + "correctness": { + "useExhaustiveDependencies": "off" + } + } + }, + "formatter": { + "indentStyle": "space" + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + }, + "files": { + "ignore": [ + "src/renderer/ethers.js", + "src/main/util/*.js", + "*genesis-l2.json" + ] + } } diff --git a/src/common/NodeSpecs/erigon/erigon-v1.0.0.json b/src/common/NodeSpecs/erigon/erigon-v1.0.0.json index e1fec8585..21c3b473f 100644 --- a/src/common/NodeSpecs/erigon/erigon-v1.0.0.json +++ b/src/common/NodeSpecs/erigon/erigon-v1.0.0.json @@ -5,9 +5,302 @@ "execution": { "executionTypes": ["docker"], "defaultExecutionType": "docker", - "imageName": "docker.io/thorax/erigon:latest" + "imageName": "docker.io/thorax/erigon", + "defaultImageTag": "2.59.3", + "input": { + "defaultConfig": { + "http": "Enabled", + "httpCorsDomains": "http://localhost", + "webSockets": "Enabled", + "httpVirtualHosts": "localhost,host.containers.internal", + "authVirtualHosts": "localhost,host.containers.internal", + "httpAddress": "0.0.0.0", + "httpPort": "8545", + "syncMode": "full", + "network": "Mainnet", + "httpApis": [ + "eth", + "net", + "web3", + "engine", + "txpool", + "debug", + "trace", + "erigon" + ] + }, + "docker": { + "containerVolumePath": "/root/.ethereum", + "raw": "", + "forcedRawNodeInput": "--authrpc.addr 0.0.0.0 --authrpc.jwtsecret /root/.ethereum/jwtsecret" + } + } + }, + "systemRequirements": { + "documentationUrl": "https://erigon.gitbook.io/erigon/basic-usage/getting-started#hardware-requirements", + "cpu": { + "cores": 4 + }, + "memory": { + "minSizeGBs": 16 + }, + "storage": { + "minSizeGBs": 1600, + "ssdRequired": true + }, + "internet": { + "minDownloadSpeedMbps": 25, + "minUploadSpeedMbps": 10 + }, + "docker": { + "required": true + } + }, + "configTranslation": { + "network": { + "displayName": "Network", + "cliConfigPrefix": "--chain ", + "defaultValue": "Mainnet", + "hideFromUserAfterStart": true, + "uiControl": { + "type": "select/single", + "controlTranslations": [ + { + "value": "Mainnet", + "config": "mainnet" + }, + { + "value": "Holesky", + "config": "holesky" + }, + { + "value": "Sepolia", + "config": "sepolia" + } + ] + }, + "documentation": "https://docs.nethermind.io/fundamentals/configuration#basic-options" + }, + "http": { + "displayName": "RPC HTTP connections", + "uiControl": { + "type": "select/single", + "controlTranslations": [ + { + "value": "Enabled", + "config": "--http" + }, + { + "value": "Disabled" + } + ] + }, + "defaultValue": "Disabled", + "infoDescription": "NiceNode requires http connections", + "documentation": "https://geth.ethereum.org/docs/rpc/server" + }, + "httpPort": { + "displayName": "HTTP-RPC server listening port", + "cliConfigPrefix": "--http.port ", + "defaultValue": "8545", + "uiControl": { + "type": "text" + }, + "documentation": "https://geth.ethereum.org/docs/rpc/server#http-server" + }, + "httpApis": { + "displayName": "Enabled HTTP APIs", + "cliConfigPrefix": "--http.api ", + "defaultValue": [ + "eth", + "net", + "web3", + "engine", + "txpool", + "debug", + "trace", + "erigon" + ], + "valuesJoinStr": ",", + "uiControl": { + "type": "select/multiple", + "controlTranslations": [ + { + "value": "eth", + "config": "eth" + }, + { + "value": "net", + "config": "net" + }, + { + "value": "web3", + "config": "web3" + }, + { + "value": "engine", + "config": "engine" + }, + { + "value": "txpool", + "config": "txpool" + }, + { + "value": "debug", + "config": "debug" + }, + + { + "value": "trace", + "config": "trace" + }, + { + "value": "erigon", + "config": "erigon" + }, + { + "value": "admin", + "config": "admin" + } + ] + } + }, + "httpAddress": { + "displayName": "HTTP-RPC server listening interface", + "cliConfigPrefix": "--http.addr ", + "defaultValue": "0.0.0.0", + "uiControl": { + "type": "text" + }, + "documentation": "https://geth.ethereum.org/docs/rpc/server#http-server" + }, + "httpCorsDomains": { + "displayName": "HTTP-RPC CORS domains", + "cliConfigPrefix": "--http.corsdomain ", + "uiControl": { + "type": "text" + }, + "infoDescription": "Change where the node accepts http connections (use comma separated urls)" + }, + "httpVirtualHosts": { + "displayName": "Virtual hostnames list", + "cliConfigPrefix": "--http.vhosts ", + "uiControl": { + "type": "text" + }, + "infoDescription": "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. Default value (localhost)", + "defaultValue": "localhost,host.containers.internal" + }, + "webSockets": { + "displayName": "WebSocket JSON-RPC connections", + "uiControl": { + "type": "select/single", + "controlTranslations": [ + { + "value": "Enabled", + "config": "--ws" + }, + { + "value": "Disabled" + } + ] + }, + "defaultValue": "Disabled", + "infoDescription": "Enables or disables the WebSocket JSON-RPC service. Beacon nodes may require websockets. The default is false.", + "documentation": "https://geth.ethereum.org/docs/rpc/server#websocket-server" + }, + "webSocketsPort": { + "displayName": "WebSockets JSON-RPC port", + "cliConfigPrefix": "--ws.port ", + "defaultValue": "8546", + "uiControl": { + "type": "text" + }, + "infoDescription": "The port (TCP) on which WebSocket JSON-RPC listens. The default is 8546. You must expose ports appropriately.", + "documentation": "https://geth.ethereum.org/docs/rpc/server#websocket-server" + }, + "webSocketAllowedOrigins": { + "displayName": "WebSocket-RPC allowed origins", + "defaultValue": "http://localhost", + "cliConfigPrefix": "--ws.origins ", + "uiControl": { + "type": "text" + }, + "infoDescription": "Change where the node accepts web socket connections (use comma separated urls) or \"*\" for all" + }, + "p2pPorts": { + "displayName": "P2P port (UDP and TCP)", + "cliConfigPrefix": "--port ", + "uiControl": { + "type": "text" + }, + "infoDescription": "Example value: 30303", + "defaultValue": "30303" + }, + "enginePort": { + "displayName": "Engine JSON-RPC listening port", + "cliConfigPrefix": "--authrpc.port ", + "defaultValue": "8551", + "uiControl": { + "type": "text" + }, + "infoDescription": "The listening port for the Engine API calls for JSON-RPC over HTTP and WebSocket." + }, + "torrentPort": { + "displayName": "BitTorrent protocol port", + "cliConfigPrefix": "--torrent.port ", + "defaultValue": "42069", + "uiControl": { + "type": "text" + }, + "infoDescription": "The listening and serving port for BitTorrent." + }, + "authVirtualHosts": { + "displayName": "Engine RPC virtual hostnames list", + "cliConfigPrefix": "--authrpc.vhosts ", + "uiControl": { + "type": "text" + }, + "infoDescription": "Comma separated list of virtual hostnames from which to accept authentication requests for engine api's (server enforced). Accepts '*' wildcard. Default value (localhost)", + "defaultValue": "localhost,host.containers.internal" + }, + "syncMode": { + "displayName": "Execution Client Sync Mode", + "category": "Syncronization", + "uiControl": { + "type": "select/single", + "controlTranslations": [ + { + "value": "full", + "config": "--prune=hrtc", + "info": "~800GB / ~2d" + }, + { + "value": "archive", + "config": "", + "info": "~16TB" + } + ] + }, + "addNodeFlow": "required", + "defaultValue": "full", + "hideFromUserAfterStart": true, + "documentation": "https://geth.ethereum.org/docs/faq#how-does-ethereum-syncing-work" + } }, "category": "L1/ExecutionClient", "rpcTranslation": "eth-l1", - "iconUrl": "https://clientdiversity.org/assets/img/execution-clients/erigon-text-logo.png" + "iconUrl": "https://clientdiversity.org/assets/img/execution-clients/erigon-text-logo.png", + "resources": [ + { + "label": "Configuration documentation", + "value": "erigon.gitbook.io", + "link": "https://erigon.gitbook.io/erigon/advanced-usage/options" + }, + { + "label": "Erigon Website", + "value": "erigon.tech", + "link": "https://erigon.tech/" + } + ] } diff --git a/src/common/NodeSpecs/ethereum/ethereum-v1.0.0.json b/src/common/NodeSpecs/ethereum/ethereum-v1.0.0.json index c8bbaedeb..4b797a2ad 100644 --- a/src/common/NodeSpecs/ethereum/ethereum-v1.0.0.json +++ b/src/common/NodeSpecs/ethereum/ethereum-v1.0.0.json @@ -10,7 +10,7 @@ { "serviceId": "executionClient", "name": "Execution Client", - "nodeOptions": ["nethermind", "besu", "geth", "reth"], + "nodeOptions": ["nethermind", "besu", "geth", "reth", "erigon"], "required": true, "requiresCommonJwtSecret": true }, diff --git a/src/common/NodeSpecs/geth/geth-v1.0.0.json b/src/common/NodeSpecs/geth/geth-v1.0.0.json index 887d4c4af..e29cfd614 100644 --- a/src/common/NodeSpecs/geth/geth-v1.0.0.json +++ b/src/common/NodeSpecs/geth/geth-v1.0.0.json @@ -20,7 +20,7 @@ "docker": { "containerVolumePath": "/root/.ethereum", "raw": "", - "forcedRawNodeInput": "--authrpc.addr 0.0.0.0 --authrpc.jwtsecret /root/.ethereum/jwtsecret --ipcdisable" + "forcedRawNodeInput": "--verbosity 4 --datadir /root/.ethereum --authrpc.jwtsecret /root/.ethereum/jwtsecret --ipcdisable" } }, "imageName": "docker.io/ethereum/client-go", diff --git a/src/common/NodeSpecs/nimbus/nimbus-v1.0.0.json b/src/common/NodeSpecs/nimbus/nimbus-v1.0.0.json index 68b4ace63..faebbe704 100644 --- a/src/common/NodeSpecs/nimbus/nimbus-v1.0.0.json +++ b/src/common/NodeSpecs/nimbus/nimbus-v1.0.0.json @@ -12,8 +12,8 @@ "http": "Enabled", "httpPort": "5052", "httpHostAddress": "0.0.0.0", - "httpCorsDomains": "\"http://localhost\"", - "executionEndpoint": "\"http://host.containers.internal:8551\"", + "httpCorsDomains": "http://localhost", + "executionEndpoint": "http://host.containers.internal:8551", "network": "Mainnet" }, "docker": { @@ -128,6 +128,7 @@ "httpCorsDomains": { "displayName": "HTTP-RPC CORS domains", "cliConfigPrefix": "--rest-allow-origin=", + "defaultValue": "http://localhost", "uiControl": { "type": "text" }, @@ -145,7 +146,7 @@ "executionEndpoint": { "displayName": "Local execution Engine RPC-JSON API URL", "cliConfigPrefix": "--web3-url=", - "defaultValue": "\"http://host.containers.internal:8551\"", + "defaultValue": "http://host.containers.internal:8551", "uiControl": { "type": "text" }, diff --git a/src/common/node.ts b/src/common/node.ts index 3f809b76a..a1315354c 100644 --- a/src/common/node.ts +++ b/src/common/node.ts @@ -257,6 +257,14 @@ export const getImageTag = (node: Node): string => { // defaultImageTag is set in node.spec.execution imageTag = defaultImageTag; } + // temp fix: see https://github.com/ledgerwatch/erigon/issues/10023 + if (imageName.includes('erigon')) { + let archPostfix = '-arm64'; + if (process.arch === 'x64') { + archPostfix = '-amd64'; + } + imageTag = imageTag + archPostfix; + } return imageTag; }; export default Node; diff --git a/src/main/corsMiddleware.ts b/src/main/corsMiddleware.ts index b8f2a828c..6fc9d844a 100644 --- a/src/main/corsMiddleware.ts +++ b/src/main/corsMiddleware.ts @@ -25,7 +25,8 @@ export const setCorsForNiceNode = (mainWindow: BrowserWindow) => { // Some api servers use lower-case. // Chrome will combine both headers and throw a CORS error for having 2 values. // So just delete the lower-case value - details.responseHeaders['access-control-allow-origin'] = undefined; + // biome-ignore lint/performance/noDelete: + delete details.responseHeaders['access-control-allow-origin']; callback({ responseHeaders: details.responseHeaders }); }, diff --git a/src/main/files.ts b/src/main/files.ts index 0f245147c..a6f88eb58 100644 --- a/src/main/files.ts +++ b/src/main/files.ts @@ -92,7 +92,7 @@ export const getSystemFreeDiskSpace = async ( const pathToCheck: string = diskSpacePath || app.getPath('userData'); // https://github.com/Alex-D/check-disk-space/issues/30 // @ts-ignore:next-line - const diskSpace = await checkDiskSpace.default(pathToCheck); + const diskSpace = await checkDiskSpace(pathToCheck); console.log('diskSpace: ', diskSpace); const freeInGBs = diskSpace.free * 1e-9; return freeInGBs; @@ -116,7 +116,7 @@ export const getNodesDirPathDetails = export const getSystemDiskSize = async (): Promise => { // https://github.com/Alex-D/check-disk-space/issues/30 // @ts-ignore:next-line - const diskSpace = await checkDiskSpace.default(app.getPath('userData')); + const diskSpace = await checkDiskSpace(app.getPath('userData')); const sizeInGBs = diskSpace.size * 1e-9; return sizeInGBs; }; diff --git a/src/main/main.ts b/src/main/main.ts index ec920cb2d..9aa680678 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -76,6 +76,8 @@ export const getMenuBuilder = () => menuBuilder; const isDevelopment = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; +const isTest = process.env.NODE_ENV === 'test'; + // if (isDevelopment) { // require('electron-debug')(); // } @@ -169,7 +171,7 @@ export const createWindow = async () => { // App auto updates updater.initialize(mainWindow); // disabled in dev env - if (!isDevelopment) { + if (!isDevelopment && !isTest) { updater.checkForUpdates(false); } else { logger.info( diff --git a/src/main/nodeLibraryManager.ts b/src/main/nodeLibraryManager.ts index c06ffd126..b258ccd25 100644 --- a/src/main/nodeLibraryManager.ts +++ b/src/main/nodeLibraryManager.ts @@ -9,6 +9,7 @@ import optimismv1 from '../common/NodeSpecs/optimism/optimism-v1.0.0.json'; // Node Services import besuv1 from '../common/NodeSpecs/besu/besu-v1.0.0.json'; +import erigonv1 from '../common/NodeSpecs/erigon/erigon-v1.0.0.json'; import gethv1 from '../common/NodeSpecs/geth/geth-v1.0.0.json'; import nethermindv1 from '../common/NodeSpecs/nethermind/nethermind-v1.0.0.json'; import rethv1 from '../common/NodeSpecs/reth/reth-v1.0.0.json'; @@ -53,6 +54,7 @@ export const initialize = async () => { const specs = [ besuv1, nethermindv1, + erigonv1, gethv1, rethv1, lodestarv1, diff --git a/src/main/podman/install/install.ts b/src/main/podman/install/install.ts index c67e47e66..ffbe8d05d 100644 --- a/src/main/podman/install/install.ts +++ b/src/main/podman/install/install.ts @@ -5,7 +5,7 @@ import installOnLinux from './installOnLinux'; import installOnMac from './installOnMac'; import installOnWindows from './installOnWindows'; -export const PODMAN_LATEST_VERSION = '5.0.1'; +export const PODMAN_LATEST_VERSION = '5.0.2'; export const PODMAN_MIN_VERSION = '4.6.0'; const installPodman = async (): Promise => { diff --git a/src/main/podman/podman.ts b/src/main/podman/podman.ts index fd7667903..f4bc072d7 100644 --- a/src/main/podman/podman.ts +++ b/src/main/podman/podman.ts @@ -632,7 +632,7 @@ export const createInitCommand = (node: Node): string => { // -d is not used here as this should be short-lived and we want to be blocked // so that we know when to start the node const containerName = getContainerName(node); - const podmanCommand = `run -q --user 0 --name ${containerName} ${finalPodmanInput} ${imageNameWithTag} ${nodeInput}`; + const podmanCommand = `run -q --name ${containerName} ${finalPodmanInput} ${imageNameWithTag} ${nodeInput}`; logger.info(`createInitCommand: podman run command ${podmanCommand}`); return podmanCommand; }; @@ -656,9 +656,15 @@ export const startPodmanNode = async (node: Node): Promise => { node.status = NodeStatus.updating; storeUpdateNode(node); + const imageTag = getImageTag(node); + // if imageTage is empty, use then imageTag is already included in the imageName (backwards compatability) + // We must include the version tag for container registries without 'latest' tag + const imageNameWithTag = + imageTag !== '' ? `${imageName}:${imageTag}` : imageName; + // todo: only set as updating if there is a new image, otherwise updating // will "flash" to the user quickly here - await runCommand(`pull ${imageName}`); + await runCommand(`pull ${imageNameWithTag}`); // Set node as starting here node.status = NodeStatus.starting; diff --git a/src/renderer/Presentational/AddNodeStepper/mergeNodeRequirements.ts b/src/renderer/Presentational/AddNodeStepper/mergeNodeRequirements.ts index 93269c334..f98973058 100644 --- a/src/renderer/Presentational/AddNodeStepper/mergeNodeRequirements.ts +++ b/src/renderer/Presentational/AddNodeStepper/mergeNodeRequirements.ts @@ -13,7 +13,6 @@ export const mergeSystemRequirements = ( const mergedReqs: SystemRequirements = {}; systemRequirementsArray.forEach((systemRequirements) => { - no - restricted - syntax; for (const [nodeReqKey, nodeReqValue] of Object.entries( systemRequirements, )) { diff --git a/src/renderer/assets/images/nodeBackgrounds/index.tsx b/src/renderer/assets/images/nodeBackgrounds/index.tsx index 355ef5bd0..1d94704d4 100644 --- a/src/renderer/assets/images/nodeBackgrounds/index.tsx +++ b/src/renderer/assets/images/nodeBackgrounds/index.tsx @@ -1,6 +1,6 @@ +// Execution import besu from './Besu.png'; import erigon from './Erigon.png'; -// Execution import geth from './Geth.png'; import nethermind from './Nethermind.png'; import reth from './Reth.png'; diff --git a/src/renderer/assets/images/nodeIcons/index.tsx b/src/renderer/assets/images/nodeIcons/index.tsx index 2afcc103f..827e2eb9a 100644 --- a/src/renderer/assets/images/nodeIcons/index.tsx +++ b/src/renderer/assets/images/nodeIcons/index.tsx @@ -2,9 +2,9 @@ import { common } from '../../../Generics/redesign/theme.css'; import ethereum from './Logo-Ethereum.png'; +// Execution import besu from './Logo-Besu.png'; import erigon from './Logo-Erigon.png'; -// Execution import geth from './Logo-Geth.png'; import nethermind from './Logo-Nethermind.png'; import reth from './Logo-Reth.png'; From 4535bc83536fe8d4bd2120e0aab666ab98e2d1ce Mon Sep 17 00:00:00 2001 From: Johns Gresham Date: Tue, 23 Apr 2024 10:46:47 -0700 Subject: [PATCH 02/11] fix(cid): use nodejs v20 of apple sign gha (#551) --- .github/workflows/package.yml | 2 +- .github/workflows/prod-publish.yml | 2 +- .github/workflows/staging-publish.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 248ba20e8..d41554c7a 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -35,7 +35,7 @@ jobs: - if: ${{ matrix.os == 'macos-latest' }} name: Import Certs - uses: apple-actions/import-codesign-certs@v2 + uses: slidoapp/import-codesign-certs@node20 with: p12-file-base64: ${{ secrets.CSC_LINK }} p12-password: ${{ secrets.CSC_KEY_PASSWORD }} diff --git a/.github/workflows/prod-publish.yml b/.github/workflows/prod-publish.yml index fb6e01740..ca947721d 100644 --- a/.github/workflows/prod-publish.yml +++ b/.github/workflows/prod-publish.yml @@ -47,7 +47,7 @@ jobs: - if: ${{ matrix.os == 'macos-latest' }} name: Import Certs - uses: apple-actions/import-codesign-certs@v2 + uses: slidoapp/import-codesign-certs@node20 with: p12-file-base64: ${{ secrets.CSC_LINK }} p12-password: ${{ secrets.CSC_KEY_PASSWORD }} diff --git a/.github/workflows/staging-publish.yml b/.github/workflows/staging-publish.yml index bb7000f4e..5fd9c0489 100644 --- a/.github/workflows/staging-publish.yml +++ b/.github/workflows/staging-publish.yml @@ -48,7 +48,7 @@ jobs: - if: ${{ matrix.os == 'macos-latest' }} name: Import Certs - uses: apple-actions/import-codesign-certs@v2 + uses: slidoapp/import-codesign-certs@node20 with: p12-file-base64: ${{ secrets.CSC_LINK }} p12-password: ${{ secrets.CSC_KEY_PASSWORD }} From d099d01a6995e470e319e1685c743b9028866b7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:49:40 -0700 Subject: [PATCH 03/11] chore(deps-dev): bump @types/node from 20.4.5 to 20.12.7 (#548) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.4.5 to 20.12.7. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Johns Gresham --- package-lock.json | 32 ++++++++------------------------ package.json | 2 +- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c059c803..3cfc76c48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,7 @@ "@testing-library/webdriverio": "^3.2.1", "@types/du": "^1.0.3", "@types/mixpanel-browser": "^2.47.3", - "@types/node": "20.4.5", + "@types/node": "20.12.7", "@types/pidusage": "^2.0.5", "@types/react": "^18.2.74", "@types/react-dom": "^18.2.24", @@ -7192,9 +7192,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.4.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", - "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", @@ -7901,15 +7904,6 @@ "node": "^16.13 || >=18" } }, - "node_modules/@wdio/runner/node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@wdio/spec-reporter": { "version": "8.36.0", "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.36.0.tgz", @@ -11933,15 +11927,6 @@ "global-agent": "^3.0.0" } }, - "node_modules/electron/node_modules/@types/node": { - "version": "20.12.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.5.tgz", - "integrity": "sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/electron/node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -21436,8 +21421,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", diff --git a/package.json b/package.json index 472b614ae..63da763f2 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@testing-library/webdriverio": "^3.2.1", "@types/du": "^1.0.3", "@types/mixpanel-browser": "^2.47.3", - "@types/node": "20.4.5", + "@types/node": "20.12.7", "@types/pidusage": "^2.0.5", "@types/react": "^18.2.74", "@types/react-dom": "^18.2.24", From 6a0a5d41b49205a1821cf6604851cdc22b294337 Mon Sep 17 00:00:00 2001 From: Johns Gresham Date: Tue, 23 Apr 2024 11:23:17 -0700 Subject: [PATCH 04/11] chore: update redux toolkit to v2 and react redux v9 (#552) --- package-lock.json | 91 ++++++++++++++++------------------------------- package.json | 4 +-- 2 files changed, 33 insertions(+), 62 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3cfc76c48..4178a62ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "6.0.0-alpha", "license": "MIT", "dependencies": { - "@reduxjs/toolkit": "^1.9.3", + "@reduxjs/toolkit": "^2.2.3", "@sentry/electron": "^4.10.0", "@vanilla-extract/css": "^1.14.2", "@vscode/sudo-prompt": "^9.3.1", @@ -34,7 +34,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^14.1.0", - "react-redux": "^8.0.5", + "react-redux": "^9.1.1", "react-router-dom": "^6.4.4", "react-select": "^5.8.0", "systeminformation": "^5.21.24", @@ -4194,18 +4194,18 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", - "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz", + "integrity": "sha512-76dll9EnJXg4EVcI5YNxZA/9hSAmZsFqzMmNRHvIlzw2WS/twfcVX3ysYrWGJMClwEmChQFC4yRq74tn6fdzRA==", "dependencies": { - "immer": "^9.0.21", - "redux": "^4.2.1", - "redux-thunk": "^2.4.2", - "reselect": "^4.1.8" + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.0.2" + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "peerDependenciesMeta": { "react": { @@ -7086,15 +7086,6 @@ "@types/unist": "*" } }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "node_modules/@types/http-cache-semantics": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", @@ -7252,7 +7243,7 @@ "version": "18.2.25", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", - "devOptional": true, + "dev": true, "dependencies": { "@types/react": "*" } @@ -14449,9 +14440,9 @@ "dev": true }, "node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz", + "integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -18789,35 +18780,23 @@ "dev": true }, "node_modules/react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.1.tgz", + "integrity": "sha512-5ynfGDzxxsoV73+4czQM56qF43vsmgJsO22rmAvU5tZT2z5Xow/A2uhhxwXuGTxgdReF3zcp7A80gma2onRs1A==", "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", "use-sync-external-store": "^1.0.0" }, "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": ">=0.69", + "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, "react-native": { "optional": true }, @@ -18826,11 +18805,6 @@ } } }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, "node_modules/react-router": { "version": "6.22.3", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", @@ -19298,19 +19272,16 @@ } }, "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", "peerDependencies": { - "redux": "^4" + "redux": "^5.0.0" } }, "node_modules/regenerate": { @@ -19494,9 +19465,9 @@ } }, "node_modules/reselect": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", - "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz", + "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==" }, "node_modules/resolve": { "version": "1.22.8", diff --git a/package.json b/package.json index 63da763f2..9a538dc6f 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "wdio-wait-for": "^3.0.11" }, "dependencies": { - "@reduxjs/toolkit": "^1.9.3", + "@reduxjs/toolkit": "^2.2.3", "@sentry/electron": "^4.10.0", "@vanilla-extract/css": "^1.14.2", "@vscode/sudo-prompt": "^9.3.1", @@ -105,7 +105,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^14.1.0", - "react-redux": "^8.0.5", + "react-redux": "^9.1.1", "react-router-dom": "^6.4.4", "react-select": "^5.8.0", "systeminformation": "^5.21.24", From 298881778ab0fc8a7dc9b8e02310f35c3796319c Mon Sep 17 00:00:00 2001 From: Johns Gresham Date: Thu, 2 May 2024 15:17:55 -0700 Subject: [PATCH 05/11] fix: geth config engine api address (#559) --- src/common/NodeSpecs/geth/geth-v1.0.0.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/NodeSpecs/geth/geth-v1.0.0.json b/src/common/NodeSpecs/geth/geth-v1.0.0.json index e29cfd614..887d4c4af 100644 --- a/src/common/NodeSpecs/geth/geth-v1.0.0.json +++ b/src/common/NodeSpecs/geth/geth-v1.0.0.json @@ -20,7 +20,7 @@ "docker": { "containerVolumePath": "/root/.ethereum", "raw": "", - "forcedRawNodeInput": "--verbosity 4 --datadir /root/.ethereum --authrpc.jwtsecret /root/.ethereum/jwtsecret --ipcdisable" + "forcedRawNodeInput": "--authrpc.addr 0.0.0.0 --authrpc.jwtsecret /root/.ethereum/jwtsecret --ipcdisable" } }, "imageName": "docker.io/ethereum/client-go", From a49819a6da6fd9d5e36a4b1775895fe04f965508 Mon Sep 17 00:00:00 2001 From: Johns Gresham Date: Fri, 3 May 2024 11:12:35 -0700 Subject: [PATCH 06/11] chore: bump 6.0.1-alpha (#560) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9a538dc6f..50cbcf981 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nice-node", - "version": "6.0.0-alpha", + "version": "6.0.1-alpha", "description": "Run a node at home, the easy way.", "homepage": "https://nicenode.xyz", "productName": "NiceNode", From e33a3a15913647628d1e0a1716f5d64201dcf5c2 Mon Sep 17 00:00:00 2001 From: Johns Gresham Date: Thu, 9 May 2024 11:09:36 -0700 Subject: [PATCH 07/11] chore: refactor and test install podman (#563) * chore: podman install ci tests by container matrix * feat: use package manager, not distro for installing podman * add uninstall for distros. ubuntu22 specific install script * feat: fix app package property tests * feat: full add node, start node, stop node flow in e2e tests (off for now) * chore: bump wdio minor versions * chore: add distro and version to debug info * chore: add fedora and other linux distros to e2e test containers * chore: update gha xvfb to use nodejs v20 * chore: bump 6.0.2-alpha * chore: add podman install verison in ci test --- .github/workflows/e2e-test-linux-distros.yml | 99 ++++ .github/workflows/e2e-test-mac.yml | 2 +- .github/workflows/e2e-test-ubuntu.yml | 6 +- .github/workflows/e2e-test-windows.yml | 3 +- .github/workflows/podman-install-linux.yml | 42 ++ .github/workflows/staging-publish.yml | 2 + README.md | 8 +- forge.config.cts | 4 +- package-lock.json | 536 ++++++++++-------- package.json | 22 +- src/__tests__/ci/installPodman.test.ts | 131 +++++ src/main/debug.ts | 11 +- src/main/execHelper.ts | 6 +- src/main/files.ts | 4 + src/main/main.ts | 12 +- src/main/menu.ts | 4 +- .../nn-auto-updater/findPackageManager.ts | 8 +- src/main/podman/install/aptInstallScript.ts | 7 + .../podman/install/debianInstallScript.ts | 15 - ...raInstallScript.ts => dnfInstallScript.ts} | 0 src/main/podman/install/install.ts | 2 +- src/main/podman/install/installOnLinux.ts | 37 +- .../podman/install/linuxMintInstallScript.ts | 14 - ...nstallScript.ts => pacmanInstallScript.ts} | 0 .../podman/install/ubuntuInstallScript.ts | 14 - src/main/podman/install/yumInstallScript.ts | 3 + .../podman/install/zypperInstallScript.ts | 3 + .../podman/uninstall/aptUninstallScript.ts | 2 + .../podman/uninstall/dnfUninstallScript.ts | 1 + .../podman/uninstall/pacmanUninstallScript.ts | 1 + src/main/podman/uninstall/uninstallOnLinux.ts | 42 +- .../podman/uninstall/yumUninstallScript.ts | 1 + .../podman/uninstall/zypperUninstallScript.ts | 2 + src/main/preload.ts | 11 +- .../redesign/ContentHeader/ContentHeader.tsx | 4 +- .../Generics/redesign/Modal/Modal.tsx | 5 +- .../Generics/redesign/Stepper/Stepper.tsx | 1 + .../AddNodeConfiguration.tsx | 2 +- .../NodeRequirements/NodeRequirements.tsx | 4 +- .../PodmanInstallation/PodmanInstallation.tsx | 11 +- test/specs/test.e2e.ts | 176 +++++- vite.base.config.ts | 24 +- vite.main.config.ts | 10 +- vite.renderer.config.ts | 13 +- vitest.config.ts | 16 - wdio.conf.ts | 14 +- 46 files changed, 932 insertions(+), 403 deletions(-) create mode 100644 .github/workflows/e2e-test-linux-distros.yml create mode 100644 .github/workflows/podman-install-linux.yml create mode 100644 src/__tests__/ci/installPodman.test.ts create mode 100644 src/main/podman/install/aptInstallScript.ts delete mode 100644 src/main/podman/install/debianInstallScript.ts rename src/main/podman/install/{fedoraInstallScript.ts => dnfInstallScript.ts} (100%) delete mode 100644 src/main/podman/install/linuxMintInstallScript.ts rename src/main/podman/install/{manjaroInstallScript.ts => pacmanInstallScript.ts} (100%) delete mode 100644 src/main/podman/install/ubuntuInstallScript.ts create mode 100644 src/main/podman/install/yumInstallScript.ts create mode 100644 src/main/podman/install/zypperInstallScript.ts create mode 100644 src/main/podman/uninstall/aptUninstallScript.ts create mode 100644 src/main/podman/uninstall/dnfUninstallScript.ts create mode 100644 src/main/podman/uninstall/pacmanUninstallScript.ts create mode 100644 src/main/podman/uninstall/yumUninstallScript.ts create mode 100644 src/main/podman/uninstall/zypperUninstallScript.ts delete mode 100644 vitest.config.ts diff --git a/.github/workflows/e2e-test-linux-distros.yml b/.github/workflows/e2e-test-linux-distros.yml new file mode 100644 index 000000000..741728645 --- /dev/null +++ b/.github/workflows/e2e-test-linux-distros.yml @@ -0,0 +1,99 @@ +name: e2e-tests-linux-distros + +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + e2e-build-n-test: + environment: staging + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + container: [ + "ubuntu:24.04", + "ubuntu:23.10", + "debian:12", + "fedora:40", + "fedora:39", + "manjarolinux/base", + "archlinux:latest", + ] + container: + image: ${{ matrix.container }} + env: + NODE_ENV: test + TEST: true + + steps: + - uses: actions/checkout@v4 + - name: ๐Ÿ’š Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: ๐Ÿงฑ Install system dependencies + run: | + # Define the packages needed (git req'd by electron forge) + packagesNeeded="nodejs npm git zip dpkg fakeroot" + + # Determine the package manager and install required packages + if command -v apt-get > /dev/null 2>&1; then + apt-get update + apt-get install --no-install-recommends -y $packagesNeeded rpm libarchive-tools + apt-get install -y \ + xvfb \ + zip \ + wget \ + ca-certificates \ + libnss3-dev \ + libasound2t64 \ + libxss1 \ + libappindicator3-1 \ + libindicator7 \ + xdg-utils \ + fonts-liberation \ + libgbm1 + elif command -v dnf > /dev/null 2>&1; then + dnf install -y $packagesNeeded rpmdevtools + elif command -v pacman > /dev/null 2>&1; then + pacman -Syu --noconfirm + pacman -S --noconfirm $packagesNeeded + elif command -v zypper > /dev/null 2>&1; then + zypper install -y $packagesNeeded + else + echo "FAILED TO INSTALL PACKAGES: Package manager not found. You must manually install: $packagesNeeded" >&2 + exit 1 + fi + + - name: Install npm dependencies + run: npm ci + + - name: ๐Ÿ“ฆ Bundle Application + env: + DEBUG: "*electron*" + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + MP_PROJECT_TOKEN: ${{ secrets.MP_PROJECT_TOKEN }} + MP_PROJECT_ENV: ${{ vars.MP_PROJECT_ENV }} + NICENODE_ENV: ${{ vars.NICENODE_ENV }} + NO_CODE_SIGNING: true + run: | + npm run make + + - name: Setup virtual display + run: | + export DISPLAY=':99.0' + Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + + - name: ๐Ÿงช Run Tests + run: | + npm run wdio + + - name: ๐Ÿ› Debug Build + uses: stateful/vscode-server-action@v1 + if: failure() + with: + timeout: '120000' diff --git a/.github/workflows/e2e-test-mac.yml b/.github/workflows/e2e-test-mac.yml index 341d9f2eb..79996de63 100644 --- a/.github/workflows/e2e-test-mac.yml +++ b/.github/workflows/e2e-test-mac.yml @@ -43,7 +43,7 @@ jobs: ls -al - name: ๐Ÿงช Run Tests - uses: coactions/setup-xvfb@v1 + uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a with: run: npm run wdio - name: ๐Ÿ› Debug Build diff --git a/.github/workflows/e2e-test-ubuntu.yml b/.github/workflows/e2e-test-ubuntu.yml index e4fdf2335..70b5434cb 100644 --- a/.github/workflows/e2e-test-ubuntu.yml +++ b/.github/workflows/e2e-test-ubuntu.yml @@ -24,8 +24,9 @@ jobs: - name: ๐Ÿงฑ Install Dependencies run: | - npm ci + sudo apt-get update sudo apt-get install --no-install-recommends -y rpm libarchive-tools + npm ci - name: ๐Ÿ“ฆ Bundle Application env: @@ -39,9 +40,10 @@ jobs: npm run make - name: ๐Ÿงช Run Tests - uses: coactions/setup-xvfb@v1 + uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a with: run: npm run wdio + - name: ๐Ÿ› Debug Build uses: stateful/vscode-server-action@v1 if: failure() diff --git a/.github/workflows/e2e-test-windows.yml b/.github/workflows/e2e-test-windows.yml index ccef4e30e..ce8e6b72e 100644 --- a/.github/workflows/e2e-test-windows.yml +++ b/.github/workflows/e2e-test-windows.yml @@ -42,9 +42,10 @@ jobs: run: npm run make - name: ๐Ÿงช Run Tests - uses: coactions/setup-xvfb@v1 + uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a with: run: npm run wdio + - name: ๐Ÿ› Debug Build uses: stateful/vscode-server-action@v1 if: failure() diff --git a/.github/workflows/podman-install-linux.yml b/.github/workflows/podman-install-linux.yml new file mode 100644 index 000000000..233c25d56 --- /dev/null +++ b/.github/workflows/podman-install-linux.yml @@ -0,0 +1,42 @@ +name: Podman Install on Linux Distros +on: + push: + # branches: [ main ] + workflow_dispatch: + +jobs: + container-test-job: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + container: [ + "ubuntu:24.04", + "ubuntu:23.10", + "debian:12", + "fedora:40", + "fedora:39", + "manjarolinux/base", + "archlinux:latest", + ] + + container: + image: ${{ matrix.container }} + env: + NODE_ENV: test + steps: + - name: print os version details + run: cat /etc/os-release + + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: ๐Ÿงฑ Install Dependencies + run: | + npm ci + + - name: ๐Ÿงฑ Run tests + run: | + npm run testCi diff --git a/.github/workflows/staging-publish.yml b/.github/workflows/staging-publish.yml index 5fd9c0489..29e5c4a57 100644 --- a/.github/workflows/staging-publish.yml +++ b/.github/workflows/staging-publish.yml @@ -78,6 +78,8 @@ jobs: # This is used for uploading release assets to github GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + versionPostfix: '-staging' + run: | npm run publish -- --arch=x64 npm run publish -- --arch=arm64 diff --git a/README.md b/README.md index a92b0e7a5..c54685375 100644 --- a/README.md +++ b/README.md @@ -70,10 +70,16 @@ arch options include: ia32, x64, armv7l, arm64, mips64el, universal Unit tests with `npm run test` +### Frontend (React) tests +`npm run test -- --config vite.renderer.config.ts --dir src/__tests__/react` + +### Backend (Nodejs) tests +`npm run test -- --config vite.main.config.ts --dir src/__tests__/node` + ### End-to-end (e2e) tests For e2e tests, we use webdriver and an electron plugin to automate testing. -It requires a packaged build to complete the tests. +**It requires a packaged build to run the tests!** To run them locally, package the source first (and after making any changes to anything other than `tests`), then run the e2e tests with `wdio` diff --git a/forge.config.cts b/forge.config.cts index 75196126b..3440ea143 100644 --- a/forge.config.cts +++ b/forge.config.cts @@ -11,6 +11,7 @@ import * as path from 'node:path'; import packageJson from './package.json'; const { version } = packageJson; +const { versionPostfix } = process.env; const iconDir = path.resolve('assets', 'icons'); console.log("forge.config.ts iconDir: ", iconDir); @@ -25,7 +26,8 @@ const packagerConfig: ForgePackagerOptions = { name: 'NiceNode Protocol', schemes: ['nice-node'], } - ] + ], + appVersion: versionPostfix ? `${version}${versionPostfix}` : version // unsure if this is needed below: // ignore: [ /stories/, /__tests__/, /.storybook/, /storybook/, /storybook-static/ ], }; diff --git a/package-lock.json b/package-lock.json index 4178a62ac..1b96695ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nice-node", - "version": "6.0.0-alpha", + "version": "6.0.1-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nice-node", - "version": "6.0.0-alpha", + "version": "6.0.1-alpha", "license": "MIT", "dependencies": { "@reduxjs/toolkit": "^2.2.3", @@ -79,10 +79,10 @@ "@types/throttle-debounce": "^5.0.0", "@types/uuid": "^9.0.3", "@vanilla-extract/vite-plugin": "^4.0.7", - "@wdio/cli": "^8.36.0", - "@wdio/local-runner": "^8.36.0", - "@wdio/mocha-framework": "^8.36.0", - "@wdio/spec-reporter": "^8.36.0", + "@wdio/cli": "^8.36.1", + "@wdio/local-runner": "^8.36.1", + "@wdio/mocha-framework": "^8.36.1", + "@wdio/spec-reporter": "^8.36.1", "cross-env": "^7.0.3", "electron": "^30.0.1", "electron-devtools-installer": "^3.2.0", @@ -98,7 +98,7 @@ "vite": "^5.2.10", "vite-plugin-svgr": "^4.2.0", "vitest": "^1.5.0", - "wdio-electron-service": "^6.4.1", + "wdio-electron-service": "^6.5.0", "wdio-wait-for": "^3.0.11" } }, @@ -7641,19 +7641,19 @@ "integrity": "sha512-9ORTwwS74VaTn38tNbQhsA5U44zkJfcb0BdTSyyG6frP4e8KMtHuTXYmwefe5dpL8XB1aGSIVTaLjD3BbWb5iA==" }, "node_modules/@wdio/cli": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.36.0.tgz", - "integrity": "sha512-B8iEwz9DRzHquPihT74nKUzN9s+rCd1TkBp+JGmdgm7pJqiWTe4FORrzaxWjdiCO78jbYK9LgaMORpCcAzjwIA==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.36.1.tgz", + "integrity": "sha512-LZBZiwcvvv5P0HuRXt8IV09UiFT5dnDr1Ag5u2roJL2D7l8wDHHa70PXw9MmlbrnyFCUN3hO7FQVUi9MAsDbDQ==", "dev": true, "dependencies": { "@types/node": "^20.1.1", "@vitest/snapshot": "^1.2.1", - "@wdio/config": "8.36.0", - "@wdio/globals": "8.36.0", + "@wdio/config": "8.36.1", + "@wdio/globals": "8.36.1", "@wdio/logger": "8.28.0", "@wdio/protocols": "8.32.0", - "@wdio/types": "8.36.0", - "@wdio/utils": "8.36.0", + "@wdio/types": "8.36.1", + "@wdio/utils": "8.36.1", "async-exit-hook": "^2.0.1", "chalk": "^5.2.0", "chokidar": "^3.5.3", @@ -7668,7 +7668,7 @@ "lodash.union": "^4.6.0", "read-pkg-up": "10.0.0", "recursive-readdir": "^2.2.3", - "webdriverio": "8.36.0", + "webdriverio": "8.36.1", "yargs": "^17.7.2" }, "bin": { @@ -7691,14 +7691,14 @@ } }, "node_modules/@wdio/config": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.36.0.tgz", - "integrity": "sha512-sAbqnx/G+OsrMquIncFXjM4U0/E0ULMP0jDHZND75r0e1DYYCHmyacrvIHu3Jyxinl9f6+4XQdev6vqdTqPdNg==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.36.1.tgz", + "integrity": "sha512-yCENnym0CrYuLKMJ3fv00WkjCR8QpPqVohGBkq5FvZOZpVJEpoG86Q8l4HtyRnd6ggMTKCA1vTQ/myhbPmZmaQ==", "dev": true, "dependencies": { "@wdio/logger": "8.28.0", - "@wdio/types": "8.36.0", - "@wdio/utils": "8.36.0", + "@wdio/types": "8.36.1", + "@wdio/utils": "8.36.1", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -7755,38 +7755,38 @@ } }, "node_modules/@wdio/config/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", + "integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/@wdio/globals": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.36.0.tgz", - "integrity": "sha512-vqMq1hR+iF0lqMNJpk9z+QB9l/QfL1DbvOfNhPtQ13NgctfNg42ffuhEObbzTLQN0MftcnPBu6O3pai79y8bUA==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.36.1.tgz", + "integrity": "sha512-Qpj6gZCRNxqdVkTwYyi4JdeYO4tLSUj3Ti6yxO0v9A4IRaKW1tS29KUcGgjL9CFSBKAOi2zRY8vvFz1u6ewxtQ==", "dev": true, "engines": { "node": "^16.13 || >=18" }, "optionalDependencies": { "expect-webdriverio": "^4.11.2", - "webdriverio": "8.36.0" + "webdriverio": "8.36.1" } }, "node_modules/@wdio/local-runner": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.36.0.tgz", - "integrity": "sha512-MIzbWcXgRQGQQK4H5N39/JFoikOg5cu34l1U6rgw74D6hO79L4RwBg2Oo4TJJYgHUL/4RbVwyeLdb5WDTdluTQ==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.36.1.tgz", + "integrity": "sha512-FYsTzbNGRnrniOsLWrZO7+DLecAS9W75AIzFZQVQxruiDFkGmKY5OV6gsuvMlasaqAQXW1s+w29bqrLY4DxdEw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.28.0", "@wdio/repl": "8.24.12", - "@wdio/runner": "8.36.0", - "@wdio/types": "8.36.0", + "@wdio/runner": "8.36.1", + "@wdio/types": "8.36.1", "async-exit-hook": "^2.0.1", "split2": "^4.1.0", "stream-buffers": "^3.0.2" @@ -7823,16 +7823,16 @@ } }, "node_modules/@wdio/mocha-framework": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.36.0.tgz", - "integrity": "sha512-5wZgh1apbSKTtgGwvd//L4kxdaXe30AQ3y9YeJD+OuAJUTYFRjTpMS13bO3pX518imQeB8HCm4aUc2kxs7J81Q==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.36.1.tgz", + "integrity": "sha512-G0h5AeneMNtoh9CcVQ82OCKj0axxUOEotEcInDu8V6UJbUywNJVL/bdTMKdaq5i84Hnc+s1LUKmLvN95F+lHGA==", "dev": true, "dependencies": { "@types/mocha": "^10.0.0", "@types/node": "^20.1.0", "@wdio/logger": "8.28.0", - "@wdio/types": "8.36.0", - "@wdio/utils": "8.36.0", + "@wdio/types": "8.36.1", + "@wdio/utils": "8.36.1", "mocha": "^10.0.0" }, "engines": { @@ -7858,14 +7858,14 @@ } }, "node_modules/@wdio/reporter": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.36.0.tgz", - "integrity": "sha512-pkAxqiMC+ljmksOKlK9g6y2NRvrdQiKtxD11rsMwJ6CH4kVDSGIvENw7u3kxg7Qwp0j1rCKf5Hp51npqKQgeDQ==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.36.1.tgz", + "integrity": "sha512-HcXr9XKq/6kPC9nexMRXIc/ft3Lvp0yCaW5tps01Axus9wbi5ysLHi2z5sB84F2YdpM+aRf7Lac56xkc4Jldeg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.28.0", - "@wdio/types": "8.36.0", + "@wdio/types": "8.36.1", "diff": "^5.0.0", "object-inspect": "^1.12.0" }, @@ -7874,35 +7874,35 @@ } }, "node_modules/@wdio/runner": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.36.0.tgz", - "integrity": "sha512-M2ZDL0gmR2VvVMchi3Pkonva6Gn6eFh6IwVCpT0np7zioaqOksy3IM7Aki8kPKKS88Osip5dAfoKIrY7JpHovA==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.36.1.tgz", + "integrity": "sha512-bLkxQ46MLEbzIf30adl2nyz8kxED/V0IjcQASm0VKfNmsG8LOf7iOIz+udOF4GkMoF++5JuONA5abUsyLvwatg==", "dev": true, "dependencies": { "@types/node": "^20.11.28", - "@wdio/config": "8.36.0", - "@wdio/globals": "8.36.0", + "@wdio/config": "8.36.1", + "@wdio/globals": "8.36.1", "@wdio/logger": "8.28.0", - "@wdio/types": "8.36.0", - "@wdio/utils": "8.36.0", + "@wdio/types": "8.36.1", + "@wdio/utils": "8.36.1", "deepmerge-ts": "^5.1.0", "expect-webdriverio": "^4.12.0", "gaze": "^1.1.3", - "webdriver": "8.36.0", - "webdriverio": "8.36.0" + "webdriver": "8.36.1", + "webdriverio": "8.36.1" }, "engines": { "node": "^16.13 || >=18" } }, "node_modules/@wdio/spec-reporter": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.36.0.tgz", - "integrity": "sha512-GVOiWqVYvzoAo4/4hNVxvyVWVoHyEmAywYhkykyJGL05YpO0oDOZY2kINPePEX5Z+nIsXsiKPmtsGGqWsfQwTw==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.36.1.tgz", + "integrity": "sha512-VgAd8VQCfwKYz4A3BPDUYNIQxXhRSTaVNbmDzSlYfo5Jekygk7fz0LRFYBpJ69l7eQH0P5nzEyF92oW/rvE3VA==", "dev": true, "dependencies": { - "@wdio/reporter": "8.36.0", - "@wdio/types": "8.36.0", + "@wdio/reporter": "8.36.1", + "@wdio/types": "8.36.1", "chalk": "^5.1.2", "easy-table": "^1.2.0", "pretty-ms": "^7.0.0" @@ -7924,9 +7924,9 @@ } }, "node_modules/@wdio/types": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.36.0.tgz", - "integrity": "sha512-0hw/PaJHqDrbIMvU08w3oMDGg89udSkqWF2hFlGAjOc20quRrhn0F1L+NhFpYdezeRKz5gpgTDIqaQs9RWKq1A==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.36.1.tgz", + "integrity": "sha512-kKtyJbypasKo/VQuJ6dTQQwFtHE9qoygjoCZjrQCLGraRSjOEiqZHPR0497wbeCvcgHIYyImbmcylqZNGUE0CQ==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -7936,14 +7936,14 @@ } }, "node_modules/@wdio/utils": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.36.0.tgz", - "integrity": "sha512-3VAbavN206qkvm6lITtOtTgscFChax7shzqHjUNln+QWMRyELtT81iw32ux2ld+Bg3F60LAmhbGodu0lJH7k2w==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.36.1.tgz", + "integrity": "sha512-xmgPHU11/o9n2FeRmDFkPRC0okiwA1i2xOcR2c3aSpuk99XkAm9RaMn/6u9LFaqsCpgaVxazcYEGSceO7U4hZA==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", "@wdio/logger": "8.28.0", - "@wdio/types": "8.36.0", + "@wdio/types": "8.36.1", "decamelize": "^6.0.0", "deepmerge-ts": "^5.1.0", "edgedriver": "^5.3.5", @@ -9664,6 +9664,18 @@ "node": ">=6.0" } }, + "node_modules/chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "dev": true, + "dependencies": { + "mitt": "3.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/chromium-pickle-js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", @@ -10207,6 +10219,18 @@ "node": ">= 0.6" } }, + "node_modules/convert-hrtime": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", + "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -12895,15 +12919,16 @@ } }, "node_modules/find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", + "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", "dev": true, "dependencies": { - "semver-regex": "^4.0.5" + "semver-regex": "^4.0.5", + "super-regex": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -13188,6 +13213,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function-timeout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.1.tgz", + "integrity": "sha512-6yPMImFFuaMPNaTMTBuolA8EanHJWF5Vju0NHpObRURT105J6x1Mf2a7J4P7Sqk2xDxv24N5L0RatEhTBhNmdA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -18514,6 +18551,147 @@ "node": ">=6" } }, + "node_modules/puppeteer-core": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", + "dev": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.0", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", + "dev": true + }, + "node_modules/puppeteer-core/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/puppeteer-core/node_modules/proxy-agent": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/puppeteer-core/node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/puppeteer-core/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/qs": { "version": "6.12.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", @@ -20660,6 +20838,22 @@ "node": ">= 8.0" } }, + "node_modules/super-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.0.0.tgz", + "integrity": "sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==", + "dev": true, + "dependencies": { + "function-timeout": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -20947,6 +21141,21 @@ "xtend": "~4.0.1" } }, + "node_modules/time-span": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", + "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "dev": true, + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tiny-each-async": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz", @@ -22570,9 +22779,9 @@ } }, "node_modules/wdio-electron-service": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/wdio-electron-service/-/wdio-electron-service-6.4.1.tgz", - "integrity": "sha512-mYF3ZXuQc9BJlWK89taFMJy5bTKEjjU/ISR//D48lMnSksUhIy7NMPhGf6rob7EaU5XCzgLvqXbpX2ZviNk2YQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/wdio-electron-service/-/wdio-electron-service-6.5.0.tgz", + "integrity": "sha512-8W+3ZoAvQOgqr6rOsKtL5h4dq8Cyj5+J24kzwOUykjZVFSljj7suvpvfFqYaPEQMGXLVMXlhwX/RCWEJt0c2Rg==", "dev": true, "dependencies": { "@vitest/spy": "^1.2.0", @@ -22581,7 +22790,7 @@ "debug": "^4.3.4", "electron-to-chromium": "^1.4.630", "fast-copy": "^3.0.1", - "find-versions": "^5.1.0", + "find-versions": "^6.0.0", "node-fetch": "^3.3.2", "read-package-up": "^11.0.0" }, @@ -22647,18 +22856,18 @@ } }, "node_modules/webdriver": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.36.0.tgz", - "integrity": "sha512-6fmZI1+OCGbhuGMLBLvA7m9TJvHU1Cyzxqd8rGzIyb8hocR53yh/olfOL1BPcjU1NXmKuU1BePSGF+yiKajiEA==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.36.1.tgz", + "integrity": "sha512-547RivYCHStVqtiGQBBcABAkzJbPnAWsxpXGzmj5KL+TOM2JF41N2iQRtUxXqr0jme1Nzzye7WS7Y7iSnK6i1g==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.36.0", + "@wdio/config": "8.36.1", "@wdio/logger": "8.28.0", "@wdio/protocols": "8.32.0", - "@wdio/types": "8.36.0", - "@wdio/utils": "8.36.0", + "@wdio/types": "8.36.1", + "@wdio/utils": "8.36.1", "deepmerge-ts": "^5.1.0", "got": "^12.6.1", "ky": "^0.33.0", @@ -22830,9 +23039,9 @@ } }, "node_modules/webdriver/node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "dev": true, "engines": { "node": ">=10.0.0" @@ -22851,18 +23060,18 @@ } }, "node_modules/webdriverio": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.36.0.tgz", - "integrity": "sha512-4WnEI+OxslHpfSnDXuADaR6bL1M7QxBUEF1mTN56AroOCJelyPvt94yRhszwQnLcJJB2OLn49eUz8M4yBCB51w==", + "version": "8.36.1", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.36.1.tgz", + "integrity": "sha512-vzE09oFQeMbOYJ/75jZ13sDIljzC3HH7uoUJKAMAEtyrn/bu1F9Sg/4IDEsvQaRD3pz3ae6SkRld33lcQk6HJA==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.36.0", + "@wdio/config": "8.36.1", "@wdio/logger": "8.28.0", "@wdio/protocols": "8.32.0", "@wdio/repl": "8.24.12", - "@wdio/types": "8.36.0", - "@wdio/utils": "8.36.0", + "@wdio/types": "8.36.1", + "@wdio/utils": "8.36.1", "archiver": "^7.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -22879,7 +23088,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.36.0" + "webdriver": "8.36.1" }, "engines": { "node": "^16.13 || >=18" @@ -22893,35 +23102,6 @@ } } }, - "node_modules/webdriverio/node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", - "dev": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/webdriverio/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -22931,15 +23111,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/webdriverio/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/webdriverio/node_modules/minimatch": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", @@ -22955,68 +23126,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webdriverio/node_modules/proxy-agent": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", - "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/webdriverio/node_modules/puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", - "dev": true, - "dependencies": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", - "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", - "ws": "8.13.0" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/webdriverio/node_modules/puppeteer-core/node_modules/chromium-bidi": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", - "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", - "dev": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/webdriverio/node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true - }, "node_modules/webdriverio/node_modules/serialize-error": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", @@ -23032,59 +23141,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webdriverio/node_modules/socks-proxy-agent": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", - "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.1", - "debug": "^4.3.4", - "socks": "^2.7.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/webdriverio/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/webdriverio/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index 50cbcf981..d9d4abac8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nice-node", - "version": "6.0.1-alpha", + "version": "6.0.2-alpha", "description": "Run a node at home, the easy way.", "homepage": "https://nicenode.xyz", "productName": "NiceNode", @@ -14,13 +14,15 @@ "lint": "biome lint ./src", "safeFix": "biome check --apply ./src", "unsafeFix": "biome check --apply-unsafe ./src", - "test": "vitest --run", - "testWatch": "vitest --watch", - "coverage": "vitest run --coverage", + "test": "npm run testFrontend && npm run testBackend", + "testFrontend": "vitest run --config vite.renderer.config.ts --dir src/__tests__/react", + "testBackend": "vitest run --config vite.main.config.ts --dir src/__tests__/node", + "testCi": "vitest run --dir src/__tests__/ci --config vite.main.config.ts", + "coverage": "npm run testFrontend -- --coverage && npm run testBackend -- --coverage", "prepare": "husky", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", - "wdio": "cross-env NODE_ENV=test wdio run ./wdio.conf.ts", + "wdio": "cross-env TEST_ENV=wdio NODE_ENV=test wdio run ./wdio.conf.ts", "docs:nodeSpec": "typedoc --plugin typedoc-plugin-markdown --name \"Node Spec examples\" --readme src/common/index.md --entryDocument index.md --out docs src/common/*" }, "devDependencies": { @@ -57,10 +59,10 @@ "@types/throttle-debounce": "^5.0.0", "@types/uuid": "^9.0.3", "@vanilla-extract/vite-plugin": "^4.0.7", - "@wdio/cli": "^8.36.0", - "@wdio/local-runner": "^8.36.0", - "@wdio/mocha-framework": "^8.36.0", - "@wdio/spec-reporter": "^8.36.0", + "@wdio/cli": "^8.36.1", + "@wdio/local-runner": "^8.36.1", + "@wdio/mocha-framework": "^8.36.1", + "@wdio/spec-reporter": "^8.36.1", "cross-env": "^7.0.3", "electron": "^30.0.1", "electron-devtools-installer": "^3.2.0", @@ -76,7 +78,7 @@ "vite": "^5.2.10", "vite-plugin-svgr": "^4.2.0", "vitest": "^1.5.0", - "wdio-electron-service": "^6.4.1", + "wdio-electron-service": "^6.5.0", "wdio-wait-for": "^3.0.11" }, "dependencies": { diff --git a/src/__tests__/ci/installPodman.test.ts b/src/__tests__/ci/installPodman.test.ts new file mode 100644 index 000000000..82fe87c05 --- /dev/null +++ b/src/__tests__/ci/installPodman.test.ts @@ -0,0 +1,131 @@ +import { execSync } from 'node:child_process'; +import { beforeAll, describe, expect, test, vi } from 'vitest'; +import { isLinux } from '../../main/platform.js'; +import { + PODMAN_MIN_VERSION, + getInstalledPodmanVersion, +} from '../../main/podman/install/install.js'; +// import installPodman from '../../main/podman/install/install.js'; +import installOnLinux from '../../main/podman/install/installOnLinux.js'; +import uninstallOnLinux from '../../main/podman/uninstall/uninstallOnLinux.js'; + +beforeAll(async () => { + // called once before all tests run + if (!isLinux()) { + throw new Error('This test suite is only for Linux'); + } + + vi.mock('../../main/logger.js', () => { + return { + default: { + info: vi.fn((msg: string) => { + console.log(msg); + }), + error: vi.fn((msg: string) => { + console.log(msg); + }), + }, + autoUpdateLogger: vi.fn(), + }; + }); + + vi.mock('../../main/execHelper.js', () => { + return { + execAwait: vi.fn((command: string) => { + return execSync(command); + }), + }; + }); + + vi.mock('electron', () => { + return { + app: { + getAppPath: vi.fn(() => { + return '/we/out/here/nice-node'; + }), + getPath: vi.fn((pathName: string) => { + return pathName; + }), + isPackaged: false, + on: vi.fn(), + getName: () => 'NiceNode', + }, + powerMonitor: { + isOnBatteryPower: vi.fn(), + }, + autoUpdater: vi.fn(), + nativeTheme: { + on: vi.fn(), + }, + }; + }); + vi.mock('@sentry/electron/main', () => { + return { + init: vi.fn(() => { + return {}; + }), + }; + }); + vi.mock('../../main/i18nMain', () => { + return { + default: { + // Mock any other properties or methods if needed + getFixedT: vi.fn((x, y) => { + return { + t: (k: any) => k, // just return the key for simplicity + }; + }), + }, + // changeLanguage: vi.fn(), + // init: vi.fn(), + // use: vi.fn(() => i18nMock), // for chaining .use() calls + }; + }); +}); +const versionRegex = /(\d+\.\d+\.\d+)/; + +describe.sequential('Install and Uninstall Podman', () => { + test('If pre-installed, uninstall to test install next', async () => { + const versionBefore = await getInstalledPodmanVersion(); + if (versionBefore !== undefined) { + expect(versionBefore).toMatch(versionRegex); + const resultInstall = await uninstallOnLinux(); + expect(resultInstall).toEqual(true); + const versionAfter = await getInstalledPodmanVersion(); + expect(versionAfter).toBeUndefined(); + } + }); + + // 180 seconds timeout, dnf/apt update can take a while + test( + 'Install is successful and returns true', + { timeout: 180000 }, + async () => { + const versionBefore = await getInstalledPodmanVersion(); + expect(versionBefore).toBeUndefined(); + const resultInstall = await installOnLinux(); + expect(resultInstall).toEqual(true); + const versionAfter = await getInstalledPodmanVersion(); + console.log('======= podman version installed: ', versionAfter); + expect(versionAfter).toMatch(versionRegex); + expect(versionAfter > PODMAN_MIN_VERSION).toBeTruthy(); + }, + ); + + test('Uninstall is successful and returns true', async () => { + const versionBefore = await getInstalledPodmanVersion(); + expect(versionBefore).toMatch(versionRegex); + expect(versionBefore > PODMAN_MIN_VERSION).toBeTruthy(); + // expect(versionBefore).toEqual('4.3.1'); + const resultInstall = await uninstallOnLinux(); + expect(resultInstall).toEqual(true); + const versionAfter = await getInstalledPodmanVersion(); + expect(versionAfter).toBeUndefined(); + }); + // check not installed before + // version? + // it('Is successful and returns true', async () => { + // const resultInstall = await installPodman(); + // expect(resultInstall).toEqual(true); + // }); +}); diff --git a/src/main/debug.ts b/src/main/debug.ts index 92b13c2f3..ff1b22ca1 100644 --- a/src/main/debug.ts +++ b/src/main/debug.ts @@ -3,18 +3,23 @@ import { app } from 'electron'; import { getArch } from './arch'; import { getPlatform } from './platform'; +import { getOperatingSystemInfo } from './systemInfo.js'; -export default function getDebugInfo() { +export default async function getDebugInfo() { let niceNodeVersion = app.getVersion(); if (process.env.NODE_ENV === 'development') { niceNodeVersion = `Dev-${niceNodeVersion}`; } + const { distro, release } = await getOperatingSystemInfo(); + // todo: make human readable (version) return { platform: getPlatform(), platformRelease: os.release(), + distro: distro, + release: release, arch: getArch(), freeMemory: os.freemem(), totalMemory: os.totalmem(), @@ -39,9 +44,9 @@ const getDebugInfoShort = () => { }; }; -export const getDebugInfoString = () => { +export const getDebugInfoString = async () => { try { - return JSON.stringify(getDebugInfo(), null, 2); + return JSON.stringify(await getDebugInfo(), null, 2); } catch (err) { return 'No system details.'; } diff --git a/src/main/execHelper.ts b/src/main/execHelper.ts index 230cfc684..079a3d303 100644 --- a/src/main/execHelper.ts +++ b/src/main/execHelper.ts @@ -25,7 +25,11 @@ export const execAwait = ( logger.info(command); } - if (options.sudo) { + logger.info( + `execHelper process.env.TEST === 'true' skips sudo. TEST= ${process.env.TEST}`, + ); + // todo: remove test check and mock this function + if (options.sudo && process.env.TEST !== 'true') { const sudoPromptOptions = { name: 'NiceNode', // icns: iconIcns, // (optional) diff --git a/src/main/files.ts b/src/main/files.ts index a6f88eb58..26b165ea7 100644 --- a/src/main/files.ts +++ b/src/main/files.ts @@ -230,5 +230,9 @@ export const getAssetsFolder = (): string => { return path.resolve(__dirname, '..', '..', 'assets'); } + if (process.env.TEST === 'true') { + return 'assets'; + } + return path.resolve((process as any).resourcesPath, 'assets'); }; diff --git a/src/main/main.ts b/src/main/main.ts index 9aa680678..44fc12acd 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -41,11 +41,11 @@ if (process.env.NODE_ENV === 'development') { } // todo: when moving from require to imports -// const isTest = process.env.NODE_ENV === 'test'; -// if (isTest) { -// console.log('NODE_ENV=TEST... requiring wdio-electron-service/main'); -// require('wdio-electron-service/main'); -// } +const isTest = process.env.TEST === 'true'; +if (isTest && process.env.TEST_ENV === 'wdio') { + logger.info('env.TEST=true... calling import(wdio-electron-service/main)'); + import('wdio-electron-service/main'); +} // todo: Turned off when switching to ESM modules. Do we need this? // https://www.electronforge.io/config/makers/squirrel.windows#handling-startup-events @@ -76,8 +76,6 @@ export const getMenuBuilder = () => menuBuilder; const isDevelopment = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; -const isTest = process.env.NODE_ENV === 'test'; - // if (isDevelopment) { // require('electron-debug')(); // } diff --git a/src/main/menu.ts b/src/main/menu.ts index 8bce7cfee..f1372c4bf 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -233,8 +233,8 @@ export default class MenuBuilder { }, { label: t('CopyConfigurationDetailsToClipboard'), - click() { - clipboard.writeText(getDebugInfoString()); + click: async () => { + clipboard.writeText(await getDebugInfoString()); }, }, { type: 'separator' }, diff --git a/src/main/nn-auto-updater/findPackageManager.ts b/src/main/nn-auto-updater/findPackageManager.ts index cfecad35f..827a05ebb 100644 --- a/src/main/nn-auto-updater/findPackageManager.ts +++ b/src/main/nn-auto-updater/findPackageManager.ts @@ -3,8 +3,8 @@ import { promisify } from 'node:util'; const exec = promisify(execCallback); -export type PackageType = 'deb' | 'rpm'; -export type PackageManager = 'dpkg' | 'dnf' | 'yum' | 'zypper'; +export type PackageType = 'deb' | 'pacman' | 'rpm'; +export type PackageManager = 'dpkg' | 'dnf' | 'pacman' | 'yum' | 'zypper'; interface PackageManagerMap { [key: string]: PackageManager; @@ -17,16 +17,16 @@ interface PackageManagerToTypeMap { const packageManagers: PackageManagerMap = { 'apt-get': 'dpkg', // "deb (apt)", dnf: 'dnf', // "rpm (dnf)", + pacman: 'pacman', yum: 'yum', // "rpm (yum)", - // pacman: "pacman", zypper: 'zypper', // "rpm (zypper)" }; const packageTypes: PackageManagerToTypeMap = { 'apt-get': 'deb', // "deb (apt)", dnf: 'rpm', // "rpm (dnf)", + pacman: 'pacman', yum: 'rpm', // "rpm (yum)", - // pacman: "pacman", zypper: 'rpm', // "rpm (zypper)" }; diff --git a/src/main/podman/install/aptInstallScript.ts b/src/main/podman/install/aptInstallScript.ts new file mode 100644 index 000000000..a9c95a653 --- /dev/null +++ b/src/main/podman/install/aptInstallScript.ts @@ -0,0 +1,7 @@ +// Reference https://podman.io/docs/installation +// first line is to remove a depracted apt source that will conflict with the official one +export const script = ` +rm -rf /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list +apt -y update -qq +apt install -y podman +`; diff --git a/src/main/podman/install/debianInstallScript.ts b/src/main/podman/install/debianInstallScript.ts deleted file mode 100644 index 2e46f742d..000000000 --- a/src/main/podman/install/debianInstallScript.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Same script as on https://podman.io/docs/installation, except the 'sudo' is removed as -// sudo-prompt will not execute a command with sudo -export const script = `apt-get -y update -qq -apt-get -y install curl -mkdir -p /etc/apt/keyrings -curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/Debian_Unstable/Release.key \ - | gpg --dearmor \ - | tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null -echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg]\ - https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/Debian_Unstable/ /" \ - | tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null -apt-get -y update -apt-get -y upgrade -apt-get -y install podman`; diff --git a/src/main/podman/install/fedoraInstallScript.ts b/src/main/podman/install/dnfInstallScript.ts similarity index 100% rename from src/main/podman/install/fedoraInstallScript.ts rename to src/main/podman/install/dnfInstallScript.ts diff --git a/src/main/podman/install/install.ts b/src/main/podman/install/install.ts index ffbe8d05d..8ee5622f8 100644 --- a/src/main/podman/install/install.ts +++ b/src/main/podman/install/install.ts @@ -6,7 +6,7 @@ import installOnMac from './installOnMac'; import installOnWindows from './installOnWindows'; export const PODMAN_LATEST_VERSION = '5.0.2'; -export const PODMAN_MIN_VERSION = '4.6.0'; +export const PODMAN_MIN_VERSION = '4.3.0'; const installPodman = async (): Promise => { logger.info('Starting podman install...'); diff --git a/src/main/podman/install/installOnLinux.ts b/src/main/podman/install/installOnLinux.ts index 2cc9f1509..885d7e3fd 100644 --- a/src/main/podman/install/installOnLinux.ts +++ b/src/main/podman/install/installOnLinux.ts @@ -1,13 +1,17 @@ import { reportEvent } from '../../events'; import { execAwait } from '../../execHelper'; import logger from '../../logger'; +import { + type PackageManager, + findPackageManager, +} from '../../nn-auto-updater/findPackageManager.js'; import { getOperatingSystemInfo } from '../../systemInfo'; import { sendMessageOnGrantPermissionToInstallPodman } from '../messageFrontEnd'; -import { script as debianInstallScript } from './debianInstallScript'; -import { script as fedoraInstallScript } from './fedoraInstallScript'; -import { script as linuxMintInstallScript } from './linuxMintInstallScript'; -import { script as manjaroInstallScript } from './manjaroInstallScript'; -import { script as ubuntuInstallScript } from './ubuntuInstallScript'; +import { script as aptInstallScript } from './aptInstallScript'; +import { script as dnfInstallScript } from './dnfInstallScript'; +import { script as pacmanInstallScript } from './pacmanInstallScript'; +import { script as yumInstallScript } from './yumInstallScript'; +import { script as zypperInstallScript } from './zypperInstallScript'; // const UBUNTU_INSTALL_SCRIPT = 'installOnUbuntuScript'; /** @@ -17,6 +21,7 @@ import { script as ubuntuInstallScript } from './ubuntuInstallScript'; const installOnLinux = async (): Promise => { logger.info('Starting podman install on Linux...'); const { distro, release } = await getOperatingSystemInfo(); + // ex: Ubuntu & 22.04.4 LTS logger.info( `Attempting to install Podman on distro and release: ${distro} & ${release} ...`, ); @@ -25,21 +30,23 @@ const installOnLinux = async (): Promise => { let installScript = ''; // Run "cat /etc/*-release; cat /usr/lib/os-release; cat /etc/openwrt_release" on a Linux Distro // or see https://github.com/sebhildebrandt/systeminformation/blob/master/lib/osinfo.js to determine. - if (lcDistro.includes('ubuntu')) { - installScript = ubuntuInstallScript; - } else if (lcDistro.includes('debian')) { - installScript = debianInstallScript; - } else if (lcDistro.includes('fedora')) { - installScript = fedoraInstallScript; - } else if (lcDistro.includes('manjaro') || lcDistro.includes('arch')) { - installScript = manjaroInstallScript; - } else if (lcDistro.includes('linuxmint')) { - installScript = linuxMintInstallScript; + const pkgManager: PackageManager = await findPackageManager(); + if (pkgManager === 'dpkg') { + installScript = aptInstallScript; + } else if (pkgManager === 'dnf') { + installScript = dnfInstallScript; + } else if (pkgManager === 'yum') { + installScript = yumInstallScript; + } else if (pkgManager === 'pacman') { + installScript = pacmanInstallScript; + } else if (pkgManager === 'zypper') { + installScript = zypperInstallScript; } else { const errorMessage = `Installing Podman is not suported on this distro and release: ${distro} & ${release}`; logger.error(errorMessage); return { error: errorMessage }; } + try { try { const { stdout, stderr } = await execAwait(installScript, { diff --git a/src/main/podman/install/linuxMintInstallScript.ts b/src/main/podman/install/linuxMintInstallScript.ts deleted file mode 100644 index c4e436eff..000000000 --- a/src/main/podman/install/linuxMintInstallScript.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Same script as on https://podman.io/docs/installation, except the 'sudo' is removed as -// sudo-prompt will not execute a command with sudo -export const script = `apt-get -y update -qq -apt-get -y install curl -mkdir -p /etc/apt/keyrings -curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(grep DISTRIB_RELEASE= /etc/upstream-release/lsb-release | cut -d "=" -f 2)/Release.key \ - | gpg --dearmor \ - | tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null -echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg]\ - https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(grep DISTRIB_RELEASE= /etc/upstream-release/lsb-release | cut -d "=" -f 2)/ /" \ - | tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null -apt-get -y update -qq -apt-get -qq -y install podman`; diff --git a/src/main/podman/install/manjaroInstallScript.ts b/src/main/podman/install/pacmanInstallScript.ts similarity index 100% rename from src/main/podman/install/manjaroInstallScript.ts rename to src/main/podman/install/pacmanInstallScript.ts diff --git a/src/main/podman/install/ubuntuInstallScript.ts b/src/main/podman/install/ubuntuInstallScript.ts deleted file mode 100644 index 738a57815..000000000 --- a/src/main/podman/install/ubuntuInstallScript.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Same script as on https://podman.io/docs/installation, except the 'sudo' is removed as -// sudo-prompt will not execute a command with sudo -export const script = `apt-get -y update -qq -apt-get -y -qq install curl -mkdir -p /etc/apt/keyrings -curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_22.04/Release.key \ - | gpg --dearmor \ - | tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null -echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg]\ - https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_22.04/ /" \ - | tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null -apt-get update -qq -apt-get -qq -y install podman`; diff --git a/src/main/podman/install/yumInstallScript.ts b/src/main/podman/install/yumInstallScript.ts new file mode 100644 index 000000000..dbbbb257d --- /dev/null +++ b/src/main/podman/install/yumInstallScript.ts @@ -0,0 +1,3 @@ +// Same script as on https://podman.io/docs/installation, except the 'sudo' is removed as +// sudo-prompt will not execute a command with sudo +export const script = 'dnf -y update && dnf -y install podman'; diff --git a/src/main/podman/install/zypperInstallScript.ts b/src/main/podman/install/zypperInstallScript.ts new file mode 100644 index 000000000..429a1eda3 --- /dev/null +++ b/src/main/podman/install/zypperInstallScript.ts @@ -0,0 +1,3 @@ +// Reference https://podman.io/docs/installation +// biome-ignore lint/style/noUnusedTemplateLiteral: less diff for future changes +export const script = `zypper install -y podman`; diff --git a/src/main/podman/uninstall/aptUninstallScript.ts b/src/main/podman/uninstall/aptUninstallScript.ts new file mode 100644 index 000000000..166263980 --- /dev/null +++ b/src/main/podman/uninstall/aptUninstallScript.ts @@ -0,0 +1,2 @@ +export const script = `rm -rf /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list +apt remove -y podman`; diff --git a/src/main/podman/uninstall/dnfUninstallScript.ts b/src/main/podman/uninstall/dnfUninstallScript.ts new file mode 100644 index 000000000..4a43e5409 --- /dev/null +++ b/src/main/podman/uninstall/dnfUninstallScript.ts @@ -0,0 +1 @@ +export const script = 'dnf remove -y podman'; diff --git a/src/main/podman/uninstall/pacmanUninstallScript.ts b/src/main/podman/uninstall/pacmanUninstallScript.ts new file mode 100644 index 000000000..5e238e2bf --- /dev/null +++ b/src/main/podman/uninstall/pacmanUninstallScript.ts @@ -0,0 +1 @@ +export const script = 'pacman -Rs podman --noconfirm'; diff --git a/src/main/podman/uninstall/uninstallOnLinux.ts b/src/main/podman/uninstall/uninstallOnLinux.ts index c3195c7bc..b3eb0986d 100644 --- a/src/main/podman/uninstall/uninstallOnLinux.ts +++ b/src/main/podman/uninstall/uninstallOnLinux.ts @@ -2,6 +2,15 @@ import { reportEvent } from '../../events'; import { execAwait } from '../../execHelper'; // import { app } from 'electron'; import logger from '../../logger'; +import { + type PackageManager, + findPackageManager, +} from '../../nn-auto-updater/findPackageManager.js'; +import { script as aptUninstallScript } from './aptUninstallScript'; +import { script as dnfUninstallScript } from './dnfUninstallScript'; +import { script as pacmanUninstallScript } from './pacmanUninstallScript'; +import { script as yumUninstallScript } from './yumUninstallScript'; +import { script as zypperUninstallScript } from './zypperUninstallScript'; /** * Uninstall podman by removing binaries and various configuration files @@ -12,29 +21,28 @@ const uninstallOnLinux = async (): Promise => { // Returns /Users/ (Ex. /Users/johns) // const userHome = app.getPath('home'); - // todo: delete more? - const foldersToDelete = [ - '/etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list', - // '/opt/podman', - // `${userHome}/.local/share/containers`, - // `${userHome}/.config/containers`, - // `${userHome}/.ssh/*podman*`, - // `${userHome}/.ssh/*nicenode*`, - // `/private/etc/paths.d/podman-pkg`, - // `/usr/local/podman`, - // `/Library/LaunchDaemons/*podman*`, - ]; // 1. (applies to mac, also linux?) This can throw return an error if a file or folder doesn't exist. // This is ok, because it will still delete the other folders that do exist. // 2. Combine sudo commands so that user is only prompted for password once - const rmCommand = ` - rm -rf ${foldersToDelete.join(' ')} - apt-get remove -y podman`; - const { stdout, stderr } = await execAwait(rmCommand, { + const pkgManager: PackageManager = await findPackageManager(); + let uninstallScript = ''; + if (pkgManager === 'dpkg') { + uninstallScript = aptUninstallScript; + } else if (pkgManager === 'dnf') { + uninstallScript = dnfUninstallScript; + } else if (pkgManager === 'pacman') { + uninstallScript = pacmanUninstallScript; + } else if (pkgManager === 'yum') { + uninstallScript = yumUninstallScript; + } else if (pkgManager === 'zypper') { + uninstallScript = zypperUninstallScript; + } + + const { stdout, stderr } = await execAwait(uninstallScript, { log: true, sudo: true, }); - logger.info(`${rmCommand} stdout, stderr ${stdout} ${stderr}`); + logger.info(`${uninstallScript} stdout, stderr ${stdout} ${stderr}`); return true; } catch (err: any) { logger.error(err); diff --git a/src/main/podman/uninstall/yumUninstallScript.ts b/src/main/podman/uninstall/yumUninstallScript.ts new file mode 100644 index 000000000..7ea1cf8ec --- /dev/null +++ b/src/main/podman/uninstall/yumUninstallScript.ts @@ -0,0 +1 @@ +export const script = 'yum remove -y podman'; diff --git a/src/main/podman/uninstall/zypperUninstallScript.ts b/src/main/podman/uninstall/zypperUninstallScript.ts new file mode 100644 index 000000000..c19858b2d --- /dev/null +++ b/src/main/podman/uninstall/zypperUninstallScript.ts @@ -0,0 +1,2 @@ +// biome-ignore lint/style/noUnusedTemplateLiteral: less diff for future changes +export const script = `zypper remove -y podman`; diff --git a/src/main/preload.ts b/src/main/preload.ts index 3265607cc..206b17a57 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -10,12 +10,11 @@ import { CHANNELS_ARRAY } from './messenger'; import type { AddNodePackageNodeService } from './nodePackageManager'; import type { ThemeSetting } from './state/settings'; -// todo: when moving from require to imports -// const isTest = process.env.NODE_ENV === 'test'; -// if (isTest) { -// console.log('NODE_ENV=TEST... requiring wdio-electron-service/main'); -// require('wdio-electron-service/preload'); -// } +const isTest = process.env.TEST === 'true'; +if (isTest && process.env.TEST_ENV === 'wdio') { + console.log('env.TEST=true... requiring wdio-electron-service/main'); + import('wdio-electron-service/preload'); +} contextBridge.exposeInMainWorld('electron', { SENTRY_DSN: process.env.SENTRY_DSN, diff --git a/src/renderer/Generics/redesign/ContentHeader/ContentHeader.tsx b/src/renderer/Generics/redesign/ContentHeader/ContentHeader.tsx index 2249e0c8f..28eff7687 100644 --- a/src/renderer/Generics/redesign/ContentHeader/ContentHeader.tsx +++ b/src/renderer/Generics/redesign/ContentHeader/ContentHeader.tsx @@ -76,7 +76,9 @@ export const ContentHeader = ({ )}
-
{title}
+
+ {title} +
{subtitle}
{textAlign === 'left' &&
} diff --git a/src/renderer/Generics/redesign/Modal/Modal.tsx b/src/renderer/Generics/redesign/Modal/Modal.tsx index 59c9f68c7..2cb7855ac 100644 --- a/src/renderer/Generics/redesign/Modal/Modal.tsx +++ b/src/renderer/Generics/redesign/Modal/Modal.tsx @@ -119,7 +119,10 @@ export const Modal = ({ > {route !== modalRoutes.alphaBuild && (
- + {modalTitle}
diff --git a/src/renderer/Generics/redesign/Stepper/Stepper.tsx b/src/renderer/Generics/redesign/Stepper/Stepper.tsx index 8086893b1..248be1404 100644 --- a/src/renderer/Generics/redesign/Stepper/Stepper.tsx +++ b/src/renderer/Generics/redesign/Stepper/Stepper.tsx @@ -24,6 +24,7 @@ const Stepper = ({ onChange, step, disabledSaveButton }: StepperProps) => {