Skip to content

Conversation

@artemmufazalov
Copy link
Member

@artemmufazalov artemmufazalov commented Nov 27, 2025

Closes #2236

Stand: https://nda.ya.ru/t/ESJMU9iT7NhbJ2

CI Results

Test Status: ⚠️ FLAKY

📊 Full Report

Total Passed Failed Flaky Skipped
378 375 0 1 2
Test Changes Summary ⏭️2

⏭️ Skipped Tests (2)

  1. Scroll to row, get shareable link, navigate to URL and verify row is scrolled into view (tenant/diagnostics/tabs/queries.test.ts)
  2. Copy result button copies to clipboard (tenant/queryEditor/queryEditor.test.ts)

Bundle Size: 🔽

Current: 62.32 MB | Main: 66.06 MB
Diff: 3.74 MB (-5.65%)

✅ Bundle size decreased.

ℹ️ CI Information
  • Test recordings for failed tests are available in the full report.
  • Bundle size is measured for the entire 'dist' directory.
  • 📊 indicates links to detailed reports.
  • 🔺 indicates increase, 🔽 decrease, and ✅ no change in bundle size.

@artemmufazalov artemmufazalov force-pushed the 2236-rsbuild branch 2 times, most recently from c3a9bc6 to 5e4de33 Compare November 27, 2025 12:54
Comment on lines 27 to 30
window.web_version = "<%= !process.env.REACT_APP_BACKEND %>"
window.custom_backend = "<%= process.env.NODE_ENV === 'development' && process.env.REACT_APP_BACKEND %>"
window.meta_backend = "<%= process.env.REACT_APP_META_BACKEND %>"
window.react_app_disable_checks = "<%= process.env.REACT_APP_DISABLE_CHECKS %>"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed templates format from % % to "<%= %>. Other changes are deleted comments and applied prettier


