Skip to content

New UI#1205

Merged
micossow merged 23 commits intomasterfrom
new-ui
Apr 4, 2026
Merged

New UI#1205
micossow merged 23 commits intomasterfrom
new-ui

Conversation

@micossow
Copy link
Copy Markdown
Contributor

@micossow micossow commented Apr 4, 2026

No description provided.

micossow and others added 22 commits March 1, 2026 17:12
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move Docker image building out of sbt (sbt-native-packager) and into
standalone Dockerfiles for the JVM server, native server, and UI.
Update CI to build JARs first then invoke docker buildx directly,
enabling multi-arch (amd64/arm64) builds and publishing. Add
docker-compose.yaml for running the full stack locally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The legacy stats server on port 9325 served two purposes: a JSON queue
metrics API and the old embedded UI. Both are now superseded: the UI by
the new Next.js application, and the metrics API was not used by anything.
The serveUI code was already broken after the old UI resources were removed.

- Delete rest/rest-sqs/src/main/scala/org/elasticmq/rest/stats/ (4 files)
- Delete StatisticsDirectivesTest.scala
- Remove RestStatisticsConfiguration from ElasticMQServerConfig
- Remove optionallyStartRestStatistics from ElasticMQServer
- Remove rest-stats block from reference.conf
- Remove EXPOSE 9325 from server/Dockerfile and native-server/Dockerfile
- Remove port 9325 mapping from docker-compose.yaml
- Remove all 9325 mentions from README.md and CLAUDE.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace single cross-compiled buildx job with native builds:
- Build JARs once on amd64 and share as artifacts (JVM bytecode is arch-neutral)
- Build amd64 images on ubuntu-24.04, arm64 images on ubuntu-24.04-arm (in parallel)
- Merge into multi-arch manifests with docker buildx imagetools create

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

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 replaces the legacy Create React App-based UI (and its dedicated /statistics/* REST server) with a new Next.js-based UI that talks directly to ElasticMQ via the SQS API, and updates Docker/CI to build and run the new UI alongside the server.

Changes:

  • Migrates ui/ from CRA + Material UI + Jest tests to a Next.js (App Router) UI using @aws-sdk/client-sqs, Tailwind v4, and server actions.
  • Removes the Scala rest-stats HTTP server, configuration, and tests; updates docs accordingly.
  • Reworks Docker/CI: adds dedicated Dockerfiles (server/native/ui), adds compose for local running, and splits UI CI from sbt.

Reviewed changes

Copilot reviewed 65 out of 77 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
ui/tsconfig.json Updates TS config for Next.js (App Router, paths, bundler resolution).
ui/src/styles/queue.css Removes legacy queue hover styling (CRA UI removal).
ui/src/setupTests.js Removes Jest DOM setup (legacy UI testing removal).
ui/src/services/QueueService.ts Removes legacy REST-stats axios service.
ui/src/services/QueueService.test.ts Removes legacy service unit tests.
ui/src/Queues/RefreshQueuesData.ts Removes legacy polling hook implementation.
ui/src/Queues/QueuesTable.tsx Removes legacy Material UI queues table.
ui/src/Queues/QueuesTable.test.tsx Removes legacy UI tests for queues table.
ui/src/Queues/QueueRowDetails.tsx Removes legacy row details component.
ui/src/Queues/QueueRow.tsx Removes legacy row component.
ui/src/Queues/QueueRow.test.tsx Removes legacy row component tests.
ui/src/Queues/QueueMessageData.ts Removes legacy UI type definitions.
ui/src/NavBar/NavBar.tsx Removes legacy navbar component.
ui/src/Main/Main.tsx Removes legacy app composition.
ui/src/index.js Removes CRA entrypoint.
ui/src/index.css Removes CRA global styles.
ui/src/App.tsx Removes legacy App component.
ui/src/App.test.tsx Removes legacy App test.
ui/README.md Removes CRA README boilerplate.
ui/public/window.svg Adds Next.js default/static asset.
ui/public/vercel.svg Adds Next.js default/static asset.
ui/public/next.svg Adds Next.js default/static asset.
ui/public/manifest.json Removes CRA PWA manifest.
ui/public/index.html Removes CRA HTML template.
ui/public/globe.svg Adds Next.js default/static asset.
ui/public/file.svg Adds Next.js default/static asset.
ui/postcss.config.mjs Adds Tailwind v4 PostCSS setup.
ui/package.json Switches to Next.js deps/scripts; removes legacy test tooling.
ui/next.config.ts Adds Next config (standalone output).
ui/lib/utils.ts Adds attribute formatting helpers and hidden-attribute list.
ui/lib/types.ts Adds UI/shared types for queues and messages.
ui/lib/theme-provider.tsx Adds client theme context/provider with persisted selection.
ui/lib/sqs-client.ts Adds SQS client configuration + queue name helper.
ui/lib/actions.ts Adds server actions for queue list/details, send/receive/delete, batch send.
ui/eslint.config.mjs Adds ESLint flat config using eslint-config-next.
ui/Dockerfile Adds multi-stage build/runtime Dockerfile for standalone Next output.
ui/components/theme-switcher.tsx Adds theme toggle UI component.
ui/components/send-message-modal.tsx Adds send-message modal (attributes, FIFO fields, trace header).
ui/components/receive-messages-panel.tsx Adds receive/delete UI panel with message inspection.
ui/components/queue-list.tsx Adds queue list client component with polling and refresh UI.
ui/components/queue-details.tsx Adds queue details view (polling, actions, attributes table).
ui/components/queue-card.tsx Adds queue summary card with quick actions.
ui/components/page-header.tsx Adds landing page header with theme control.
ui/components/loading-skeleton.tsx Adds loading skeleton component.
ui/components/generate-messages-modal.tsx Adds message generation/batch send modal.
ui/components/error-display.tsx Adds UI error component with retry.
ui/app/queues/[name]/page.tsx Adds dynamic queue details route page.
ui/app/page.tsx Adds home page rendering queue list.
ui/app/layout.tsx Adds root layout with fonts + ThemeProvider.
ui/app/globals.css Adds global theme variables + Tailwind import.
ui/app/favicon.ico Adds new favicon asset.
ui/.gitignore Updates ignores for Next/Yarn/env/build artifacts.
ui/.dockerignore Adds Docker ignore for UI build context.
server/Dockerfile Adds dedicated JVM server image build (jar + config, non-root user).
rest/rest-sqs/src/test/.../StatisticsDirectivesTest.scala Removes stats REST server test coverage.
rest/rest-sqs/src/main/.../ElasticMQServer.scala Stops wiring up the stats REST server.
rest/rest-sqs/src/main/.../ElasticMQServerConfig.scala Removes rest-stats config section.
rest/rest-sqs/src/main/.../StatisticsRestServerBuilder.scala Removes stats REST server builder implementation.
rest/rest-sqs/src/main/.../StatisticsJsonFormat.scala Removes stats REST JSON formats.
rest/rest-sqs/src/main/.../StatisticsDirectives.scala Removes stats routes + UI-serving directive code.
rest/rest-sqs/src/main/.../stats/package.scala Removes stats package types alias.
rest/rest-sqs/src/main/resources/reference.conf Removes rest-stats reference config block.
README.md Updates local run/UI docs; removes rest-stats references.
project/plugins.sbt Removes sbt-native-packager plugin usage.
native-server/Dockerfile Adds dedicated GraalVM native-image build + minimal runtime image.
integration-tests/docker/Dockerfile Switches logback.xml source path to examples/logback.xml.
examples/logback.xml Adds example logback config (currently DEBUG root).
examples/elasticmq.conf Adds example ElasticMQ config for compose/local runs.
docker-compose.yaml Adds compose to run server + new UI images together.
CLAUDE.md Adds repo documentation and UI/backend dev notes.
build.sbt Removes sbt-managed UI build + docker packaging logic; adjusts aggregates.
.gitignore Adds .data ignore.
.github/workflows/ci.yml Adds ci-ui job; updates docker build steps to use Dockerfiles.
.dockerignore Adds root docker ignore list for smaller contexts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +11
interface QueuePageProps {
params: Promise<{
name: string;
}>;
}

export default async function QueuePage({ params }: QueuePageProps) {
const { name } = await params;
const queueName = decodeURIComponent(name);
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

params in App Router pages is passed as a plain object, not a Promise. Typing it as Promise and await-ing it is misleading and can hide incorrect usage; update the prop type to { params: { name: string } } and remove the unnecessary await.

Copilot uses AI. Check for mistakes.
Comment thread README.md
Comment on lines +500 to +507
The dev server starts at **http://localhost:3000** and expects ElasticMQ running at `http://localhost:9324`. Configure the endpoint in `ui/.env.local` if needed:

You can start UI via `yarn start` command in the `ui` directory, which will run on localhost:3000 address.
```bash
NEXT_PUBLIC_SQS_ENDPOINT=http://localhost:9324
AWS_REGION=elasticmq
AWS_ACCESS_KEY_ID=x
AWS_SECRET_ACCESS_KEY=x
```
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

The docs suggest NEXT_PUBLIC_SQS_ENDPOINT, but the UI server-side SQS client reads process.env.SQS_ENDPOINT (and docker-compose also sets SQS_ENDPOINT). Update the README env snippet to match the actual variable name(s) used by the code.

Copilot uses AI. Check for mistakes.
Comment thread ui/lib/actions.ts
Comment on lines +38 to +43
// Get attributes for each queue
const queueDataPromises = listResult.QueueUrls.map(async (queueUrl) => {
const attributesCommand = new GetQueueAttributesCommand({
QueueUrl: queueUrl,
AttributeNames: ['All'],
});
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

getQueues() always fetches AttributeNames: ['All'] for every queue. Since the list page only needs the three numeric stats, requesting all attributes increases payload and makes polling much more expensive as queue count grows; consider requesting only the needed attribute names (or splitting list vs details endpoints).

Copilot uses AI. Check for mistakes.
Comment thread ui/lib/actions.ts
Comment on lines +57 to +60
} catch (error) {
console.error('Error fetching queues:', error);
throw new Error('Failed to fetch queues. Make sure ElasticMQ is running on localhost:9324');
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

getQueues() throws an error mentioning localhost:9324, but the code actually uses process.env.SQS_ENDPOINT (and can point elsewhere, e.g. http://elasticmq:9324 in Docker). Consider making this message endpoint-agnostic or include the configured endpoint value to avoid misleading users.

Copilot uses AI. Check for mistakes.
Comment thread ui/lib/actions.ts
Comment on lines +94 to +97
} catch (error) {
console.error('Error fetching queue details:', error);
throw new Error('Failed to fetch queue details. Make sure ElasticMQ is running on localhost:9324');
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

getQueueDetails() throws an error mentioning localhost:9324, but the code actually uses process.env.SQS_ENDPOINT (and can point elsewhere). Consider making this message endpoint-agnostic or include the configured endpoint value to avoid misleading users.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +36
useEffect(() => {
fetchQueues();
const interval = setInterval(() => fetchQueues(), 1000);
return () => clearInterval(interval);
}, []);
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

Polling every 1s will trigger getQueues() repeatedly; combined with per-queue GetQueueAttributes calls this can create significant load (N+1 SQS calls per second). Consider increasing the interval, making it configurable, or switching to manual refresh / backoff after errors.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +20
// System attribute keys that contain Unix timestamps (seconds)
const TIMESTAMP_ATTRS = ['SentTimestamp', 'ApproximateFirstReceiveTimestamp'];

function formatSysAttrValue(key: string, value: string): string {
if (TIMESTAMP_ATTRS.includes(key)) {
const ms = parseInt(value);
if (!isNaN(ms)) return new Date(ms).toLocaleString();
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

Comment says the system attributes are Unix timestamps in seconds, but SentTimestamp / ApproximateFirstReceiveTimestamp are epoch milliseconds in SQS (and the code treats them as ms). Please update the comment to avoid confusion.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +47
const options = [
{ value: 'light', label: '☀', title: 'Light' },
{ value: 'dark', label: '☾', title: 'Dark' },
{ value: 'auto', label: '⬡', title: 'Auto' },
] as const;

return (
<div
style={{
display: 'flex',
background: 'var(--card-bg)',
border: '1px solid var(--card-border)',
borderRadius: 8,
padding: 3,
gap: 2,
}}
>
{options.map(o => {
const active = mounted && theme === o.value;
return (
<button
key={o.value}
onClick={() => setTheme(o.value)}
title={o.title}
style={{
width: 30, height: 28,
borderRadius: 5,
border: 'none',
cursor: 'pointer',
fontSize: 13,
fontWeight: active ? 700 : 400,
background: active ? 'var(--accent-dim)' : 'transparent',
color: active ? 'var(--accent)' : 'var(--muted)',
transition: 'all 150ms ease',
outline: active ? '1px solid var(--accent)' : 'none',
outlineOffset: -1,
}}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

The theme toggle buttons only render symbols (e.g. , , ) and rely on title for meaning. Add an accessible name (e.g. aria-label / aria-pressed) so screen readers can understand the options and current state.

Copilot uses AI. Check for mistakes.
Comment thread ui/package.json
Comment on lines 5 to 16
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jest-environment-jsdom-sixteen",
"test:ci": "CI=true react-scripts test --env=jest-environment-jsdom-sixteen --maxWorkers 2",
"eject": "react-scripts eject"
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
"eslintConfig": {
"extends": [
"react-app"
]
"dependencies": {
"@aws-sdk/client-sqs": "^3.1000.0",
"next": "16.1.6",
"react": "19.2.3",
"react-dom": "19.2.3"
},
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

UI test coverage was removed (no test script and no test dependencies), but the PR introduces substantial new UI behavior (queue polling, send/receive/delete, batch generation). Consider adding at least a minimal automated test setup (e.g. Playwright smoke tests or component tests) to prevent regressions.

Copilot uses AI. Check for mistakes.
- Correct NEXT_PUBLIC_SQS_ENDPOINT → SQS_ENDPOINT in CLAUDE.md and README
  (code already used SQS_ENDPOINT; docs were out of sync)
- Replace disabled Cancel with active Stop button while generating;
  clicking Stop sets abortRef to abort after the current batch completes
- Show "Stopped" state in the done screen when generation was aborted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@micossow micossow marked this pull request as ready for review April 4, 2026 16:24
@micossow micossow merged commit b023031 into master Apr 4, 2026
31 checks passed
@micossow micossow deleted the new-ui branch April 4, 2026 16:24
@micossow micossow mentioned this pull request Apr 4, 2026
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.

2 participants