Repository: open-edge-platform/geti
Pull request #184: ITEP-66300 Create monorepo config
Author: login: dwesolow
Labels: name: UI
name: ready for review
Created: 2025-05-09T12:41:22Z | Merged: 2025-05-14T12:57:44Z

## 📝 Description

ITEP-66300

This PR is the first part of the mono repo journey. It introduces four packages:
- `@geti/ui` - will store UI components that do not rely on geti details;
- `@geti/config` - stores basic typescript, eslint and jest config for unit tests.

In the next PR I'll work on moving geti ui components to `@geti/ui` package ([ITEP-66301).

<!--  
If the PR addresses a specific GitHub issue, include one of the following lines to enable auto-closing:
Fixes #<issue_number>
Closes #<issue_number>

If referencing an internal ticket (e.g. JIRA), include the ticket number instead:
JIRA: <project-key>-<ticket-number>

If there’s no related issue or ticket, you can skip this section.
-->

## ✨ Type of Change

Select the type of change your PR introduces:

- [ ] 🐞 **Bug fix** – Non-breaking change which fixes an issue
- [ ] 🚀 **New feature** – Non-breaking change which adds functionality
- [X] 🔨 **Refactor** – Non-breaking change which refactors the code base
- [ ] 💥 **Breaking change** – Changes that break existing functionality
- [ ] 📚 **Documentation update**
- [ ] 🔒 **Security update**
- [ ] 🧪 **Tests**

## 🧪 Testing Scenarios

Describe how the changes were tested and how reviewers can test them too:

- [ ] ✅ Tested manually
- [ ] 🤖 Run automated end-to-end tests


## ✅ Checklist

Before submitting the PR, ensure the following:

- [X] 🔍 PR title is clear and descriptive
- [ ] 📝 For internal contributors: If applicable, include the JIRA ticket number (e.g., ITEP-123456) in the PR **title**. Do **not** include full URLs
- [ ] 💬 I have commented my code, especially in hard-to-understand areas
- [ ] 📄 I have made corresponding changes to the documentation
- [ ] ✅ I have added tests that prove my fix is effective or my feature works



Diff:
diff --git a/web_ui/.dockerignore b/web_ui/.dockerignore
index ab01fcf638..f4f69ef708 100644
--- a/web_ui/.dockerignore
+++ b/web_ui/.dockerignore
@@ -14,3 +14,4 @@
 !nginx.conf
 !rsbuild.config.ts
 !dev-proxy.ts
+!packages
diff --git a/web_ui/Dockerfile b/web_ui/Dockerfile
index d2f4bb191f..25db711d60 100644
--- a/web_ui/Dockerfile
+++ b/web_ui/Dockerfile
@@ -28,6 +28,7 @@ WORKDIR ${LOCATION}
 
 COPY --link package.json ./
 COPY --link package-lock.json ./
+COPY --link packages/ packages/
 RUN npm ci --audit=false
 
 COPY --link ./eslint.config.js ./
diff --git a/web_ui/eslint.config.js b/web_ui/eslint.config.js
index 9b0308d1a9..051c820436 100644
--- a/web_ui/eslint.config.js
+++ b/web_ui/eslint.config.js
@@ -4,18 +4,9 @@
 import path from 'node:path';
 import { fileURLToPath } from 'node:url';
 
-import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
 import { FlatCompat } from '@eslint/eslintrc';
 import js from '@eslint/js';
-import typescriptEslint from '@typescript-eslint/eslint-plugin';
-import tsParser from '@typescript-eslint/parser';
-import header from 'eslint-plugin-header';
-import _import from 'eslint-plugin-import';
-import jest from 'eslint-plugin-jest';
-import jsxA11Y from 'eslint-plugin-jsx-a11y';
-import reactPlugin from 'eslint-plugin-react';
-import reactHooks from 'eslint-plugin-react-hooks';
-import globals from 'globals';
+import sharedEslintConfig from '@geti/config/lint';
 
 const filename = fileURLToPath(import.meta.url);
 const dirname = path.dirname(filename);
@@ -25,225 +16,8 @@ const compat = new FlatCompat({
     allConfig: js.configs.all,
 });
 
