From 96cd2f82d95f98d3850439731ad8adf06f53e31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Mon, 20 Nov 2023 15:31:10 +0100 Subject: [PATCH 1/7] feat: node endpoint configuration via persistent storage --- main/background.ts | 1 - main/config.ts | 21 +++++++++++++++++++++ renderer/store/configSlice.ts | 23 +++++++++++++++++++++++ types/config.ts | 9 +++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 main/config.ts create mode 100644 renderer/store/configSlice.ts create mode 100644 types/config.ts diff --git a/main/background.ts b/main/background.ts index e97a73b..f288b88 100644 --- a/main/background.ts +++ b/main/background.ts @@ -18,7 +18,6 @@ let mainWindow: BrowserWindow; (async () => { await app.whenReady(); - mainWindow = createWindow("main", { width: 1000, height: 600, diff --git a/main/config.ts b/main/config.ts new file mode 100644 index 0000000..cef60f7 --- /dev/null +++ b/main/config.ts @@ -0,0 +1,21 @@ +import { ipcMain } from "electron"; +import Store from "electron-store"; +import { ArweaveMinerUiConfig, ArweaveNodeConfig } from "../types/config"; + +const schema = { + nodes: { + type: "array" as const, + }, +}; + +const store = new Store({ schema }); + +ipcMain.on("configGetNodes", (): ArweaveNodeConfig[] => { + return store.get("nodes", []); +}); + +ipcMain.on("configAppendNode", (_, node: ArweaveNodeConfig): void => { + const currentNodes = store.get("nodes", []); + const newNodes = [...currentNodes, node]; + store.set("nodes", newNodes); +}); diff --git a/renderer/store/configSlice.ts b/renderer/store/configSlice.ts new file mode 100644 index 0000000..9371539 --- /dev/null +++ b/renderer/store/configSlice.ts @@ -0,0 +1,23 @@ +import { createSlice } from "@reduxjs/toolkit"; +import type { PayloadAction } from "@reduxjs/toolkit"; +import { ArweaveMinerUiConfig, ArweaveNodeConfig } from "../../types/config"; + +interface ConfigState { + nodes: ArweaveMinerUiConfig["nodes"]; +} + +const initialState = { nodes: [] } as ConfigState; + +const configSlice = createSlice({ + name: "config", + initialState, + reducers: { + appendNode(state, action: PayloadAction) { + window.ipc.send("configAppendNode", action.payload); + state.nodes.push(action.payload); + }, + }, +}); + +export const { appendNode } = configSlice.actions; +export default configSlice.reducer; diff --git a/types/config.ts b/types/config.ts new file mode 100644 index 0000000..0d62920 --- /dev/null +++ b/types/config.ts @@ -0,0 +1,9 @@ +export interface ArweaveNodeConfig { + host: string; + port: number; + protocol: string; +} + +export interface ArweaveMinerUiConfig { + nodes: ArweaveNodeConfig[]; +} From 8f92117ae4e097ccc03326986c4525e0647b62e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Mon, 20 Nov 2023 15:43:30 +0100 Subject: [PATCH 2/7] fix: deprecated api warnings --- renderer/pages/_app.tsx | 14 +++++++++----- renderer/store/metricsSlice.ts | 7 +++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/renderer/pages/_app.tsx b/renderer/pages/_app.tsx index a315aba..138b025 100644 --- a/renderer/pages/_app.tsx +++ b/renderer/pages/_app.tsx @@ -1,9 +1,13 @@ import { AppProps } from "next/app"; -import "../styles/globals.css"; +import { Provider } from "react-redux"; import { wrapper } from "../store"; +import "../styles/globals.css"; -function MyApp({ Component, pageProps }: AppProps) { - return ; +export default function ArweaveMinerUi({ Component, ...rest }: AppProps) { + const { store, props } = wrapper.useWrappedStore(rest); + return ( + + + + ); } - -export default wrapper.withRedux(MyApp); diff --git a/renderer/store/metricsSlice.ts b/renderer/store/metricsSlice.ts index 23cbd08..29a50b3 100644 --- a/renderer/store/metricsSlice.ts +++ b/renderer/store/metricsSlice.ts @@ -51,13 +51,12 @@ export const metricsSlice = createSlice({ }, }, - extraReducers: { - [HYDRATE]: (state, action) => { + extraReducers: (builder) => { + builder.addCase(HYDRATE, (state) => { return { ...state, - ...action.payload, }; - }, + }); }, }); From b537b080491a825912677336264133a5bea2af9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Mon, 20 Nov 2023 16:05:48 +0100 Subject: [PATCH 3/7] feat: add-miner modal boilerplate --- renderer/components/Navbar.tsx | 5 ++-- .../add-miner-button.tsx} | 9 +++--- .../components/add-miner/add-miner-modal.tsx | 28 +++++++++++++++++++ renderer/components/add-miner/add-miner.tsx | 14 ++++++++++ .../components/add-miner/use-add-miner.ts | 10 +++++++ 5 files changed, 58 insertions(+), 8 deletions(-) rename renderer/components/{WalletButton.tsx => add-miner/add-miner-button.tsx} (56%) create mode 100644 renderer/components/add-miner/add-miner-modal.tsx create mode 100644 renderer/components/add-miner/add-miner.tsx create mode 100644 renderer/components/add-miner/use-add-miner.ts diff --git a/renderer/components/Navbar.tsx b/renderer/components/Navbar.tsx index d65538a..b2f1e47 100644 --- a/renderer/components/Navbar.tsx +++ b/renderer/components/Navbar.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; import { useRouter } from "next/router"; -import WalletButton from "./WalletButton"; +import { AddMiner } from "./add-miner/add-miner"; import { ASSET } from "./Asset"; interface NavLink { @@ -67,8 +67,7 @@ export default function Navbar() {
- - + ); } diff --git a/renderer/components/add-miner/add-miner-modal.tsx b/renderer/components/add-miner/add-miner-modal.tsx new file mode 100644 index 0000000..94cfb8e --- /dev/null +++ b/renderer/components/add-miner/add-miner-modal.tsx @@ -0,0 +1,28 @@ +export function AddMinerModal({ onClose }: { onClose: () => void }) { + return ( +
+
+
+
+ {/* Modal Content */} + + +
+
+
+
+ ); +} diff --git a/renderer/components/add-miner/add-miner.tsx b/renderer/components/add-miner/add-miner.tsx new file mode 100644 index 0000000..a5f88e7 --- /dev/null +++ b/renderer/components/add-miner/add-miner.tsx @@ -0,0 +1,14 @@ +import { AddMinerButton } from "./add-miner-button"; +import { AddMinerModal } from "./add-miner-modal"; +import { useAddMiner } from "./use-add-miner"; + +export function AddMiner() { + const { isModalOpen, setIsModalOpen } = useAddMiner(); + + return ( + <> + setIsModalOpen(true)} /> + {isModalOpen && setIsModalOpen(false)} />} + + ); +} diff --git a/renderer/components/add-miner/use-add-miner.ts b/renderer/components/add-miner/use-add-miner.ts new file mode 100644 index 0000000..408eb86 --- /dev/null +++ b/renderer/components/add-miner/use-add-miner.ts @@ -0,0 +1,10 @@ +import { useState } from "react"; + +export const useAddMiner = () => { + const [isModalOpen, setIsModalOpen] = useState(false); + + return { + isModalOpen, + setIsModalOpen, + }; +}; From 17bd71c2c04395dd3882b72e797290ac49c00a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Tue, 21 Nov 2023 12:52:58 +0100 Subject: [PATCH 4/7] feat: configSlice that stores persistently node-cfg --- main/background.ts | 9 + main/config.ts | 39 +- main/helpers/create-window.ts | 4 +- main/preload.ts | 2 + package-lock.json | 474 +++++++++++------- package.json | 23 +- renderer/components/Charts/DataRelated.tsx | 6 +- renderer/components/Navbar.tsx | 14 +- .../components/add-miner/add-miner-modal.tsx | 95 +++- renderer/components/add-miner/add-miner.tsx | 33 +- .../components/add-miner/use-add-miner.ts | 53 +- renderer/layouts/MainLayout.tsx | 7 +- renderer/layouts/index.tsx | 1 - renderer/pages/dashboard.tsx | 6 +- renderer/pages/home.tsx | 4 +- renderer/store/configSlice.ts | 23 - renderer/store/configSlice/configSlice.ts | 31 ++ .../store/configSlice/configSliceHooks.ts | 7 + .../store/configSlice/configSliceSelectors.ts | 3 + renderer/store/index.ts | 13 +- .../store/{ => metricsSlice}/metricsSlice.ts | 4 +- .../{ => metricsSlice}/metricsSliceHooks.ts | 2 +- .../metricsSliceSelectors.ts} | 2 +- types/config.ts | 1 + 24 files changed, 603 insertions(+), 253 deletions(-) delete mode 100644 renderer/layouts/index.tsx delete mode 100644 renderer/store/configSlice.ts create mode 100644 renderer/store/configSlice/configSlice.ts create mode 100644 renderer/store/configSlice/configSliceHooks.ts create mode 100644 renderer/store/configSlice/configSliceSelectors.ts rename renderer/store/{ => metricsSlice}/metricsSlice.ts (94%) rename renderer/store/{ => metricsSlice}/metricsSliceHooks.ts (97%) rename renderer/store/{selectors.ts => metricsSlice/metricsSliceSelectors.ts} (94%) diff --git a/main/background.ts b/main/background.ts index f288b88..a87de78 100644 --- a/main/background.ts +++ b/main/background.ts @@ -18,6 +18,15 @@ let mainWindow: BrowserWindow; (async () => { await app.whenReady(); + // session.defaultSession.webRequest.onHeadersReceived((details, callback) => { + // callback({ + // responseHeaders: { + // ...details.responseHeaders, + // "Content-Security-Policy": ["script-src 'self' localhost:8888"], + // }, + // }); + // }); + mainWindow = createWindow("main", { width: 1000, height: 600, diff --git a/main/config.ts b/main/config.ts index cef60f7..0c06d76 100644 --- a/main/config.ts +++ b/main/config.ts @@ -1,21 +1,40 @@ -import { ipcMain } from "electron"; import Store from "electron-store"; import { ArweaveMinerUiConfig, ArweaveNodeConfig } from "../types/config"; const schema = { nodes: { type: "array" as const, + items: { + type: "object" as const, + properties: { + name: { + type: "string" as const, + }, + host: { + type: "string" as const, + }, + port: { + type: "number" as const, + }, + protocol: { + type: "string" as const, + }, + }, + required: ["name", "host", "port", "protocol"], + }, }, }; const store = new Store({ schema }); -ipcMain.on("configGetNodes", (): ArweaveNodeConfig[] => { - return store.get("nodes", []); -}); - -ipcMain.on("configAppendNode", (_, node: ArweaveNodeConfig): void => { - const currentNodes = store.get("nodes", []); - const newNodes = [...currentNodes, node]; - store.set("nodes", newNodes); -}); +export const configHandler = { + configGetNodes: () => { + console.log(store); + return store.get("nodes") || []; + }, + configAppendNode: (node: ArweaveNodeConfig) => { + const currentNodes = store.get("nodes", []); + const newNodes = [...currentNodes, node]; + store.set("nodes", newNodes); + }, +}; diff --git a/main/helpers/create-window.ts b/main/helpers/create-window.ts index c686dfd..445bd63 100644 --- a/main/helpers/create-window.ts +++ b/main/helpers/create-window.ts @@ -79,8 +79,10 @@ export const createWindow = ( ...state, ...options, webPreferences: { - nodeIntegration: false, + nodeIntegration: true, + nodeIntegrationInWorker: true, contextIsolation: true, + sandbox: false, ...options.webPreferences, }, }); diff --git a/main/preload.ts b/main/preload.ts index fd0535c..e09254f 100644 --- a/main/preload.ts +++ b/main/preload.ts @@ -1,4 +1,5 @@ import { contextBridge, ipcRenderer, IpcRendererEvent } from "electron"; +import { configHandler } from "./config"; import { SetMetricsStateActionPayload } from "../types/metrics"; ipcRenderer.on("metricsPush", (_event, msg) => { @@ -26,6 +27,7 @@ const handler = { ipcRenderer.removeListener(channel, subscription); }; }, + ...configHandler, }; contextBridge.exposeInMainWorld("ipc", handler); diff --git a/package-lock.json b/package-lock.json index 0ff4ff2..653e5e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,34 +11,37 @@ "license": "MIT", "dependencies": { "@reduxjs/toolkit": "^1.9.7", + "ajv": "^8.12.0", "arweave": "^1.14.4", - "electron-serve": "^1.1.0", + "electron-serve": "^1.2.0", "electron-store": "^8.1.0", "next-redux-wrapper": "^8.1.0", "parse-prometheus-text-format": "^1.1.1", + "ramda": "^0.29.1", "react-redux": "^8.1.3", "react-ui-scrollspy": "^2.3.0" }, "devDependencies": { - "@types/react": "^18.2.31", - "@types/react-dom": "^18.2.15", - "@typescript-eslint/eslint-plugin": "^6.9.0", - "@typescript-eslint/parser": "^6.9.0", + "@types/ramda": "^0.29.9", + "@types/react": "^18.2.38", + "@types/react-dom": "^18.2.16", + "@typescript-eslint/eslint-plugin": "^6.12.0", + "@typescript-eslint/parser": "^6.12.0", "autoprefixer": "^10.4.16", - "electron": "^26.2.2", + "electron": "^27.1.0", "electron-builder": "^24.6.4", - "eslint": "^8.52.0", + "eslint": "^8.54.0", "eslint-plugin-react": "^7.33.2", "husky": "^8.0.3", - "lint-staged": "^15.0.2", + "lint-staged": "^15.1.0", "next": "^12.3.4", "nextron": "^8.12.0", "postcss": "^8.4.31", - "prettier": "^3.0.3", + "prettier": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwindcss": "^3.3.5", - "typescript": "^5.2.2" + "typescript": "^5.3.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1986,6 +1989,37 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/@develar/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@develar/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/@develar/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@electron/asar": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.7.tgz", @@ -2265,9 +2299,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -2287,6 +2321,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2312,6 +2362,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2337,9 +2393,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", + "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2944,10 +3000,19 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz", "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==" }, + "node_modules/@types/ramda": { + "version": "0.29.9", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.29.9.tgz", + "integrity": "sha512-X3yEG6tQCWBcUAql+RPC/O1Hm9BSU+MXu2wJnCETuAgUlrEDwTA1kIOdEEE4YXDtf0zfQLHa9CCE7WYp9kqPIQ==", + "dev": true, + "dependencies": { + "types-ramda": "^0.29.6" + } + }, "node_modules/@types/react": { - "version": "18.2.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.31.tgz", - "integrity": "sha512-c2UnPv548q+5DFh03y8lEDeMfDwBn9G3dRwfkrxQMo/dOtRHUUO57k6pHvBIfH/VF4Nh+98mZ5aaSe+2echD5g==", + "version": "18.2.38", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.38.tgz", + "integrity": "sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2955,9 +3020,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.15", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz", - "integrity": "sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==", + "version": "18.2.16", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.16.tgz", + "integrity": "sha512-766c37araZ9vxtYs25gvY2wNdFWsT2ZiUvOd0zMhTaoGj6B911N8CKQWgXXJoPMLF3J82thpRqQA7Rf3rBwyJw==", "devOptional": true, "dependencies": { "@types/react": "*" @@ -2978,9 +3043,9 @@ "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==" }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/use-sync-external-store": { @@ -3006,16 +3071,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", - "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", + "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/type-utils": "6.9.0", - "@typescript-eslint/utils": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/type-utils": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3056,15 +3121,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", - "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", + "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4" }, "engines": { @@ -3084,13 +3149,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", + "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3101,13 +3166,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", - "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", + "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/utils": "6.12.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3128,9 +3193,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", + "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3141,13 +3206,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", + "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3183,17 +3248,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", - "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", + "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", "semver": "^7.5.4" }, "engines": { @@ -3223,12 +3288,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", + "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.12.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3461,14 +3526,13 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { @@ -3492,35 +3556,6 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/ansi-escapes": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", @@ -4593,26 +4628,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/conf/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/conf/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/conf/node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -4982,6 +4997,30 @@ "node": ">=8" } }, + "node_modules/dmg-license/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/dmg-license/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "optional": true + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -5045,9 +5084,9 @@ } }, "node_modules/electron": { - "version": "26.4.2", - "resolved": "https://registry.npmjs.org/electron/-/electron-26.4.2.tgz", - "integrity": "sha512-BOfQUOIvsq5NnssWOMqcZnA5M0ull620wvQoJq3WhXN1wJAsWu+cdjHvREyxnHbArPkV+F+x3YAi5Dt+UKoqhw==", + "version": "27.1.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-27.1.0.tgz", + "integrity": "sha512-XPdJiO475QJ8cx59/goWNNWnlV0vab+Ut3occymos7VDxkHV5mFrlW6tcGi+M3bW6gBfwpJocWMng8tw542vww==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -5174,9 +5213,15 @@ } }, "node_modules/electron-serve": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/electron-serve/-/electron-serve-1.1.0.tgz", - "integrity": "sha512-tQJBCbXKoKCfkBC143QCqnEtT1s8dNE2V+b/82NF6lxnGO/2Q3a3GSLHtKl3iEDQgdzTf9pH7p418xq2rXbz1Q==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/electron-serve/-/electron-serve-1.2.0.tgz", + "integrity": "sha512-zJG3wisMrDn2G/gnjrhyB074COvly1FnS0U7Edm8bfXLB8MYX7UtwR9/y2LkFreYjzQHm9nEbAfgCmF+9M9LHQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/electron-store": { "version": "8.1.0", @@ -5388,15 +5433,15 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.54.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5557,6 +5602,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5623,6 +5684,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -7237,10 +7304,9 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/json-schema-typed": { "version": "7.0.3", @@ -7349,9 +7415,9 @@ "dev": true }, "node_modules/lint-staged": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.2.tgz", - "integrity": "sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.1.0.tgz", + "integrity": "sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==", "dev": true, "dependencies": { "chalk": "5.3.0", @@ -7363,7 +7429,7 @@ "micromatch": "4.0.5", "pidtree": "0.6.0", "string-argv": "0.3.2", - "yaml": "2.3.3" + "yaml": "2.3.4" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -8815,9 +8881,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -8912,6 +8978,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ramda": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", + "integrity": "sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -9424,22 +9499,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/schema-utils/node_modules/ajv-keywords": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", @@ -9452,12 +9511,6 @@ "ajv": "^8.8.2" } }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -10151,6 +10204,37 @@ } } }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -10271,6 +10355,12 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "dev": true + }, "node_modules/tsconfig-paths": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", @@ -10392,10 +10482,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/types-ramda": { + "version": "0.29.6", + "resolved": "https://registry.npmjs.org/types-ramda/-/types-ramda-0.29.6.tgz", + "integrity": "sha512-VJoOk1uYNh9ZguGd3eZvqkdhD4hTGtnjRBUx5Zc0U9ftmnCgiWcSj/lsahzKunbiwRje1MxxNkEy1UdcXRCpYw==", + "dev": true, + "dependencies": { + "ts-toolbelt": "^9.6.0" + } + }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", + "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -10624,6 +10723,37 @@ "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -10786,9 +10916,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", - "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, "engines": { "node": ">= 14" diff --git a/package.json b/package.json index 8aca06a..b742a71 100644 --- a/package.json +++ b/package.json @@ -34,33 +34,36 @@ }, "dependencies": { "@reduxjs/toolkit": "^1.9.7", + "ajv": "^8.12.0", "arweave": "^1.14.4", - "electron-serve": "^1.1.0", + "electron-serve": "^1.2.0", "electron-store": "^8.1.0", "next-redux-wrapper": "^8.1.0", "parse-prometheus-text-format": "^1.1.1", + "ramda": "^0.29.1", "react-redux": "^8.1.3", "react-ui-scrollspy": "^2.3.0" }, "devDependencies": { - "@types/react": "^18.2.31", - "@types/react-dom": "^18.2.15", - "@typescript-eslint/eslint-plugin": "^6.9.0", - "@typescript-eslint/parser": "^6.9.0", + "@types/ramda": "^0.29.9", + "@types/react": "^18.2.38", + "@types/react-dom": "^18.2.16", + "@typescript-eslint/eslint-plugin": "^6.12.0", + "@typescript-eslint/parser": "^6.12.0", "autoprefixer": "^10.4.16", - "electron": "^26.2.2", + "electron": "^27.1.0", "electron-builder": "^24.6.4", - "eslint": "^8.52.0", + "eslint": "^8.54.0", "eslint-plugin-react": "^7.33.2", "husky": "^8.0.3", - "lint-staged": "^15.0.2", + "lint-staged": "^15.1.0", "next": "^12.3.4", "nextron": "^8.12.0", "postcss": "^8.4.31", - "prettier": "^3.0.3", + "prettier": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwindcss": "^3.3.5", - "typescript": "^5.2.2" + "typescript": "^5.3.2" } } diff --git a/renderer/components/Charts/DataRelated.tsx b/renderer/components/Charts/DataRelated.tsx index 69b8ebf..2f85803 100644 --- a/renderer/components/Charts/DataRelated.tsx +++ b/renderer/components/Charts/DataRelated.tsx @@ -1,5 +1,9 @@ import { BottomArrow, TopArrow } from "./Arrows"; -import { useDataPacked, useStorageAvailable, useWeaveSize } from "../../store/metricsSliceHooks"; +import { + useDataPacked, + useStorageAvailable, + useWeaveSize, +} from "../../store/metricsSlice/metricsSliceHooks"; export default function DataRelatedChart() { const { dataPacked } = useDataPacked(); diff --git a/renderer/components/Navbar.tsx b/renderer/components/Navbar.tsx index b2f1e47..9744f00 100644 --- a/renderer/components/Navbar.tsx +++ b/renderer/components/Navbar.tsx @@ -1,7 +1,11 @@ import Link from "next/link"; import { useRouter } from "next/router"; +import { useAppDispatch } from "../store"; import { AddMiner } from "./add-miner/add-miner"; import { ASSET } from "./Asset"; +import { getNodes } from "../store/configSlice/configSlice"; +import { useConfigNodes } from "../store/configSlice/configSliceHooks"; +import { useEffect } from "react"; interface NavLink { href: string; @@ -11,6 +15,14 @@ interface NavLink { export default function Navbar() { const router = useRouter(); + const dispatch = useAppDispatch(); + const nodes = useConfigNodes(); + + useEffect(() => { + dispatch(getNodes()); + }, [dispatch]); + + console.log({ nodes }); const links: NavLink[] = [ { @@ -67,7 +79,7 @@ export default function Navbar() {
- + +
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
diff --git a/renderer/components/add-miner/add-miner.tsx b/renderer/components/add-miner/add-miner.tsx index a5f88e7..46f6924 100644 --- a/renderer/components/add-miner/add-miner.tsx +++ b/renderer/components/add-miner/add-miner.tsx @@ -2,13 +2,38 @@ import { AddMinerButton } from "./add-miner-button"; import { AddMinerModal } from "./add-miner-modal"; import { useAddMiner } from "./use-add-miner"; -export function AddMiner() { - const { isModalOpen, setIsModalOpen } = useAddMiner(); +export function AddMiner({ withButton }: { withButton?: boolean }) { + const { + isModalOpen, + newMinerName, + newMinerHost, + newMinerPort, + newMinerProtocol, + handleAddMiner, + handleNewMinerNameChange, + handleNewMinerHostChange, + handleNewMinerPortChange, + handleNewMinerProtocolChange, + setIsModalOpen, + } = useAddMiner(); return ( <> - setIsModalOpen(true)} /> - {isModalOpen && setIsModalOpen(false)} />} + {withButton && setIsModalOpen(true)} />} + {isModalOpen && ( + setIsModalOpen(false)} + onAddMiner={handleAddMiner} + nameValue={newMinerName} + hostnameValue={newMinerHost} + portValue={newMinerPort} + protocolValue={newMinerProtocol} + onNameChange={handleNewMinerNameChange} + onHostnameChange={handleNewMinerHostChange} + onPortChange={handleNewMinerPortChange} + onProtocolChange={handleNewMinerProtocolChange} + /> + )} ); } diff --git a/renderer/components/add-miner/use-add-miner.ts b/renderer/components/add-miner/use-add-miner.ts index 408eb86..758ca51 100644 --- a/renderer/components/add-miner/use-add-miner.ts +++ b/renderer/components/add-miner/use-add-miner.ts @@ -1,10 +1,61 @@ -import { useState } from "react"; +import React, { useCallback, useState } from "react"; +import { useDispatch } from "react-redux"; +import { appendNode } from "../../store/configSlice/configSlice"; +import { ArweaveNodeConfig } from "../../../types/config"; export const useAddMiner = () => { + const dispatch = useDispatch(); const [isModalOpen, setIsModalOpen] = useState(false); + const [newMinerName, setNewMinerName] = useState(""); + const [newMinerHost, setNewMinerHost] = useState(""); + const [newMinerPort, setNewMinerPort] = useState(1984); + const [newMinerProtocol, setNewMinerProtocol] = useState("http"); + + const newMinerData: ArweaveNodeConfig = { + name: newMinerName, + host: newMinerHost, + port: newMinerPort, + protocol: newMinerProtocol, + }; + + const handleAddMiner = useCallback(() => { + dispatch(appendNode(newMinerData)); + setIsModalOpen(false); + }, [dispatch, newMinerData, setIsModalOpen]); + + const handleNewMinerNameChange = useCallback( + (event: React.ChangeEvent) => setNewMinerName(event.currentTarget.value), + [setNewMinerName], + ); + + const handleNewMinerHostChange = useCallback( + (event: React.ChangeEvent) => setNewMinerHost(event.currentTarget.value), + [setNewMinerHost], + ); + + const handleNewMinerPortChange = useCallback( + (event: React.ChangeEvent) => + !Number.isNaN(event.currentTarget.value) && + setNewMinerPort(Number(event.currentTarget.value)), + [setNewMinerPort], + ); + + const handleNewMinerProtocolChange = useCallback( + (event: React.ChangeEvent) => setNewMinerProtocol(event.currentTarget.value), + [setNewMinerProtocol], + ); return { isModalOpen, + newMinerName, + newMinerHost, + newMinerPort, + newMinerProtocol, + handleAddMiner, + handleNewMinerNameChange, + handleNewMinerHostChange, + handleNewMinerPortChange, + handleNewMinerProtocolChange, setIsModalOpen, }; }; diff --git a/renderer/layouts/MainLayout.tsx b/renderer/layouts/MainLayout.tsx index 0603491..58af74d 100644 --- a/renderer/layouts/MainLayout.tsx +++ b/renderer/layouts/MainLayout.tsx @@ -1,10 +1,11 @@ +import React from "react"; import Navbar from "../components/Navbar"; -interface Props { - children: React.ReactNode | React.ReactNodeArray; +interface MainLayoutProps { + children: React.ReactNode; } -export default function MainLayout({ children }: Props) { +export function MainLayout({ children }: MainLayoutProps) { return (
diff --git a/renderer/layouts/index.tsx b/renderer/layouts/index.tsx deleted file mode 100644 index 4bea620..0000000 --- a/renderer/layouts/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default as MainLayout } from "./MainLayout"; diff --git a/renderer/pages/dashboard.tsx b/renderer/pages/dashboard.tsx index 460938f..f6be723 100644 --- a/renderer/pages/dashboard.tsx +++ b/renderer/pages/dashboard.tsx @@ -1,10 +1,10 @@ import React, { useCallback, useEffect, useState } from "react"; import { useDispatch } from "react-redux"; import ScrollSpy from "react-ui-scrollspy"; -import { useEarnings, useHashRate } from "../store/metricsSliceHooks"; +import { useEarnings, useHashRate } from "../store/metricsSlice/metricsSliceHooks"; import DataRelatedChart from "../components/Charts/DataRelated"; -import { MainLayout } from "../layouts"; -import { setMetricsState } from "../store/metricsSlice"; +import { MainLayout } from "../layouts/MainLayout"; +import { setMetricsState } from "../store/metricsSlice/metricsSlice"; import { SetMetricsStateActionPayload } from "../../types/metrics"; interface MenuItems { diff --git a/renderer/pages/home.tsx b/renderer/pages/home.tsx index bedb18d..892b7dc 100644 --- a/renderer/pages/home.tsx +++ b/renderer/pages/home.tsx @@ -1,8 +1,8 @@ import React from "react"; -import { MainLayout } from "../layouts"; +import { MainLayout } from "../layouts/MainLayout"; import { useRouter } from "next/router"; import { useSelector } from "react-redux"; -import { selectMinorState } from "../store/metricsSlice"; +import { selectMinorState } from "../store/metricsSlice/metricsSlice"; export default function HomePage() { const router = useRouter(); diff --git a/renderer/store/configSlice.ts b/renderer/store/configSlice.ts deleted file mode 100644 index 9371539..0000000 --- a/renderer/store/configSlice.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createSlice } from "@reduxjs/toolkit"; -import type { PayloadAction } from "@reduxjs/toolkit"; -import { ArweaveMinerUiConfig, ArweaveNodeConfig } from "../../types/config"; - -interface ConfigState { - nodes: ArweaveMinerUiConfig["nodes"]; -} - -const initialState = { nodes: [] } as ConfigState; - -const configSlice = createSlice({ - name: "config", - initialState, - reducers: { - appendNode(state, action: PayloadAction) { - window.ipc.send("configAppendNode", action.payload); - state.nodes.push(action.payload); - }, - }, -}); - -export const { appendNode } = configSlice.actions; -export default configSlice.reducer; diff --git a/renderer/store/configSlice/configSlice.ts b/renderer/store/configSlice/configSlice.ts new file mode 100644 index 0000000..155cbc9 --- /dev/null +++ b/renderer/store/configSlice/configSlice.ts @@ -0,0 +1,31 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import type { PayloadAction } from "@reduxjs/toolkit"; +import { ArweaveMinerUiConfig, ArweaveNodeConfig } from "../../../types/config"; + +interface ConfigState { + nodes: ArweaveMinerUiConfig["nodes"]; +} + +const initialState = { nodes: [] } as ConfigState; + +export const configSlice = createSlice({ + name: "config", + initialState, + reducers: { + setNodes(state, action: PayloadAction) { + state.nodes = action.payload; + }, + appendNode(state, action: PayloadAction) { + window.ipc.configAppendNode(action.payload); + state.nodes.push(action.payload); + }, + }, +}); + +export const getNodes = createAsyncThunk("config/getNodes", async (_, { dispatch }) => { + const answer = window.ipc.configGetNodes(); + dispatch(configSlice.actions.setNodes(answer)); +}); + +export const { appendNode } = configSlice.actions; +export default configSlice.reducer; diff --git a/renderer/store/configSlice/configSliceHooks.ts b/renderer/store/configSlice/configSliceHooks.ts new file mode 100644 index 0000000..3beda4d --- /dev/null +++ b/renderer/store/configSlice/configSliceHooks.ts @@ -0,0 +1,7 @@ +import { useSelector } from "react-redux"; +import { equals } from "ramda"; +import { selectNodesFromConfig } from "./configSliceSelectors"; + +export const useConfigNodes = () => { + return useSelector(selectNodesFromConfig, equals); +}; diff --git a/renderer/store/configSlice/configSliceSelectors.ts b/renderer/store/configSlice/configSliceSelectors.ts new file mode 100644 index 0000000..b714454 --- /dev/null +++ b/renderer/store/configSlice/configSliceSelectors.ts @@ -0,0 +1,3 @@ +import { AppState } from "../index"; + +export const selectNodesFromConfig = (state: AppState) => state.config.nodes; diff --git a/renderer/store/index.ts b/renderer/store/index.ts index 156ad38..ec56c45 100644 --- a/renderer/store/index.ts +++ b/renderer/store/index.ts @@ -1,23 +1,32 @@ -import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit"; +import { Action, AnyAction, ThunkAction, ThunkDispatch, configureStore } from "@reduxjs/toolkit"; +import { useDispatch } from "react-redux"; +import thunkMiddleware from "redux-thunk"; import { createWrapper } from "next-redux-wrapper"; -import { metricsSlice } from "./metricsSlice"; +import { metricsSlice } from "./metricsSlice/metricsSlice"; +import { configSlice } from "./configSlice/configSlice"; export const makeStore = () => { return configureStore({ reducer: { + [configSlice.name]: configSlice.reducer, [metricsSlice.name]: metricsSlice.reducer, }, devTools: true, + middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(thunkMiddleware), }); }; export type AppStore = ReturnType; export type AppState = ReturnType; +export type AppThunkDispatch = ThunkDispatch; export type AppThunk = ThunkAction< ReturnType, AppState, unknown, Action >; +export type AppDispatch = AppStore["dispatch"]; + +export const useAppDispatch = () => useDispatch(); export const wrapper = createWrapper(makeStore); diff --git a/renderer/store/metricsSlice.ts b/renderer/store/metricsSlice/metricsSlice.ts similarity index 94% rename from renderer/store/metricsSlice.ts rename to renderer/store/metricsSlice/metricsSlice.ts index 29a50b3..53480c6 100644 --- a/renderer/store/metricsSlice.ts +++ b/renderer/store/metricsSlice/metricsSlice.ts @@ -1,7 +1,7 @@ import { createSlice } from "@reduxjs/toolkit"; import { HYDRATE } from "next-redux-wrapper"; -import { SetMetricsStateActionPayload } from "../../types/metrics"; -import { AppState } from "./index"; +import { SetMetricsStateActionPayload } from "../../../types/metrics"; +import { AppState } from "../index"; // Type for our state export interface MetricsSliceReducerState { diff --git a/renderer/store/metricsSliceHooks.ts b/renderer/store/metricsSlice/metricsSliceHooks.ts similarity index 97% rename from renderer/store/metricsSliceHooks.ts rename to renderer/store/metricsSlice/metricsSliceHooks.ts index 691d0d4..94a585f 100644 --- a/renderer/store/metricsSliceHooks.ts +++ b/renderer/store/metricsSlice/metricsSliceHooks.ts @@ -6,7 +6,7 @@ import { selectDataUnpacked, selectStorageAvailable, selectWeaveSize, -} from "./selectors"; +} from "./metricsSliceSelectors"; export const useHashRate = () => { return useSelector(selectHashRate, (prev, current) => { diff --git a/renderer/store/selectors.ts b/renderer/store/metricsSlice/metricsSliceSelectors.ts similarity index 94% rename from renderer/store/selectors.ts rename to renderer/store/metricsSlice/metricsSliceSelectors.ts index 259c4b0..19dbb19 100644 --- a/renderer/store/selectors.ts +++ b/renderer/store/metricsSlice/metricsSliceSelectors.ts @@ -1,4 +1,4 @@ -import { AppState } from "./index"; +import { AppState } from "../index"; export const selectHashRate = (state: AppState) => ({ hashRate: state.metrics.hashRate, diff --git a/types/config.ts b/types/config.ts index 0d62920..cc8c18b 100644 --- a/types/config.ts +++ b/types/config.ts @@ -1,4 +1,5 @@ export interface ArweaveNodeConfig { + name: string; host: string; port: number; protocol: string; From 8a8fc9da5ecf05d890ee1d0a1a27cb731811ed78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Tue, 21 Nov 2023 13:49:44 +0100 Subject: [PATCH 5/7] feat: add React import for ide detection --- renderer/components/Navbar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/renderer/components/Navbar.tsx b/renderer/components/Navbar.tsx index 9744f00..643911f 100644 --- a/renderer/components/Navbar.tsx +++ b/renderer/components/Navbar.tsx @@ -1,3 +1,4 @@ +import React from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { useAppDispatch } from "../store"; From 19d197935c70f5f0e9ddbfe40c15ef2569f8f4d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Tue, 21 Nov 2023 14:22:25 +0100 Subject: [PATCH 6/7] cleanup: use interface for modal props --- .../components/add-miner/add-miner-modal.tsx | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/renderer/components/add-miner/add-miner-modal.tsx b/renderer/components/add-miner/add-miner-modal.tsx index 96f5d15..f479b9c 100644 --- a/renderer/components/add-miner/add-miner-modal.tsx +++ b/renderer/components/add-miner/add-miner-modal.tsx @@ -1,5 +1,18 @@ import React from "react"; +interface AddMinerModalProps { + nameValue: string; + hostnameValue: string; + portValue: number; + protocolValue: string; + onClose: () => void; + onAddMiner: () => void; + onNameChange: (event: React.ChangeEvent) => void; + onHostnameChange: (event: React.ChangeEvent) => void; + onPortChange: (event: React.ChangeEvent) => void; + onProtocolChange: (event: React.ChangeEvent) => void; +} + export function AddMinerModal({ nameValue, hostnameValue, @@ -11,18 +24,7 @@ export function AddMinerModal({ onHostnameChange, onPortChange, onProtocolChange, -}: { - nameValue: string; - hostnameValue: string; - portValue: number; - protocolValue: string; - onClose: () => void; - onAddMiner: () => void; - onNameChange: (event: React.ChangeEvent) => void; - onHostnameChange: (event: React.ChangeEvent) => void; - onPortChange: (event: React.ChangeEvent) => void; - onProtocolChange: (event: React.ChangeEvent) => void; -}) { +}: AddMinerModalProps) { return (
Date: Tue, 21 Nov 2023 14:27:42 +0100 Subject: [PATCH 7/7] lint: import order --- renderer/components/DataRelated.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/renderer/components/DataRelated.tsx b/renderer/components/DataRelated.tsx index aaf266e..a653b99 100644 --- a/renderer/components/DataRelated.tsx +++ b/renderer/components/DataRelated.tsx @@ -1,3 +1,5 @@ +import React from "react"; +import { filesize } from "filesize/dist/filesize.esm.js"; import DataRelatedChart from "./Charts/DataRelated"; import { ASSET } from "./Asset"; import { @@ -5,8 +7,6 @@ import { useStorageAvailable, useWeaveSize, } from "../store/metricsSlice/metricsSliceHooks"; -import { filesize } from "filesize/dist/filesize.esm.js"; -import React from "react"; export default function DataRelated() { const { dataPacked } = useDataPacked();