Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions frontend/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
npmMinimalAgeGate: "3d"
npmPreapprovedPackages:
- typescript
- eslint

enableScripts: true

nodeLinker: node-modules

# react-scripts@5.0.1 bundles eslint-config-react-app@7.0.1 and eslint-webpack-plugin@3.x,
# both of which declare eslint: ^8 as peer deps (non-overlapping with our eslint 9).
# eslint-config-react-app is never imported by this project's eslint.config.mjs, and
# DISABLE_ESLINT_PLUGIN=true is set in build/devserver scripts so the webpack eslint
# integration is fully disabled. This is a known, intentional mismatch.
# TODO: Remove this filter once react-scripts is replaced with Vite.
logFilters:
- code: YN0060
text: "eslint-config-react-app"
level: discard
6 changes: 3 additions & 3 deletions frontend/bin/write-version-file.cjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env node

const fse = require('fs-extra');
const fs = require('fs');

let packageData = JSON.parse(fse.readFileSync('package.json'));
fse.writeFileSync(
let packageData = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
fs.writeFileSync(
'public/version.json',
JSON.stringify({ version: packageData.version }),
);
4 changes: 2 additions & 2 deletions frontend/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { defineConfig } from "cypress";
export default defineConfig({
component: {
devServer: {
framework: "create-react-app",
bundler: "webpack",
framework: "react",
bundler: "vite",
},
specPattern: "src/**/*.cy.{js,jsx,cjs,mjs,ts,tsx}",
excludeSpecPattern: "**/node_modules/**",
Expand Down
17 changes: 1 addition & 16 deletions frontend/docker/Dockerfile.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ ENV COREPACK_NPM_REGISTRY=${COREPACK_NPM_REGISTRY}
# not for the production build, and it consumes ~300 MB of memory/disk.
ENV CYPRESS_INSTALL_BINARY=0

# Constrain the V8 heap so webpack/react-scripts cannot grow past the
# Quay.io builder's memory limit and get OOM-killed.
# NOTE: once react-scripts is replaced with Vite, this can be removed — Vite
# is not memory-hungry and does not need a V8 heap override.
ENV NODE_OPTIONS="--max-old-space-size=3072"

# Copy package metadata and lockfile first for better layer caching.
# Changes to source code won't invalidate the dependency install layer.
COPY --chown=1001:0 .yarnrc.yml package.json yarn.lock ./
Expand Down Expand Up @@ -89,27 +83,19 @@ RUN if [ -n "${NPM_REGISTRY}" ]; then \
# Copy the rest of the source code (bin/ needed for build script)
COPY --chown=1001:0 . .

# CI=false suppresses react-scripts/webpack treating warnings as errors.
# GENERATE_SOURCEMAP=false saves memory and time during the webpack build.
# NOTE: both vars are react-scripts/CRA-specific and can be removed once
# the project migrates to Vite.
ENV NODE_ENV=production
RUN CI=false GENERATE_SOURCEMAP=false yarn build
RUN yarn build

# Second stage: minimal runtime image containing only the compiled static
# assets and the 'serve' binary. No node_modules are carried over from the
# builder — the runtime does not need the full dependency tree.
#
# When react-scripts is replaced with Vite, the only change needed here is
# updating the COPY source path from 'build' to 'dist'.
#
# See: https://catalog.redhat.com/en/software/containers/ubi9/nodejs-22-minimal/664330aa459a2d3c807ccea9
FROM registry.access.redhat.com/ubi9/nodejs-22-minimal:1-1783399267

WORKDIR /opt/app-root/src

# Copy only the compiled static files from the builder stage.
# NOTE: update 'build' → 'dist' when migrating to Vite.
COPY --from=builder --chown=1001:0 /opt/app-root/src/build /opt/app-root/src/build

# Install the static-file server. 'serve' is the only runtime dependency;
Expand Down Expand Up @@ -138,5 +124,4 @@ ENTRYPOINT ["/opt/app-root/bin/entrypoint.sh"]

# Serve the static build directory on port 8080.
# -s enables SPA routing (equivalent to nginx try_files $uri /index.html).
# NOTE: update 'build' → 'dist' when migrating to Vite.
CMD ["serve", "-s", "build", "-l", "tcp://0.0.0.0:8080"]
22 changes: 0 additions & 22 deletions frontend/docker/docker-entrypoint.sh

This file was deleted.

40 changes: 0 additions & 40 deletions frontend/docker/nginx.conf

This file was deleted.

84 changes: 28 additions & 56 deletions frontend/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
// eslint.config.mjs
import reactPlugin from 'eslint-plugin-react';
import eslintReact from '@eslint-react/eslint-plugin';
import unusedImports from 'eslint-plugin-unused-imports';
import globals from 'globals';
import babelParser from '@babel/eslint-parser';
import { defineConfig, globalIgnores } from 'eslint/config';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import js from '@eslint/js';
import pluginCypress from 'eslint-plugin-cypress/flat';
import eslintPluginJsxA11y from 'eslint-plugin-jsx-a11y';
import pluginCypress from 'eslint-plugin-cypress';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';

export default defineConfig([
Expand All @@ -16,74 +14,44 @@ export default defineConfig([
'Ignore build dir and node_modules',
),
js.configs.recommended,
reactPlugin.configs.flat.recommended,
reactPlugin.configs.flat['jsx-runtime'],
eslintPluginJsxA11y.flatConfigs.recommended,
// TODO: Re-enable eslint-plugin-jsx-a11y when ESLint 10 support is released
// Tracking: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/1075
pluginCypress.configs.recommended,
// Global settings for React
{
settings: {
react: {
version: '18.3.1',
},
},
},
{
files: ['src/**/*', 'cypress/**/*', 'bin/**/*'],
extends: [eslintReact.configs.recommended],
plugins: {
'unused-imports': unusedImports, // not flat config compatible
'unused-imports': unusedImports,
'react-hooks': reactHooksPlugin,
},
linterOptions: {
reportUnusedDisableDirectives: 'error',
},
languageOptions: {
...reactPlugin.configs.flat.recommended.languageOptions,
globals: {
...globals.browser,
...globals.node,
...globals.cypress,
process: 'readonly', // Explicitly define process for build-time env vars
es2020: true,
},
parser: babelParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
requireConfigFile: false,
plugins: [
'@babel/plugin-transform-class-properties',
'@babel/plugin-transform-private-methods',
'@babel/plugin-syntax-jsx',
'@babel/plugin-syntax-flow',
],
babelOptions: {
presets: [
'@babel/preset-flow',
'@babel/preset-env',
'@babel/preset-react',
],
},
},
},
rules: {
'react/jsx-curly-brace-presence': [
'error',
{
props: 'never',
children: 'never',
},
],
'react/react-in-jsx-scope': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'@eslint-react/component-hook-factories': 'warn',
'@eslint-react/no-nested-component-definitions': 'warn',
'@eslint-react/no-access-state-in-setstate': 'warn',
camelcase: 'off',
quotes: ['warn', 'single'],
'no-duplicate-imports': 'error',
'no-unused-vars': 'off', // Turn off base rule in favor of unused-imports
'no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'error',
},
},
Expand All @@ -102,33 +70,37 @@ export default defineConfig([
],
},
},
// Specific configuration for service-worker.js to handle process.env
{
files: ['src/pages/service-worker.js'],
languageOptions: {
globals: {
...globals.browser,
process: 'readonly', // Allow process for build-time environment variables
},
},
},
// Specific configuration for test files to handle Jest globals
// Vitest globals for test files
{
files: ['**/*.test.js', '**/*.test.jsx', '**/*.spec.js', '**/*.spec.jsx'],
languageOptions: {
globals: {
...globals.browser,
...globals.jest, // Add Jest globals for test files
vi: 'readonly',
describe: 'readonly',
it: 'readonly',
expect: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
beforeAll: 'readonly',
after all: 'readonly',
},
},
},
// Specific configuration for test utility files to handle Jest globals
// Vitest globals for test utility files
{
files: ['src/test-utils/**/*.js', 'src/setupTests.js'],
languageOptions: {
globals: {
...globals.browser,
...globals.jest, // Add Jest globals for test utility files
vi: 'readonly',
describe: 'readonly',
it: 'readonly',
expect: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
beforeAll: 'readonly',
after all: 'readonly',
},
},
},
Expand Down
63 changes: 63 additions & 0 deletions frontend/fix-mock-defaults.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env node
const fs = require('fs');

const files = process.argv.slice(2);

for (const file of files) {
let content = fs.readFileSync(file, 'utf-8');
const lines = content.split('\n');
const result = [];
let i = 0;

while (i < lines.length) {
const line = lines[i];

// Detect: " return function SomeName(" pattern inside a vi.mock factory
const match = line.match(/^(\s+)return function (\w+)\s*\(/);
if (match) {
const indent = match[1];
// Check if previous non-empty lines are inside a vi.mock factory
// Replace "return function" with "return { default: function"
result.push(line.replace('return function', 'return { default: function'));

// Now track braces to find the end of this function
let braceCount = 0;
for (const ch of line) {
if (ch === '{') braceCount++;
if (ch === '}') braceCount--;
}

i++;
// Keep reading until braces balance (function body ends)
while (i < lines.length && braceCount > 0) {
const currentLine = lines[i];
for (const ch of currentLine) {
if (ch === '{') braceCount++;
if (ch === '}') braceCount--;
}

if (braceCount === 0) {
// This line closes the function. It should end with ";"
// We need to add " }" before the ";" to close the { default: } wrapper
// Typical line: " };" -- transform to " } };"
result.push(currentLine.replace(/;\s*$/, ' };'));
} else {
result.push(currentLine);
}
i++;
}
continue;
}

result.push(line);
i++;
}

const newContent = result.join('\n');
if (newContent !== content) {
fs.writeFileSync(file, newContent);
console.log(`Fixed: ${file}`);
} else {
console.log(`No changes: ${file}`);
}
}
19 changes: 19 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="/favicon.ico">
<script src="/settings.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="/manifest.json">
<title>Ibutsu</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<script type="module" src="/src/index.js"></script>
</body>
</html>
2 changes: 0 additions & 2 deletions frontend/jest.polyfills.cjs

This file was deleted.

Loading
Loading