-// https://github.com/sindresorhus/globals/issues/239
-const GLOBALS_BROWSER_FIX = Object.assign({}, globals.browser, {
-    AudioWorkletGlobalScope: globals.browser['AudioWorkletGlobalScope '],
-});
-
-delete GLOBALS_BROWSER_FIX['AudioWorkletGlobalScope '];
-
-// https://github.com/Stuk/eslint-plugin-header/issues/57#issuecomment-2378485611
-header.rules.header.meta.schema = false;
-
 export default [
-    {
-        ignores: [
-            '**/build',
-            '**/coverage',
-            '**/node_modules',
-            '**/*.tsx.snap',
-            'src/assets\\(!/icons/**/index.ts)',
-            'src/opencv-types',
-            'src/__mocks__',
-            '**/dex_templates',
-            '**/oauth2_proxy_templates',
-            '**/public',
-            'src/core/server/generated/*',
-        ],
-    },
-    ...fixupConfigRules(
-        compat.extends(
-            'plugin:jsx-a11y/recommended',
-            'plugin:@typescript-eslint/recommended',
-            'plugin:import/recommended',
-            'plugin:import/typescript'
-        )
-    ),
-    {
-        files: ['src/**/*.tsx', 'src/**/*.ts'],
-        ...reactPlugin.configs.flat.recommended,
-    },
-    {
-        files: ['src/**/*.tsx', 'src/**/*.ts'],
-        plugins: {
-            'react-hooks': fixupPluginRules(reactHooks),
-        },
-        rules: {
-            ...reactHooks.configs.recommended.rules,
-            'react/jsx-props-no-spreading': ['off'],
-            'react/no-unknown-property': [
-                'error',
-                {
-                    ignore: ['transform-origin', 'onLoad'],
-                },
-            ],
-
-            'react/jsx-indent-props': ['error', 4],
-            'react-hooks/rules-of-hooks': 'error',
-            'react/require-default-props': 'off',
-            'react/prop-types': 'off',
-            'react/display-name': 'off',
-            'react/react-in-jsx-scope': 'off',
-            'react/jsx-filename-extension': [
-                2,
-                {
-                    extensions: ['.js', '.jsx', '.ts', '.tsx'],
-                },
-            ],
-            'react/default-props-match-prop-types': 'warn',
-            'react/no-unused-prop-types': 'warn',
-            'jsx-a11y/click-events-have-key-events': 'off',
-            'jsx-a11y/no-noninteractive-element-interactions': 'off',
-            'jsx-a11y/no-static-element-interactions': 'off',
-        },
-    },
-    {
-        plugins: {
-            import: fixupPluginRules(_import),
-            jest,
-            'jsx-a11y': fixupPluginRules(jsxA11Y),
-            '@typescript-eslint': fixupPluginRules(typescriptEslint),
-            header,
-        },
-        languageOptions: {
-            globals: {
-                ...GLOBALS_BROWSER_FIX,
-            },
-            parser: tsParser,
-            ecmaVersion: 11,
-            sourceType: 'module',
-
-            parserOptions: {
-                ecmaFeatures: {
-                    jsx: true,
-                },
-            },
-        },
-
-        settings: {
-            'import/resolver': {
-                node: {
-                    paths: ['src'],
-                    extensions: ['.js', '.jsx', '.ts', '.tsx'],
-                },
-
-                typescript: {
-                    alwaysTryTypes: true,
-                    project: './tsconfig.json',
-                },
-            },
-
-            react: {
-                version: 'detect',
-            },
-        },
-
-        rules: {
-            '@typescript-eslint/no-unused-expressions': [
-                'error',
-                {
-                    allowTernary: true,
-                    allowShortCircuit: true,
-                },
-            ],
-            '@typescript-eslint/no-duplicate-enum-values': ['off'],
-            'max-len': [
-                'error',
-                {
-                    code: 120,
-                    ignorePattern: '^import .*',
-                },
-            ],
-
-            'no-underscore-dangle': ['error'],
-
-            '@typescript-eslint/no-unused-vars': [
-                'error',
-                {
-                    args: 'all',
-                    argsIgnorePattern: '^_',
-                    caughtErrors: 'all',
-                    caughtErrorsIgnorePattern: '^_',
-                    destructuredArrayIgnorePattern: '^_',
-                    varsIgnorePattern: '^_',
-                    ignoreRestSiblings: true,
-                },
-            ],
-
-            'jest/no-disabled-tests': 'error',
-            'jest/no-focused-tests': 'error',
-            'jest/no-identical-title': 'error',
-            'jest/prefer-to-have-length': 'warn',
-            'jest/valid-expect': 'error',
-
-            'import/extensions': [
-                'error',
-                'ignorePackages',
-                {
-                    js: 'always',
-                    jsx: 'never',
-                    ts: 'never',
-                    tsx: 'never',
-                },
-            ],
-
-            'import/order': ['off'],
-
-            'no-restricted-imports': [
-                'error',
-                {
-                    name: '@adobe/react-spectrum',
-                    importNames: ['Button'],
-                    message: "Use 'Button' from shared folder instead.",
-                },
-                {
-                    name: '@adobe/react-spectrum',
-                    importNames: ['ActionButton'],
-                    message: "Use 'ActionButton' from shared folder instead.",
-                },
-            ],
-
-            'import/no-unresolved': [
-                2,
-                {
-                    ignore: ['opencv-types', 'OpenCVTypes', 'csstype', 'opencv'],
-                },
-            ],
-
-            'header/header': [
-                'warn',
-                'line',
-                [
-                    {
-                        pattern: ' Copyright \\(C\\) 2022-\\d{4} Intel Corporation',
-                        template: ' Copyright (C) 2022-2025 Intel Corporation',
-                    },
-                    ' LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE',
-                ],
-            ],
-
-            '@typescript-eslint/no-shadow': [
-                'warn',
-                {
-                    builtinGlobals: false,
-                    hoist: 'never',
-                },
-            ],
-
-            '@typescript-eslint/ban-ts-comment': 'warn',
-            'no-console': ['error', { allow: ['warn', 'error', 'time', 'timeEnd', 'info'] }],
-            'object-shorthand': ['error', 'always'],
-        },
-    },
-    {
-        files: ['**/*.test.tsx', '**/*.test.ts'],
-
-        rules: {
-            'max-len': 'off',
-            '@typescript-eslint/no-non-null-assertion': 'error',
-        },
-    },
-
+    ...sharedEslintConfig,
     ...compat.extends('plugin:playwright/playwright-test').map((config) => ({
         ...config,
         files: ['tests/features/**/*.ts', 'tests/utils/**/*.ts', 'tests/fixtures/**/*.ts', 'tests/e2e/**/*.ts'],
diff --git a/web_ui/jest.config.js b/web_ui/jest.config.js
new file mode 100644
index 0000000000..c5f751952b
--- /dev/null
+++ b/web_ui/jest.config.js
@@ -0,0 +1,6 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+import sharedConfig from '@geti/config/test';
+
+export default sharedConfig;
diff --git a/web_ui/jest.global.ts b/web_ui/jest.global.js
similarity index 100%
rename from web_ui/jest.global.ts
rename to web_ui/jest.global.js
diff --git a/web_ui/package-lock.json b/web_ui/package-lock.json
index 12ee8adfd6..a48cc02677 100644
--- a/web_ui/package-lock.json
+++ b/web_ui/package-lock.json
@@ -7,9 +7,14 @@
     "": {
       "name": "geti-ui",
       "version": "2.9.0",
+      "workspaces": [
+        "packages/ui",
+        "packages/config"
+      ],
       "dependencies": {
         "@adobe/react-spectrum": "^3.41.0",
         "@doodle3d/clipper-js": "^1.0.11",
+        "@geti/ui": "*",
         "@opentelemetry/api": "^1.9.0",
         "@opentelemetry/core": "^1.26.0",
         "@opentelemetry/exporter-metrics-otlp-http": "^0.53.0",
@@ -84,6 +89,7 @@
       "devDependencies": {
         "@apidevtools/swagger-cli": "^4.0.4",
         "@eslint/compat": "^1.2.8",
+        "@geti/config": "*",
         "@ianvs/prettier-plugin-sort-imports": "^4.4.1",
         "@mjackson/headers": "^0.10.0",
         "@playwright/test": "^1.51.1",
@@ -2891,6 +2897,14 @@
         "tslib": "^2.8.0"
       }
     },
+    "node_modules/@geti/config": {
+      "resolved": "packages/config",
+      "link": true
+    },
+    "node_modules/@geti/ui": {
+      "resolved": "packages/ui",
+      "link": true
+    },
     "node_modules/@headlessui/tailwindcss": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz",
@@ -14549,6 +14563,8 @@
     },
     "node_modules/eslint-plugin-header": {
       "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz",
+      "integrity": "sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==",
       "dev": true,
       "license": "MIT",
       "peerDependencies": {
@@ -25608,6 +25624,66 @@
         "type": "github",
         "url": "https://github.com/sponsors/wooorm"
       }
+    },
+    "packages/config": {
+      "name": "@geti/config",
+      "version": "1.0.0",
+      "devDependencies": {
+        "@types/node": "^22.15.3",
+        "typescript": "^5.7.2"
+      }
+    },
+    "packages/eslint-config": {
+      "name": "@geti/eslint-config",
+      "version": "1.0.0",
+      "extraneous": true,
+      "license": "ISC",
+      "devDependencies": {},
+      "peerDependencies": {
+        "@eslint/compat": "^1.2.8",
+        "@typescript-eslint/eslint-plugin": "^8.31.1",
+        "eslint": "^9.25.1",
+        "eslint-plugin-header": "^3.1.1",
+        "eslint-plugin-import": "^2.31.0",
+        "eslint-plugin-jest": "^28.11.0",
+        "eslint-plugin-jsx-a11y": "^6.10.2",
+        "eslint-plugin-react": "^7.37.5",
+        "eslint-plugin-react-hooks": "^5.2.0"
+      }
+    },
+    "packages/test-config": {
+      "name": "@geti/test-config",
+      "version": "1.0.0",
+      "extraneous": true,
+      "license": "ISC",
+      "peerDependencies": {
+        "jest": "^29.7.0"
+      }
+    },
+    "packages/typescript-config": {
+      "name": "@geti/typescript-config",
+      "version": "1.0.0",
+      "extraneous": true,
+      "license": "ISC",
+      "devDependencies": {},
+      "peerDependencies": {
+        "typescript": "^5.7.2"
+      }
+    },
+    "packages/ui": {
+      "name": "@geti/ui",
+      "version": "1.0.0",
+      "devDependencies": {
+        "@geti/config": "*",
+        "@testing-library/jest-dom": "^5.16.5",
+        "@testing-library/react": "^15.0.7",
+        "@testing-library/user-event": "^14.6.1",
+        "@types/jest": "^29.5.14",
+        "@types/node": "^22.15.3",
+        "eslint": "^9.25.1",
+        "jest": "^29.7.0",
+        "typescript": "^5.7.2"
+      }
     }
   }
 }
diff --git a/web_ui/package.json b/web_ui/package.json
index b448959452..07b38be1e9 100644
--- a/web_ui/package.json
+++ b/web_ui/package.json
@@ -79,7 +79,8 @@
     "web-vitals": "^4.2.4",
     "workbox-core": "^7.3.0",
     "yup": "^1.6.1",
-    "zipson": "^0.2.12"
+    "zipson": "^0.2.12",
+    "@geti/ui": "*"
   },
   "scripts": {
     "build": "rsbuild build --environment geti --environment admin",
@@ -96,17 +97,17 @@
     "find-deadcode": "npx knip",
     "format": "prettier --write --cache \"./src/**/*.{js,ts,jsx,tsx,css,scss,sass}\" \"tests/**/*.ts*\"",
     "format:check": "prettier --check --cache \"./src/**/*.{js,ts,jsx,tsx,css,scss,sass}\" \"tests/**/*.ts*\"",
-    "lint": "eslint \"src/**/*.ts*\" \"tests/**/*.ts*\" --max-warnings 0",
-    "lint:fix": "eslint --fix \"./src/**/*.ts*\" \"tests/**/*.ts*\"",
+    "lint": "eslint \"src/**/*.ts*\" \"tests/**/*.ts*\" --max-warnings 0 && npm run lint --workspace=@geti/ui",
+    "lint:fix": "eslint --fix \"./src/**/*.ts*\" \"tests/**/*.ts*\" && npm run lint:fix --workspace=@geti/ui",
     "preview": "rsbuild preview",
     "start": "rsbuild dev --environment dev",
     "test:component": "npx playwright test --config=playwright.config.ts",
     "test:component:ui": "npm run test:component -- --ui",
     "test:coverage": "npm test -- --coverage",
     "test:e2e": "npx playwright test --config=playwright.config.ts --project=e2e",
-    "test:unit": "jest --config jest.config.ts --watchAll=false",
-    "test:unit:watch": "jest --config jest.config.ts --watch",
-    "type-check": "tsc --noEmit"
+    "test:unit": "jest --config jest.config.js --watchAll=false && npm run test:unit --workspace=@geti/ui",
+    "test:unit:watch": "jest --config jest.config.js --watch",
+    "type-check": "tsc --noEmit && npm run type-check --workspace=@geti/ui"
   },
   "browserslist": {
     "production": [
@@ -170,9 +171,13 @@
     "openapi-typescript-fetch": "^2.1.0",
     "prettier": "^3.5.3",
     "ts-node": "^10.9.2",
-    "typescript": "^5.7.2"
+    "typescript": "^5.7.2",
+    "@geti/config": "*"
   },
   "overrides": {
     "lz-string": "github:pieroxy/lz-string#573d8e6ab49cab839143953f0970930c57bc0782"
-  }
+  },
+  "workspaces": [
+    "packages/*"
+  ]
 }
