diff --git a/app/launch/eslint.config.js b/app/launch/eslint.config.js
index e582619..d2a7049 100644
--- a/app/launch/eslint.config.js
+++ b/app/launch/eslint.config.js
@@ -1,15 +1,17 @@
import js from '@eslint/js'
import globals from 'globals'
-import reactPlugin from 'eslint-plugin-react'
import importPlugin from 'eslint-plugin-import'
+import reactHooksPlugin from 'eslint-plugin-react-hooks'
+import reactPlugin from 'eslint-plugin-react'
export default [
js.configs.recommended,
{
files: ['**/*.{js,jsx}'],
plugins: {
- react: reactPlugin,
import: importPlugin,
+ react: reactPlugin,
+ 'react-hooks': reactHooksPlugin,
},
languageOptions: {
ecmaVersion: 'latest',
@@ -30,9 +32,11 @@ export default [
...reactPlugin.configs.recommended.rules,
// React 17+ automatic JSX transform does not require React in scope
'react/react-in-jsx-scope': 'off',
+ 'react-hooks/rules-of-hooks': 'error',
+ 'react-hooks/exhaustive-deps': 'warn',
// Project does not use PropTypes
'react/prop-types': 'off',
- 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
+ 'no-unused-vars': ['error', { argsIgnorePattern: '^_', caughtErrors: 'none' }],
'no-case-declarations': 'warn',
'import/order': [
'error',
diff --git a/app/launch/package-lock.json b/app/launch/package-lock.json
index fc62f11..5b24a7c 100644
--- a/app/launch/package-lock.json
+++ b/app/launch/package-lock.json
@@ -26,9 +26,11 @@
"@testing-library/react": "^16.3.2",
"@vitejs/plugin-react": "^6.0.1",
"baseline-browser-mapping": "^2.10.0",
+ "cross-env": "^10.1.0",
"eslint": "^9.39.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-react": "^7.37.5",
+ "eslint-plugin-react-hooks": "^7.0.1",
"globals": "^17.6.0",
"jsdom": "^29.1.1",
"prettier": "^3.8.3",
@@ -718,6 +720,13 @@
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
+ "node_modules/@epic-web/invariant": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
+ "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
@@ -2977,6 +2986,24 @@
}
}
},
+ "node_modules/cross-env": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
+ "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@epic-web/invariant": "^1.0.0",
+ "cross-spawn": "^7.0.6"
+ },
+ "bin": {
+ "cross-env": "dist/bin/cross-env.js",
+ "cross-env-shell": "dist/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -3665,6 +3692,26 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
}
},
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz",
+ "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.24.4",
+ "@babel/parser": "^7.24.4",
+ "hermes-parser": "^0.25.1",
+ "zod": "^3.25.0 || ^4.0.0",
+ "zod-validation-error": "^3.5.0 || ^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0"
+ }
+ },
"node_modules/eslint-scope": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
@@ -4220,6 +4267,23 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
"node_modules/highlight.js": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
@@ -7293,24 +7357,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/yaml": {
- "version": "2.8.4",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz",
- "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "bin": {
- "yaml": "bin.mjs"
- },
- "engines": {
- "node": ">= 14.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/eemeli"
- }
- },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -7324,6 +7370,29 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/zod": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
+ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
+ "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ }
+ },
"node_modules/zustand": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz",
diff --git a/app/launch/package.json b/app/launch/package.json
index f76086c..475b8d4 100755
--- a/app/launch/package.json
+++ b/app/launch/package.json
@@ -2,6 +2,7 @@
"name": "app",
"version": "0.1.1",
"private": true,
+ "type": "module",
"homepage": ".",
"dependencies": {
"@emotion/react": "^11.14.0",
@@ -22,8 +23,10 @@
"@testing-library/react": "^16.3.2",
"@vitejs/plugin-react": "^6.0.1",
"baseline-browser-mapping": "^2.10.0",
+ "cross-env": "^10.1.0",
"eslint": "^9.39.4",
"eslint-plugin-import": "^2.32.0",
+ "eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react": "^7.37.5",
"globals": "^17.6.0",
"jsdom": "^29.1.1",
@@ -34,12 +37,12 @@
},
"scripts": {
"start": "vite",
- "start:local": "VITE_VERSION_FEED='http://localhost:8088' vite",
+ "start:local": "cross-env VITE_VERSION_FEED=http://localhost:8088/grails-version-feed.json vite",
"build": "vite build",
"preview": "vite preview",
"format": "prettier --write \"**/*.+(js|jsx|json|css|md)\"",
- "lint": "eslint './src/**/*.{js,jsx}'",
- "lint:fix": "eslint './src/**/*.{js,jsx}' --fix",
+ "lint": "eslint \"./src/**/*.{js,jsx}\"",
+ "lint:fix": "eslint \"./src/**/*.{js,jsx}\" --fix",
"test": "vitest run"
},
"browserslist": {
diff --git a/app/launch/src/components/Application/__tests__/Application.test.jsx b/app/launch/src/components/Application/__tests__/Application.test.jsx
index c69c215..9b87208 100644
--- a/app/launch/src/components/Application/__tests__/Application.test.jsx
+++ b/app/launch/src/components/Application/__tests__/Application.test.jsx
@@ -1,7 +1,7 @@
import React from 'react'
import { render } from '@testing-library/react'
-import { useAppStore } from '../../../state/store'
import ApplicationState from '../../../state/ApplicationState'
+import { useAppStore } from '../../../state/store'
import { App } from '../App'
@@ -15,5 +15,7 @@ it(`Application Launches`, () => {