This is an automated email from the ASF dual-hosted git repository.
yuluo-yx pushed a commit to branch 2.0.0
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/2.0.0 by this push:
new 258fefd64f feat: fix 2.0 web frontend
258fefd64f is described below
commit 258fefd64fe0ff1126694670c76baa912220de1b
Author: yuluo-yx <[email protected]>
AuthorDate: Sat Jul 11 00:00:36 2026 +0800
feat: fix 2.0 web frontend
Signed-off-by: yuluo-yx <[email protected]>
---
web-next/.eslintrc.json | 3 --
.../components/pages/login-form.submit.test.tsx | 2 +-
web-next/components/pages/login-form.test.tsx | 1 -
.../components/shell/app-frame.chrome.test.tsx | 2 +-
web-next/eslint.config.mjs | 12 ++++++++
web-next/package-lock.json | 1 +
web-next/package.json | 3 +-
web-next/scripts/parity/seed-state-lib.test.ts | 27 +++++++++---------
web-next/scripts/release-shell-smoke.test.ts | 22 +++++++++++++++
web-next/scripts/release-shell.mjs | 33 ++++++++++++++++++----
web-next/scripts/standalone-server.mjs | 3 +-
11 files changed, 81 insertions(+), 28 deletions(-)
diff --git a/web-next/.eslintrc.json b/web-next/.eslintrc.json
deleted file mode 100644
index 957cd1545e..0000000000
--- a/web-next/.eslintrc.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": ["next/core-web-vitals"]
-}
diff --git a/web-next/components/pages/login-form.submit.test.tsx
b/web-next/components/pages/login-form.submit.test.tsx
index 28f21a60cd..c6fa650a22 100644
--- a/web-next/components/pages/login-form.submit.test.tsx
+++ b/web-next/components/pages/login-form.submit.test.tsx
@@ -26,7 +26,7 @@ vi.mock('next/navigation', () => ({
}));
vi.mock('next/image', () => ({
- default: ({ alt, src, priority: _priority, ...props }: any) => <img
alt={alt} src={src} {...props} />
+ default: ({ alt, src, priority: _priority, ...props }: any) =>
React.createElement('img', { alt, src, ...props })
}));
vi.mock('../providers/i18n-provider', () => ({
diff --git a/web-next/components/pages/login-form.test.tsx
b/web-next/components/pages/login-form.test.tsx
index 25449884fa..110738b608 100644
--- a/web-next/components/pages/login-form.test.tsx
+++ b/web-next/components/pages/login-form.test.tsx
@@ -1,5 +1,4 @@
import { createTranslatorMock } from '../../test/i18n-test-helper';
-/* eslint-disable @next/next/no-img-element */
import React from 'react';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
diff --git a/web-next/components/shell/app-frame.chrome.test.tsx
b/web-next/components/shell/app-frame.chrome.test.tsx
index b7b7607744..9a5cb5d93e 100644
--- a/web-next/components/shell/app-frame.chrome.test.tsx
+++ b/web-next/components/shell/app-frame.chrome.test.tsx
@@ -7,7 +7,7 @@ import { createTranslatorMock } from
'../../test/i18n-test-helper';
vi.mock('next/image', () => ({
default: ({ alt, priority: _priority, ...props }:
React.ComponentProps<'img'> & { priority?: boolean }) => (
- <img alt={alt} {...props} />
+ React.createElement('img', { alt, ...props })
)
}));
diff --git a/web-next/eslint.config.mjs b/web-next/eslint.config.mjs
new file mode 100644
index 0000000000..722ed58a4a
--- /dev/null
+++ b/web-next/eslint.config.mjs
@@ -0,0 +1,12 @@
+import { FlatCompat } from '@eslint/eslintrc';
+
+const compat = new FlatCompat({ baseDirectory: import.meta.dirname });
+
+const eslintConfig = [
+ {
+ ignores: ['.next/**', '.next-*/**', 'next-env.d.ts']
+ },
+ ...compat.extends('next/core-web-vitals')
+];
+
+export default eslintConfig;
diff --git a/web-next/package-lock.json b/web-next/package-lock.json
index 6866386618..61b44b6223 100644
--- a/web-next/package-lock.json
+++ b/web-next/package-lock.json
@@ -33,6 +33,7 @@
"tailwind-merge": "3.3.0"
},
"devDependencies": {
+ "@eslint/eslintrc": "3.3.5",
"@types/node": "22.15.21",
"@types/react": "19.1.2",
"@types/react-dom": "19.1.2",
diff --git a/web-next/package.json b/web-next/package.json
index f06fd24767..4923fdf280 100644
--- a/web-next/package.json
+++ b/web-next/package.json
@@ -6,7 +6,7 @@
"dev": "next dev --turbopack -p 4200",
"build": "next build && node ./scripts/standalone-server.mjs prepare",
"start": "node ./scripts/standalone-server.mjs start",
- "lint": "ESLINT_USE_FLAT_CONFIG=false eslint . --ext .js,.jsx,.ts,.tsx",
+ "lint": "eslint .",
"test": "vitest run",
"parity:runtime": "node ./scripts/parity/runtime.mjs",
"parity:smoke": "node ./scripts/parity/harness.mjs",
@@ -47,6 +47,7 @@
"tailwind-merge": "3.3.0"
},
"devDependencies": {
+ "@eslint/eslintrc": "3.3.5",
"@types/node": "22.15.21",
"@types/react": "19.1.2",
"@types/react-dom": "19.1.2",
diff --git a/web-next/scripts/parity/seed-state-lib.test.ts
b/web-next/scripts/parity/seed-state-lib.test.ts
index 44fc403934..173207c45b 100644
--- a/web-next/scripts/parity/seed-state-lib.test.ts
+++ b/web-next/scripts/parity/seed-state-lib.test.ts
@@ -1,4 +1,5 @@
import { describe, expect, it, vi } from 'vitest';
+import { fileURLToPath } from 'node:url';
import {
applySeedContextToRoutePair,
resolveSeedContext,
@@ -222,18 +223,18 @@ describe('parity seed-state helpers', () => {
execFileSyncImpl
});
- expect(execFileSyncImpl).toHaveBeenCalledWith(
- 'bash',
- [expect.stringContaining('seed-trace-rich-demo.sh')],
- expect.objectContaining({
- cwd:
expect.stringContaining('/Users/zhaoqingran/IdeaProjects/hertzbeat'),
- encoding: 'utf8',
- stdio: 'pipe',
- env: expect.objectContaining({
- TRACE_WINDOW_END_MS: '1776751800000',
- GREPTIME_HTTP: 'http://127.0.0.1:14000'
- })
- })
- );
+ const [command, args, options] = execFileSyncImpl.mock.lastCall as unknown
as [
+ string,
+ string[],
+ { cwd: string; encoding: string; stdio: string; env: NodeJS.ProcessEnv }
+ ];
+
+ expect(command).toBe('bash');
+ expect(args).toEqual([fileURLToPath(new
URL('../../../script/dev/seed-trace-rich-demo.sh', import.meta.url))]);
+ expect(options.cwd).toBe(fileURLToPath(new URL('../../../',
import.meta.url)));
+ expect(options.encoding).toBe('utf8');
+ expect(options.stdio).toBe('pipe');
+ expect(options.env.TRACE_WINDOW_END_MS).toBe('1776751800000');
+ expect(options.env.GREPTIME_HTTP).toBe('http://127.0.0.1:14000');
});
});
diff --git a/web-next/scripts/release-shell-smoke.test.ts
b/web-next/scripts/release-shell-smoke.test.ts
index 707bd0c37e..a04e6a186a 100644
--- a/web-next/scripts/release-shell-smoke.test.ts
+++ b/web-next/scripts/release-shell-smoke.test.ts
@@ -1,11 +1,14 @@
import { describe, expect, it } from 'vitest';
import { readFileSync } from 'node:fs';
+import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
+import os from 'node:os';
import { resolve } from 'node:path';
import {
buildExpectedQueryEntries,
findMismatchedQueryEntries,
resolveNextRedirectDigestUrl
} from './release-shell-smoke.mjs';
+import { resolveLocalReleaseLaunch } from './release-shell.mjs';
describe('release-shell smoke helpers', () => {
it('normalizes expected query entries into string pairs', () => {
@@ -36,6 +39,25 @@ describe('release-shell smoke helpers', () => {
expect(resolveNextRedirectDigestUrl('<html><body>no redirect
digest</body></html>', 'http://127.0.0.1:4200')).toBeNull();
});
+ it('runs release checks through the standalone server when a production
build exists', async () => {
+ const rootDir = await mkdtemp(resolve(os.tmpdir(),
'hertzbeat-release-shell-'));
+ try {
+ const appDir = resolve(rootDir, '.next', 'standalone', 'web-next');
+ const serverFile = resolve(appDir, 'server.js');
+ await mkdir(appDir, { recursive: true });
+ await writeFile(resolve(rootDir, '.next', 'BUILD_ID'), 'build-id');
+ await writeFile(serverFile, 'server');
+
+ expect(resolveLocalReleaseLaunch({ port: 4300, rootDir })).toEqual({
+ args: [serverFile],
+ cwd: appDir,
+ env: { PORT: '4300', HOSTNAME: '127.0.0.1' }
+ });
+ } finally {
+ await rm(rootDir, { recursive: true, force: true });
+ }
+ });
+
it('keeps the release route browser smoke on the required route and console
contracts', () => {
const source = readFileSync(resolve(process.cwd(),
'scripts/release-route-browser-smoke.spec.ts'), 'utf8');
diff --git a/web-next/scripts/release-shell.mjs
b/web-next/scripts/release-shell.mjs
index dd78792c44..c3ff3b525b 100644
--- a/web-next/scripts/release-shell.mjs
+++ b/web-next/scripts/release-shell.mjs
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import path from 'node:path';
import process from 'node:process';
+import { resolveStandalonePaths } from './standalone-server.mjs';
export function sleep(ms) {
return new Promise(resolve => {
@@ -30,17 +31,37 @@ export async function waitForServer(baseUrl, readyPath =
'/overview') {
);
}
+export function resolveLocalReleaseLaunch({
+ port,
+ distDir = process.env.NEXT_DIST_DIR || '.next',
+ rootDir = process.cwd()
+}) {
+ const buildIdPath = path.join(rootDir, distDir, 'BUILD_ID');
+ if (existsSync(buildIdPath)) {
+ const { appDir, serverFile } = resolveStandalonePaths(rootDir, distDir);
+ return {
+ args: [serverFile],
+ cwd: appDir,
+ env: { PORT: String(port), HOSTNAME: '127.0.0.1' }
+ };
+ }
+
+ return {
+ args: [path.join(rootDir, 'node_modules', 'next', 'dist', 'bin', 'next'),
'dev', '--hostname', '127.0.0.1', '--port', String(port)],
+ cwd: rootDir,
+ env: { PORT: String(port) }
+ };
+}
+
export async function startLocalReleaseServer({
port,
readyPath = '/overview',
distDir = process.env.NEXT_DIST_DIR || '.next'
}) {
- const buildIdPath = path.join(process.cwd(), distDir, 'BUILD_ID');
- const nextBinPath = path.join(process.cwd(), 'node_modules', 'next', 'dist',
'bin', 'next');
- const command = existsSync(buildIdPath) ? 'start' : 'dev';
- const child = spawn(process.execPath, [nextBinPath, command, '--hostname',
'127.0.0.1', '--port', String(port)], {
- cwd: process.cwd(),
- env: { ...process.env, PORT: String(port) },
+ const launch = resolveLocalReleaseLaunch({ port, distDir });
+ const child = spawn(process.execPath, launch.args, {
+ cwd: launch.cwd,
+ env: { ...process.env, ...launch.env },
stdio: ['ignore', 'pipe', 'pipe']
});
diff --git a/web-next/scripts/standalone-server.mjs
b/web-next/scripts/standalone-server.mjs
index 9c26740890..e67feb0f96 100644
--- a/web-next/scripts/standalone-server.mjs
+++ b/web-next/scripts/standalone-server.mjs
@@ -41,8 +41,7 @@ export function parseStartArgs(args, env = process.env) {
return parsed;
}
-export function resolveStandalonePaths(rootDir = process.cwd()) {
- const distDir = process.env.NEXT_DIST_DIR || '.next';
+export function resolveStandalonePaths(rootDir = process.cwd(), distDir =
process.env.NEXT_DIST_DIR || '.next') {
const standaloneRoot = path.join(rootDir, distDir, 'standalone');
const candidates = [path.join(standaloneRoot, 'web-next'), standaloneRoot];
const appDir = candidates.find((candidate) =>
existsSync(path.join(candidate, 'server.js')));
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]