diff --git a/web_ui/packages/config/lint/eslint.config.js b/web_ui/packages/config/lint/eslint.config.js
new file mode 100644
index 0000000000..4b5c545626
--- /dev/null
+++ b/web_ui/packages/config/lint/eslint.config.js
@@ -0,0 +1,246 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
+import { FlatCompat } from '@eslint/eslintrc';
+import js from '@eslint/js';
+import typescriptEslint from '@typescript-eslint/eslint-plugin';
+import tsParser from '@typescript-eslint/parser';
+import header from 'eslint-plugin-header';
+import _import from 'eslint-plugin-import';
+import jest from 'eslint-plugin-jest';
+import jsxA11Y from 'eslint-plugin-jsx-a11y';
+import reactPlugin from 'eslint-plugin-react';
+import reactHooks from 'eslint-plugin-react-hooks';
+import globals from 'globals';
+
+const filename = fileURLToPath(import.meta.url);
+const dirname = path.dirname(filename);
+const compat = new FlatCompat({
+    baseDirectory: dirname,
+    recommendedConfig: js.configs.recommended,
+    allConfig: js.configs.all,
+});
+
+// https://github.com/sindresorhus/globals/issues/239
+const GLOBALS_BROWSER_FIX = Object.assign({}, globals.browser, {
+    AudioWorkletGlobalScope: globals.browser['AudioWorkletGlobalScope '],
+});
+
+delete GLOBALS_BROWSER_FIX['AudioWorkletGlobalScope '];
+
+// https://github.com/Stuk/eslint-plugin-header/issues/57#issuecomment-2378485611
+header.rules.header.meta.schema = false;
+
+export default [
+    {
+        ignores: [
+            '**/build',
+            '**/coverage',
+            '**/node_modules',
+            '**/*.tsx.snap',
+            'src/assets\\(!/icons/**/index.ts)',
+            'src/opencv-types',
+            'src/__mocks__',
+            '**/dex_templates',
+            '**/oauth2_proxy_templates',
+            '**/public',
+            'src/core/server/generated/*',
+        ],
+    },
+    ...fixupConfigRules(
+        compat.extends(
+            'plugin:jsx-a11y/recommended',
+            'plugin:@typescript-eslint/recommended',
+            'plugin:import/recommended',
+            'plugin:import/typescript'
+        )
+    ),
+    {
+        files: ['src/**/*.tsx', 'src/**/*.ts'],
+        ...reactPlugin.configs.flat.recommended,
+    },
+    {
+        files: ['src/**/*.tsx', 'src/**/*.ts'],
+        plugins: {
+            'react-hooks': fixupPluginRules(reactHooks),
+        },
+        rules: {
+            ...reactHooks.configs.recommended.rules,
+            'react/jsx-props-no-spreading': ['off'],
+            'react/no-unknown-property': [
+                'error',
+                {
+                    ignore: ['transform-origin', 'onLoad'],
+                },
+            ],
+
+            'react/jsx-indent-props': ['error', 4],
+            'react-hooks/rules-of-hooks': 'error',
+            'react/require-default-props': 'off',
+            'react/prop-types': 'off',
+            'react/display-name': 'off',
+            'react/react-in-jsx-scope': 'off',
+            'react/jsx-filename-extension': [
+                2,
+                {
+                    extensions: ['.js', '.jsx', '.ts', '.tsx'],
+                },
+            ],
+            'react/default-props-match-prop-types': 'warn',
+            'react/no-unused-prop-types': 'warn',
+            'jsx-a11y/click-events-have-key-events': 'off',
+            'jsx-a11y/no-noninteractive-element-interactions': 'off',
+            'jsx-a11y/no-static-element-interactions': 'off',
+        },
+    },
+    {
+        plugins: {
+            import: fixupPluginRules(_import),
+            jest,
+            'jsx-a11y': fixupPluginRules(jsxA11Y),
+            '@typescript-eslint': fixupPluginRules(typescriptEslint),
+            header,
+        },
+        languageOptions: {
+            globals: {
+                ...GLOBALS_BROWSER_FIX,
+            },
+            parser: tsParser,
+            ecmaVersion: 11,
+            sourceType: 'module',
+
+            parserOptions: {
+                ecmaFeatures: {
+                    jsx: true,
+                },
+            },
+        },
+
+        settings: {
+            'import/resolver': {
+                node: {
+                    paths: ['src'],
+                    extensions: ['.js', '.jsx', '.ts', '.tsx'],
+                },
+
+                typescript: {
+                    alwaysTryTypes: true,
+                    project: './tsconfig.json',
+                },
+            },
+
+            react: {
+                version: 'detect',
+            },
+        },
+
+        rules: {
+            '@typescript-eslint/no-unused-expressions': [
+                'error',
+                {
+                    allowTernary: true,
+                    allowShortCircuit: true,
+                },
+            ],
+            '@typescript-eslint/no-duplicate-enum-values': ['off'],
+            'max-len': [
+                'error',
+                {
+                    code: 120,
+                    ignorePattern: '^import .*',
+                },
+            ],
+
+            'no-underscore-dangle': ['error'],
+
+            '@typescript-eslint/no-unused-vars': [
+                'error',
+                {
+                    args: 'all',
+                    argsIgnorePattern: '^_',
+                    caughtErrors: 'all',
+                    caughtErrorsIgnorePattern: '^_',
+                    destructuredArrayIgnorePattern: '^_',
+                    varsIgnorePattern: '^_',
+                    ignoreRestSiblings: true,
+                },
+            ],
+
+            'jest/no-disabled-tests': 'error',
+            'jest/no-focused-tests': 'error',
+            'jest/no-identical-title': 'error',
+            'jest/prefer-to-have-length': 'warn',
+            'jest/valid-expect': 'error',
+
+            'import/extensions': [
+                'error',
+                'ignorePackages',
+                {
+                    js: 'always',
+                    jsx: 'never',
+                    ts: 'never',
+                    tsx: 'never',
+                },
+            ],
+
+            'import/order': ['off'],
+
+            'no-restricted-imports': [
+                'error',
+                {
+                    name: '@adobe/react-spectrum',
+                    importNames: ['Button'],
+                    message: "Use 'Button' from shared folder instead.",
+                },
+                {
+                    name: '@adobe/react-spectrum',
+                    importNames: ['ActionButton'],
+                    message: "Use 'ActionButton' from shared folder instead.",
+                },
+            ],
+
+            'import/no-unresolved': [
+                2,
+                {
+                    ignore: ['opencv-types', 'OpenCVTypes', '^@.*', 'csstype', 'opencv'],
+                },
+            ],
+
+            'header/header': [
+                'warn',
+                'line',
+                [
+                    {
+                        pattern: ' Copyright \\(C\\) 2022-\\d{4} Intel Corporation',
+                        template: ' Copyright (C) 2022-2025 Intel Corporation',
+                    },
+                    ' LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE',
+                ],
+            ],
+
+            '@typescript-eslint/no-shadow': [
+                'warn',
+                {
+                    builtinGlobals: false,
+                    hoist: 'never',
+                },
+            ],
+
+            '@typescript-eslint/ban-ts-comment': 'warn',
+            'no-console': ['error', { allow: ['warn', 'error', 'time', 'timeEnd', 'info'] }],
+            'object-shorthand': ['error', 'always'],
+        },
+    },
+    {
+        files: ['**/*.test.tsx', '**/*.test.ts'],
+
+        rules: {
+            'max-len': 'off',
+            '@typescript-eslint/no-non-null-assertion': 'error',
+        },
+    },
+];
diff --git a/web_ui/packages/config/package.json b/web_ui/packages/config/package.json
new file mode 100644
index 0000000000..f33f3abcab
--- /dev/null
+++ b/web_ui/packages/config/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "type": "module",
+  "devDependencies": {
+    "@types/node": "^22.15.3",
+    "typescript": "^5.7.2"
+  },
+  "exports": {
+    "./test": "./test/jest.config.js",
+    "./lint": "./lint/eslint.config.js",
+    "./typescript": "./typescript/tsconfig.base.json"
+  }
+}
diff --git a/web_ui/jest.config.ts b/web_ui/packages/config/test/jest.config.js
similarity index 72%
rename from web_ui/jest.config.ts
rename to web_ui/packages/config/test/jest.config.js
index 6388e45e2f..5cfb236f02 100644
--- a/web_ui/jest.config.ts
+++ b/web_ui/packages/config/test/jest.config.js
@@ -1,6 +1,12 @@
 // Copyright (C) 2022-2025 Intel Corporation
 // LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
 