// Mock window.location.origin that is used inside prepareErrorStack
const windowSpy = jest.spyOn(window, 'window', 'get');
windowSpy.mockImplementation(() => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newer version of jest-environment-jsdom does not allow to manipulate window manually. So I had to replace all window mocks with different approach.

This test now expects localhost:3000 base url from config

@@ -0,0 +1,7 @@
module.exports = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

babel config is needed for jest tests to work

"prettier --write"
]
},
"jest": {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jest config now in its own separate file

Comment on lines +59 to +62
export const webVersion = Boolean(parseJson(window.web_version));
export const customBackend = parseJson(window.custom_backend);
export const metaBackend = parseJson(window.meta_backend);
export const codeAssistBackend = parseJson(window.code_assist_backend);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously they were parsed automatically and we only faced problem with 'undefined' being a string

@artemmufazalov artemmufazalov force-pushed the 2236-rsbuild branch 10 times, most recently from 3e68add to 87d2115 Compare November 28, 2025 13:41
jobs:
e2e_tests:
name: Playwright Tests
timeout-minutes: 60
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now e2e tests can run for a very long time (hours), when they are totally broken, set timeout for such case

@artemmufazalov artemmufazalov marked this pull request as ready for review November 28, 2025 14:20
Copilot AI review requested due to automatic review settings November 28, 2025 14:20
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

17 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copilot finished reviewing on behalf of artemmufazalov November 28, 2025 14:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the build system from Create React App (CRA) to Rsbuild, a modern and faster bundler. The migration involves replacing CRA's configuration with Rsbuild's declarative config, updating build tools, and adjusting how environment variables are injected into the application.

Key changes:

  • Replaced react-scripts and react-app-rewired with Rsbuild and its plugins
  • Migrated Jest configuration from package.json inline config to dedicated jest.config.ts
  • Updated environment variable injection to use rsbuild's templating system in index.html
  • Modified dynamic SVG imports to include ?react query parameter for proper SVGR processing

Reviewed changes

Copilot reviewed 15 out of 18 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
rsbuild.config.ts New Rsbuild configuration defining build setup, environment variables, plugins, and Monaco editor integration
babel.config.js New Babel configuration for Jest testing with TypeScript and React support
jest.config.ts Migrated Jest configuration from package.json to dedicated TypeScript config file
package.json Updated scripts to use rsbuild commands, added rsbuild dependencies, removed CRA dependencies
public/index.html Updated environment variable injection from CRA placeholders to rsbuild template expressions
tsconfig.json Changed module resolution options to lowercase (stylistic change, no functional impact)
eslint.config.mjs Updated to reference babel.config.js instead of removed config-overrides.js
playwright.config.ts Added conditional retries for CI environment and clarified testDir path
src/types/assets.d.ts Added type declaration for *.svg?react imports to support rsbuild's SVGR plugin
src/utils/utils.ts Updated parseJson to handle string "undefined" and accept unknown type parameter
src/store/configureStore.ts Added parseJson calls to convert string environment variables to proper types
src/components/Illustration/Illustration.tsx Added ?react suffix to dynamic SVG imports for proper SVGR processing
src/store/test/getUrlData.test.ts Replaced jest.spyOn window mocking with direct window.history.pushState calls
src/utils/test/parseBalancer.test.ts Replaced jest.spyOn window mocking with direct window property assignments
src/components/ErrorBoundary/tests/prepareErrorStack.test.ts Removed window mocking since jsdom provides localhost:3000 by default
config-overrides.js Removed CRA configuration overrides file (no longer needed with Rsbuild)
Comments suppressed due to low confidence (1)

src/store/test/getUrlData.test.ts:147

  • Test pollution risk: Directly mutating window.history using pushState without cleanup can cause test state to leak between tests. The URL changes persist and could affect other tests.

Consider adding cleanup to restore the original state:

describe('getUrlData', () => {
    const originalPathname = window.location.pathname;
    
    afterEach(() => {
        window.history.pushState({}, '', originalPathname);
    });
    
    // ... rest of tests
});
describe('getUrlData', () => {
    describe('multi-cluster version', () => {
        test('should parse pathname with folder', () => {
            window.history.pushState(
                {},
                '',
                '/ui/cluster?clusterName=my_cluster&backend=http://my-node:8765',
            );
            const result = getUrlData({singleClusterMode: false, customBackend: undefined});
            expect(result).toEqual({
                basename: '/ui',
                backend: 'http://my-node:8765',
                clusterName: 'my_cluster',
            });
        });
        test('should parse pathname with folder and some prefix', () => {
            window.history.pushState(
                {},
                '',
                '/monitoring/ui/cluster?clusterName=my_cluster&backend=http://my-node:8765',
            );
            const result = getUrlData({singleClusterMode: false, customBackend: undefined});
            expect(result).toEqual({
                basename: '/monitoring/ui',
                backend: 'http://my-node:8765',
                clusterName: 'my_cluster',
            });
        });
        test('should parse pathname without folder', () => {
            window.history.pushState(
                {},
                '',
                '/cluster?clusterName=my_cluster&backend=http://my-node:8765',
            );

            const result = getUrlData({singleClusterMode: false, customBackend: undefined});
            expect(result).toEqual({
                basename: '',
                backend: 'http://my-node:8765',
                clusterName: 'my_cluster',
            });
        });
        test('should extract environment from first segment', () => {
            window.history.pushState(
                {},
                '',
                '/cloud-prod/cluster?clusterName=my_cluster&backend=http://my-node:8765',
            );

            const result = getUrlData({
                singleClusterMode: false,
                customBackend: undefined,
                allowedEnvironments: ['cloud-prod', 'cloud-preprod'],
            });
            expect(result).toEqual({
                basename: '',
                backend: 'http://my-node:8765',
                clusterName: 'my_cluster',
                environment: 'cloud-prod',
            });
        });
        test('should extract environment from first segment with monitoring folder', () => {
            window.history.pushState(
                {},
                '',
                '/cloud-preprod/api/meta3/proxy/cluster/pre-prod_global/monitoring/cluster/tenants',
            );

            const result = getUrlData({
                singleClusterMode: false,
                customBackend: undefined,
                allowedEnvironments: ['cloud-prod', 'cloud-preprod'],
            });
            expect(result).toEqual({
                basename: '/cloud-preprod/api/meta3/proxy/cluster/pre-prod_global/monitoring',
                backend: undefined,
                clusterName: undefined,
                environment: 'cloud-preprod',
            });
        });
        test('should not extract environment if not in allowed list', () => {
            window.history.pushState({}, '', '/cluster/tenants?clusterName=my_cluster');

            const result = getUrlData({
                singleClusterMode: false,
                customBackend: undefined,
                allowedEnvironments: ['cloud-prod', 'cloud-preprod'],
            });
            expect(result).toEqual({
                basename: '',
                backend: undefined,
                clusterName: 'my_cluster',
                environment: undefined,
            });
        });
        test('should not extract environment without allowedEnvironments list', () => {
            window.history.pushState({}, '', '/my-env/cluster?clusterName=my_cluster');

            const result = getUrlData({
                singleClusterMode: false,
                customBackend: undefined,
            });
            expect(result).toEqual({
                basename: '',
                backend: undefined,
                clusterName: 'my_cluster',
                environment: undefined,
            });
        });
    });
    describe('single-cluster version with custom backend', () => {
        test('should parse correclty parse pathname', () => {
            window.history.pushState({}, '', '/cluster');

            const result = getUrlData({
                singleClusterMode: true,
                customBackend: 'http://my-node:8765',
            });
            expect(result).toEqual({
                basename: '',
                backend: 'http://my-node:8765',
            });
        });
    });
    describe('single-cluster embedded version', () => {
        test('should parse pathname with folder', () => {
            window.history.pushState({}, '', '/monitoring/cluster');

            const result = getUrlData({singleClusterMode: true, customBackend: undefined});
            expect(result).toEqual({
                basename: '/monitoring',
                backend: '',
            });
        });
        test('should parse pathname with folder and some prefix', () => {
            window.history.pushState({}, '', '/node/12/monitoring/cluster');

            const result = getUrlData({singleClusterMode: true, customBackend: undefined});
            expect(result).toEqual({
                basename: '/node/12/monitoring',
                backend: '/node/12',
            });
        });
    });
});

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

20 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

package.json Outdated
"build:embedded": "GENERATE_SOURCEMAP=false PUBLIC_URL=. REACT_APP_BACKEND=http://localhost:8765 REACT_APP_META_BACKEND=undefined npm run build",
"build:embedded-mc": "GENERATE_SOURCEMAP=false PUBLIC_URL=. REACT_APP_BACKEND= REACT_APP_META_BACKEND= npm run build",
"start": "rsbuild dev",
"dev": "DISABLE_ESLINT_PLUGIN=true TSC_COMPILE_ON_ERROR=true REACT_APP_BACKEND=http://localhost:8765 REACT_APP_META_BACKEND=undefined rsbuild dev",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may be left untouched - npm start will invoke correct command

Raubzeug
Raubzeug previously approved these changes Dec 1, 2025
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

20 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@artemmufazalov artemmufazalov added this pull request to the merge queue Dec 1, 2025
Merged via the queue into main with commit 6450a1f Dec 1, 2025
8 checks passed
@artemmufazalov artemmufazalov deleted the 2236-rsbuild branch December 1, 2025 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build embedded ui with rsbuild

3 participants