+import { fileURLToPath } from 'node:url';
+import path from 'path';
+
+const pathUrl = fileURLToPath(import.meta.url);
+const dirname = path.dirname(pathUrl);
+
 export default {
     roots: ['<rootDir>/src'],
     collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
@@ -9,9 +15,9 @@ export default {
     testMatch: ['<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}', '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}'],
     testEnvironment: 'jsdom',
     transform: {
-        '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': '<rootDir>/config/jest/babelTransform.js',
-        '^.+\\.css$': '<rootDir>/config/jest/cssTransform.js',
-        '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': '<rootDir>/config/jest/fileTransform.js',
+        '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': path.resolve(dirname, '../../../config/jest/babelTransform.js'),
+        '^.+\\.css$': path.resolve(dirname, '../../../config/jest/cssTransform.js'),
+        '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': path.resolve(dirname, '../../../config/jest/fileTransform.js'),
     },
     transformIgnorePatterns: ['node_modules/?!(pretty-bytes)'],
     moduleNameMapper: {
@@ -41,5 +47,5 @@ export default {
             lines: 75,
         },
     },
-    globalSetup: './jest.global.ts',
+    globalSetup: path.resolve(dirname, './jest.global.js'),
 };
diff --git a/web_ui/packages/config/test/jest.global.js b/web_ui/packages/config/test/jest.global.js
new file mode 100644
index 0000000000..c090d0a5a1
--- /dev/null
+++ b/web_ui/packages/config/test/jest.global.js
@@ -0,0 +1,6 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+export default async () => {
+    process.env.TZ = 'UTC';
+};
diff --git a/web_ui/packages/config/typescript/tsconfig.base.json b/web_ui/packages/config/typescript/tsconfig.base.json
new file mode 100644
index 0000000000..e08259efe5
--- /dev/null
+++ b/web_ui/packages/config/typescript/tsconfig.base.json
@@ -0,0 +1,24 @@
+{
+  "compilerOptions": {
+    "target": "esnext",
+    "lib": [
+      "dom",
+      "dom.iterable",
+      "esnext"
+    ],
+    "allowJs": true,
+    "skipLibCheck": true,
+    "esModuleInterop": true,
+    "allowSyntheticDefaultImports": true,
+    "strict": true,
+    "forceConsistentCasingInFileNames": true,
+    "noFallthroughCasesInSwitch": true,
+    "module": "esnext",
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx",
+    "types": ["jest"],
+  },
+}
diff --git a/web_ui/packages/ui/eslint.config.js b/web_ui/packages/ui/eslint.config.js
new file mode 100644
index 0000000000..247fb189d1
--- /dev/null
+++ b/web_ui/packages/ui/eslint.config.js
@@ -0,0 +1,6 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+import sharedConfig from '@geti/config/lint';
+
+export default sharedConfig;
diff --git a/web_ui/packages/ui/jest.config.js b/web_ui/packages/ui/jest.config.js
new file mode 100644
index 0000000000..c5f751952b
--- /dev/null
+++ b/web_ui/packages/ui/jest.config.js
@@ -0,0 +1,6 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+import sharedConfig from '@geti/config/test';
+
+export default sharedConfig;
diff --git a/web_ui/packages/ui/package.json b/web_ui/packages/ui/package.json
new file mode 100644
index 0000000000..2ba2fea425
--- /dev/null
+++ b/web_ui/packages/ui/package.json
@@ -0,0 +1,24 @@
+{
+  "name": "@geti/ui",
+  "version": "1.0.0",
+  "description": "Contains UI representative components",
+  "main": "index.js",
+  "type": "module",
+  "devDependencies": {
+    "@types/node": "^22.15.3",
+    "@geti/config": "*",
+    "jest": "^29.7.0",
+    "@testing-library/jest-dom": "^5.16.5",
+    "@testing-library/react": "^15.0.7",
+    "@testing-library/user-event": "^14.6.1",
+    "@types/jest": "^29.5.14",
+    "eslint": "^9.25.1",
+    "typescript": "^5.7.2"
+  },
+  "scripts": {
+    "test:unit": "jest --config jest.config.js --watchAll=false",
+    "type-check": "tsc --noEmit -p tsconfig.json",
+    "lint": "eslint \"src/**/*.ts*\" --max-warnings 0",
+    "lint:fix": "eslint --fix \"./src/**/*.ts*\""
+  }
+}
diff --git a/web_ui/packages/ui/src/button/button.component.tsx b/web_ui/packages/ui/src/button/button.component.tsx
new file mode 100644
index 0000000000..17eaa15bbc
--- /dev/null
+++ b/web_ui/packages/ui/src/button/button.component.tsx
@@ -0,0 +1,8 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+import { FC, PropsWithChildren } from 'react';
+
+export const Button: FC<PropsWithChildren> = ({ children }) => {
+    return <button>{children}</button>;
+};
diff --git a/web_ui/packages/ui/src/button/button.test.tsx b/web_ui/packages/ui/src/button/button.test.tsx
new file mode 100644
index 0000000000..f22cce9a1e
--- /dev/null
+++ b/web_ui/packages/ui/src/button/button.test.tsx
@@ -0,0 +1,12 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+import { render, screen } from '@testing-library/react';
+
+import { Button } from './button.component';
+
+test('Button', () => {
+    render(<Button>Test</Button>);
+
+    expect(screen.getByRole('button', { name: 'Test' })).toBeInTheDocument();
+});
diff --git a/web_ui/packages/ui/src/setupTests.tsx b/web_ui/packages/ui/src/setupTests.tsx
new file mode 100644
index 0000000000..5d56e0fd14
--- /dev/null
+++ b/web_ui/packages/ui/src/setupTests.tsx
@@ -0,0 +1,4 @@
+// Copyright (C) 2022-2025 Intel Corporation
+// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
+
+import '@testing-library/jest-dom';
diff --git a/web_ui/packages/ui/tsconfig.json b/web_ui/packages/ui/tsconfig.json
new file mode 100644
index 0000000000..ed8706ef4e
--- /dev/null
+++ b/web_ui/packages/ui/tsconfig.json
@@ -0,0 +1,8 @@
+{
+  "extends": "@geti/config/typescript",
+  "compilerOptions": {
+    "baseUrl": "./",
+    "types": ["jest", "node"],
+  },
+  "include": ["./src"]
+}
diff --git a/web_ui/tsconfig.json b/web_ui/tsconfig.json
index 6572c9c0e9..0dd4f10d75 100644
--- a/web_ui/tsconfig.json
+++ b/web_ui/tsconfig.json
@@ -1,27 +1,8 @@
 {
+  "extends": "@geti/config/typescript",
   "compilerOptions": {
-    "target": "esnext",
-    "lib": [
-      "dom",
-      "dom.iterable",
-      "esnext"
-    ],
-    "allowJs": true,
-    "skipLibCheck": true,
-    "esModuleInterop": true,
-    "allowSyntheticDefaultImports": true,
-    "strict": true,
-    "forceConsistentCasingInFileNames": true,
-    "noFallthroughCasesInSwitch": true,
-    "module": "esnext",
-    "moduleResolution": "node",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "noEmit": true,
-    "jsx": "react-jsx",
-    "types": ["jest"],
     "paths": {
-      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"]
+      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"],
     }
   },
   "include": [


Reviews:
user: login: MarkRedeman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T13:22:11Z
user: login: MarkRedeman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T08:46:29Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T09:16:15Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T09:20:14Z
user: login: MarkRedeman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T16:03:05Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T06:47:35Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T06:48:33Z
user: login: jpggvilaca
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T07:30:29Z
user: login: jpggvilaca
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T07:31:53Z
user: login: jpggvilaca
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T07:32:10Z
user: login: jpggvilaca
body: Minor comments. LGTM but this will absolutely destroy my PR https://github.com/open-edge-platform/geti/pull/171 😭  
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T07:33:25Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T08:31:43Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T08:32:35Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T08:34:04Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T08:34:18Z
user: login: MarkRedeman
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T10:37:16Z
user: login: MarkRedeman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T10:40:13Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T10:49:21Z
user: login: pplaskie
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T10:58:08Z
user: login: jpggvilaca
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T06:49:46Z
user: login: jpggvilaca
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T06:49:50Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR establishes the foundation for the monorepo by introducing two new packages—@geti/ui and @geti/config—while refactoring the project to use shared configurations for testing and linting.  
- Added a basic UI component (Button) with corresponding tests in the UI package.  
- Updated Jest and ESLint configurations across the monorepo to import shared configurations from @geti/config.  
- Introduced package-specific configuration files for test setup and global settings.

### Reviewed Changes

Copilot reviewed 10 out of 20 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File                                                           | Description                                                             |
| -------------------------------------------------------------- | ----------------------------------------------------------------------- |
| web_ui/packages/ui/src/setupTests.tsx                           | New test setup file importing jest-dom for better assertions.           |
| web_ui/packages/ui/src/button/button.test.tsx                   | Added a test for the Button component to validate its rendering.        |
| web_ui/packages/ui/src/button/button.component.tsx              | Introduces a simple Button component with minimal implementation.       |
| web_ui/packages/ui/jest.config.ts                               | Refactored Jest config to use shared configuration from @geti/config.     |
| web_ui/packages/ui/eslint.config.js                             | Updated ESLint config to import shared lint settings from @geti/config.     |
| web_ui/packages/config/test/jest.global.ts                      | New global setup for Jest, ensuring tests run in the UTC timezone.        |
| web_ui/packages/config/test/jest.config.ts                      | Configures Jest for the config package with detailed settings and paths.  |
| web_ui/packages/config/lint/eslint.config.js                    | Replaces custom ESLint rules with shared configuration from @geti/config.   |
| web_ui/jest.config.ts                                            | Root Jest config now imports shared configuration.                      |
| web_ui/eslint.config.js                                          | Root ESLint config refactored to include shared settings and Playwright rules. |
</details>


<details>
<summary>Files not reviewed (10)</summary>

* **web_ui/.dockerignore**: Language not supported
* **web_ui/Dockerfile**: Language not supported
* **web_ui/package-lock.json**: Language not supported
* **web_ui/package.json**: Language not supported
* **web_ui/packages/config/package.json**: Language not supported
* **web_ui/packages/config/test/tsconfig.json**: Language not supported
* **web_ui/packages/config/typescript/tsconfig.base.json**: Language not supported
* **web_ui/packages/ui/package.json**: Language not supported
* **web_ui/packages/ui/tsconfig.json**: Language not supported
* **web_ui/tsconfig.json**: Language not supported
</details>



state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T06:50:17Z
user: login: jpggvilaca
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T07:23:44Z
user: login: jpggvilaca
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T10:47:14Z
user: login: dwesolow
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T12:24:17Z
user: login: pplaskie
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T12:30:32Z

Review comments:
diff_hunk: @@ -0,0 +1,26 @@
+{
+  "name": "@geti/ui",
+  "version": "1.0.0",
+  "description": "Contains UI representative components",
+  "main": "index.js",
+  "devDependencies": {
+    "@geti/typescript-config": "*",
+    "@geti/eslint-config": "*",
+    "@geti/test-config": "*",
+    "jest": "^29.7.0",
+    "@testing-library/jest-dom": "^5.16.5",
+    "@testing-library/react": "^15.0.7",
+    "@testing-library/user-event": "^14.6.1",
+    "@types/jest": "^29.5.14",
+    "eslint": "^9.25.1",
+    "typescript": "^5.7.2"
+  },
+  "scripts": {
+    "test": "jest --config jest.config.mjs --watchAll=false",
+    "type-check": "tsc --noEmit -p tsconfig.json",
+    "lint": "eslint --config eslint.config.mjs \"src/**/*.ts*\" --max-warnings 0",
+    "lint:fix": "eslint --fix --config eslint.config.mjs \"./src/**/*.ts*\""
path: web_ui/packages/ui/package.json
user: login: MarkRedeman
body: We will need to figure out how we want to include this into our CI setup. For now the quickest way might be to also call these scripts in the test scripts of the main `web_ui/package.json`.
Later we could consider using NX so that it forwards the test scripts to every package we aim to end up with.
created_at: 2025-05-09T13:22:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "description": "",
+  "exports": {
+    "./test": "./test/jest.config.mjs",
+    "./lint": "./lint/eslint.config.mjs",
+    "./typescript": "./typescript/tsconfig.base.json"
path: web_ui/packages/config/package.json
user: login: MarkRedeman
body: At first glance it wasn't immediately abvious to me how the other packages were able to import from these files, but I guess that's what the exports file does.
I'm wondering if it might be easier if we name these the same, i..e `import config from '@geti/config/lint/eslint.config.ts` instead? Or if we could add a single `index.ts` file as an entrypoint to the package?

This isn't super important for the config package as that's something we will only look at once in a while. But I think the way we export for say the ui package will be important.
created_at: 2025-05-12T08:46:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "description": "",
+  "exports": {
+    "./test": "./test/jest.config.mjs",
+    "./lint": "./lint/eslint.config.mjs",
+    "./typescript": "./typescript/tsconfig.base.json"
path: web_ui/packages/config/package.json
user: login: dwesolow
body: Yes, I'd liket o add barrel file for the `ui` package but for the config package I don't think it's important. When u hover over the import path like `import sharedConfig from @geti/core/lint` it shows u the exact path.
created_at: 2025-05-12T09:16:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,26 @@
+{
+  "name": "@geti/ui",
+  "version": "1.0.0",
+  "description": "Contains UI representative components",
+  "main": "index.js",
+  "devDependencies": {
+    "@geti/typescript-config": "*",
+    "@geti/eslint-config": "*",
+    "@geti/test-config": "*",
+    "jest": "^29.7.0",
+    "@testing-library/jest-dom": "^5.16.5",
+    "@testing-library/react": "^15.0.7",
+    "@testing-library/user-event": "^14.6.1",
+    "@types/jest": "^29.5.14",
+    "eslint": "^9.25.1",
+    "typescript": "^5.7.2"
+  },
+  "scripts": {
+    "test": "jest --config jest.config.mjs --watchAll=false",
+    "type-check": "tsc --noEmit -p tsconfig.json",
+    "lint": "eslint --config eslint.config.mjs \"src/**/*.ts*\" --max-warnings 0",
+    "lint:fix": "eslint --fix --config eslint.config.mjs \"./src/**/*.ts*\""
path: web_ui/packages/ui/package.json
user: login: dwesolow
body: Updated
created_at: 2025-05-12T09:20:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,9 +7,17 @@
     "": {
       "name": "geti-ui",
       "version": "2.9.0",
+      "workspaces": [
+        "packages/ui",
+        "packages/eslint-config",
+        "packages/typescript-config",
+        "packages/test-config",
path: web_ui/package-lock.json
user: login: MarkRedeman
body: Should these be removed? I think you may need to run `npm install` once more to make sure the lock file doesn't include the previous configuration.
created_at: 2025-05-12T15:57:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,9 +7,17 @@
     "": {
       "name": "geti-ui",
       "version": "2.9.0",
+      "workspaces": [
+        "packages/ui",
+        "packages/eslint-config",
+        "packages/typescript-config",
+        "packages/test-config",
path: web_ui/package-lock.json
user: login: dwesolow
body: Yeah, they should be removed. Let me check it once again.
created_at: 2025-05-13T06:47:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,9 +7,17 @@
     "": {
       "name": "geti-ui",
       "version": "2.9.0",
+      "workspaces": [
+        "packages/ui",
+        "packages/eslint-config",
+        "packages/typescript-config",
+        "packages/test-config",
path: web_ui/package-lock.json
user: login: dwesolow
body: Updated
created_at: 2025-05-13T06:48:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -95,17 +96,17 @@
     "find-deadcode": "npx knip",
     "format": "prettier --write --cache \"./src/**/*.{js,ts,jsx,tsx,css,scss,sass,mjs}\" \"tests/**/*.ts*\"",
     "format:check": "prettier --check --cache \"./src/**/*.{js,ts,jsx,tsx,css,scss,sass,mjs}\" \"tests/**/*.ts*\"",
-    "lint": "eslint \"src/**/*.ts*\" \"tests/**/*.ts*\" --max-warnings 0",
-    "lint:fix": "eslint --fix \"./src/**/*.ts*\" \"tests/**/*.ts*\"",
+    "lint": "eslint \"src/**/*.ts*\" \"tests/**/*.ts*\" --max-warnings 0 && npm run lint --workspace=@geti/ui",
path: web_ui/package.json
user: login: jpggvilaca
body: wouldnt it be more suitable to run `&& npm run link --workspaces` ? Or else this script wont scale well with more packages
created_at: 2025-05-13T07:30:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "devDependencies": {},
path: web_ui/packages/config/package.json
user: login: jpggvilaca
body: can we get rid of unnecessary keys? Or are they required?
created_at: 2025-05-13T07:31:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
path: web_ui/packages/config/package.json
user: login: jpggvilaca
body: let's add author and description as well. Intel Corporation as author i guess
created_at: 2025-05-13T07:32:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -95,17 +96,17 @@
     "find-deadcode": "npx knip",
     "format": "prettier --write --cache \"./src/**/*.{js,ts,jsx,tsx,css,scss,sass,mjs}\" \"tests/**/*.ts*\"",
     "format:check": "prettier --check --cache \"./src/**/*.{js,ts,jsx,tsx,css,scss,sass,mjs}\" \"tests/**/*.ts*\"",
-    "lint": "eslint \"src/**/*.ts*\" \"tests/**/*.ts*\" --max-warnings 0",
-    "lint:fix": "eslint --fix \"./src/**/*.ts*\" \"tests/**/*.ts*\"",
+    "lint": "eslint \"src/**/*.ts*\" \"tests/**/*.ts*\" --max-warnings 0 && npm run lint --workspace=@geti/ui",
path: web_ui/package.json
user: login: dwesolow
body: We don't have those scripts in the `@geti/config`. We can either add them there with `echo "Error: no test specified" && exit 1" or be specific here with the workspaces names.
created_at: 2025-05-13T08:31:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "devDependencies": {},
path: web_ui/packages/config/package.json
user: login: dwesolow
body: it was there by default when I generated a package but I think it does not impact anything there.
created_at: 2025-05-13T08:32:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "devDependencies": {},
path: web_ui/packages/config/package.json
user: login: dwesolow
body: Updated
created_at: 2025-05-13T08:34:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+{
+  "name": "@geti/config",
+  "version": "1.0.0",
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
path: web_ui/packages/config/package.json
user: login: dwesolow
body: Removed it since we don't have it in the main `package.json`.
created_at: 2025-05-13T08:34:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,23 @@
+{
+  "name": "@geti/ui",
+  "version": "1.0.0",
+  "description": "Contains UI representative components",
+  "main": "index.js",
path: web_ui/packages/ui/package.json
user: login: MarkRedeman
body: One additional thing to consider after #171 is merged is that we probably should change each package json to be a module in itself as well.
created_at: 2025-05-13T10:40:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,23 @@
+{
+  "name": "@geti/ui",
+  "version": "1.0.0",
+  "description": "Contains UI representative components",
+  "main": "index.js",
path: web_ui/packages/ui/package.json
user: login: dwesolow
body: Yeah, that's my plan :).
created_at: 2025-05-13T10:49:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,14 +2,15 @@
   "extends": "@geti/config/typescript",
   "compilerOptions": {
     "paths": {
-      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"]
+      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"],
path: web_ui/tsconfig.json
user: login: jpggvilaca
body: np: leftover comma?
created_at: 2025-05-14T06:49:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,16 @@
 {
+  "extends": "@geti/config/typescript",
   "compilerOptions": {
-    "target": "esnext",
-    "lib": [
-      "dom",
-      "dom.iterable",
-      "esnext"
-    ],
-    "allowJs": true,
-    "skipLibCheck": true,
-    "esModuleInterop": true,
-    "allowSyntheticDefaultImports": true,
-    "strict": true,
-    "forceConsistentCasingInFileNames": true,
-    "noFallthroughCasesInSwitch": true,
-    "module": "esnext",
-    "moduleResolution": "node",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "noEmit": true,
-    "jsx": "react-jsx",
-    "types": ["jest"],
     "paths": {
-      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"]
+      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"],
     }
   },
   "include": [
     "src",
     "tests",
     "rsbuild.config.ts",
     "dev-proxy.ts",
+    "jest.config.ts"
path: web_ui/tsconfig.json
user: login: jpggvilaca
body: should we add this one here?
created_at: 2025-05-14T07:23:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,34 +1,16 @@
 {
+  "extends": "@geti/config/typescript",
   "compilerOptions": {
-    "target": "esnext",
-    "lib": [
-      "dom",
-      "dom.iterable",
-      "esnext"
-    ],
-    "allowJs": true,
-    "skipLibCheck": true,
-    "esModuleInterop": true,
-    "allowSyntheticDefaultImports": true,
-    "strict": true,
-    "forceConsistentCasingInFileNames": true,
-    "noFallthroughCasesInSwitch": true,
-    "module": "esnext",
-    "moduleResolution": "node",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "noEmit": true,
-    "jsx": "react-jsx",
-    "types": ["jest"],
     "paths": {
-      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"]
+      "opencv": ["./public/assets/opencv/4.9.0/opencv.js"],
     }
   },
   "include": [
     "src",
     "tests",
     "rsbuild.config.ts",
     "dev-proxy.ts",
+    "jest.config.ts"
path: web_ui/tsconfig.json
user: login: dwesolow
body: outdated
created_at: 2025-05-14T12:24:17Z
author_association: CONTRIBUTOR

PR comments:
user: login: MarkRedeman
created_at: 2025-05-09T13:08:28Z
body: > @geti/typescript-config - stores basic tsconfig;
> @geti/eslint-config - stores basic eslint config;
> @geti/test-config - stores basic jest config for unit tests.

What do you think of combining these into a single config package?
author_association: CONTRIBUTOR
user: login: dwesolow
created_at: 2025-05-09T13:26:43Z
body: > > @geti/typescript-config - stores basic tsconfig;
> > @geti/eslint-config - stores basic eslint config;
> > @geti/test-config - stores basic jest config for unit tests.
> 
> What do you think of combining these into a single config package?

I think it's better (at least for now) to keep them separate because not every package/app might require test (theoretically ofc). IMO it won't be a big problem to combine them later.
author_association: CONTRIBUTOR
user: login: dwesolow
created_at: 2025-05-12T09:22:09Z
body: > > @geti/typescript-config - stores basic tsconfig;
> > @geti/eslint-config - stores basic eslint config;
> > @geti/test-config - stores basic jest config for unit tests.
> 
> What do you think of combining these into a single config package?

Yeah, that's fine. Combined.
author_association: CONTRIBUTOR