Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
314131a
feat: python scripting for queue server type handling
JMit-dev Nov 25, 2025
409e448
fix: type conversion for unchecked parameters
JMit-dev Nov 26, 2025
0561325
fix: console output does not jumble text with progress bars
JMit-dev Nov 26, 2025
a3538b4
fix: running plan display persists throughout cycle
JMit-dev Nov 26, 2025
79b7fe0
style: removed focus from all ui components except tables
JMit-dev Dec 3, 2025
6202ac9
refactor: logging is consistent and respectfully to console output
JMit-dev Dec 3, 2025
4f4cab9
feat: added drag selection to history widget
JMit-dev Dec 3, 2025
ba634ef
fix: pane dragging is relative to mouse not parent
JMit-dev Dec 3, 2025
fd69b91
feat: added web socket message DTOs for status, info, and console output
JMit-dev Dec 5, 2025
96c8329
feat: generic queue server websocket client with factory methods in r…
JMit-dev Dec 5, 2025
cde53de
feat: add preferences for web sockets
JMit-dev Dec 5, 2025
a91df17
fix: autoscroll checkbox issue where it will uncheck with websockets …
JMit-dev Dec 5, 2025
5c8b54a
feat: added status websocket messages
JMit-dev Dec 5, 2025
38ab11a
fix: plan editor python type representation fixed
JMit-dev Dec 9, 2025
e5de83b
fix: preserve parameter schema order in plan queue item
JMit-dev Dec 9, 2025
f3d8b68
chore: update queue server api key name, add url env var, support env…
JMit-dev Dec 9, 2025
63bf834
docs: update queue server docs
JMit-dev Dec 9, 2025
e53c78f
feat: add polling intervals as preference
JMit-dev Dec 9, 2025
183397a
feat: throttle websocket ui updates as the same rate as polling
JMit-dev Dec 9, 2025
e9201e1
feat: timeout in connection manager
JMit-dev Dec 9, 2025
a16ccc9
fix: clear ui when disconnected, disable widgets if environment is cl…
JMit-dev Dec 9, 2025
4eb664f
feat: disable plan viewer/editor when environment is closed
JMit-dev Dec 9, 2025
102c08d
feat: added timeout while the client is connected to the queue server
JMit-dev Dec 9, 2025
b4e170d
fix: removed javafx thread blocking service calls on connection
JMit-dev Dec 9, 2025
82714be
fix: lazy intialization for jython to prevent javafx thread blocking
JMit-dev Dec 9, 2025
9a374bd
fix: python type converter javafx thread blocking fixed
JMit-dev Dec 19, 2025
c9fb1cd
fix: remove javafx thread blocking in plan loading and validation
JMit-dev Dec 19, 2025
f2b56e9
refactor: console monitor tab only open by default
JMit-dev Dec 19, 2025
13ac094
refactor: autoscroll checked by default in console monitor
JMit-dev Dec 19, 2025
fe5c94d
feat: autoscroll text turns red when disabled
JMit-dev Dec 19, 2025
9f1a139
fix: autoscroll uses events to check if user scrolled to disable
JMit-dev Dec 19, 2025
9bd6a16
feat: added auto connect manager widget
JMit-dev Dec 23, 2025
d583861
fix: status widgets are not cleared when offline
JMit-dev Dec 23, 2025
58b35b1
fix: auto connect on startup
JMit-dev Dec 23, 2025
31108ea
fix: queue operations enabled while environment is closed
JMit-dev Jan 28, 2026
c12cd6b
fix: connect button text changed to connect/disconnect
JMit-dev Jan 28, 2026
5f1828b
fix: disable update env when no status
JMit-dev Jan 28, 2026
d2b87f9
Merge pull request #4 from JMit-dev/master
JMit-dev Jan 28, 2026
ed5cfb9
fix: offload text processing in background thread
JMit-dev Jan 30, 2026
5ba654a
fix: check status bus current value on controller initialization
JMit-dev Jan 30, 2026
6fee3d0
fix: plan editor/viewer enabled when enviornment is not open
JMit-dev Jan 30, 2026
f7c80bb
fix: plan viewer/editor column sizes adjusted
JMit-dev Jan 30, 2026
b86fd7b
fix: stopped clearing plan viewer on change
JMit-dev Jan 30, 2026
cce7e64
fix: add listener tracking to StatusBus and event buses
JMit-dev Feb 2, 2026
e13fb87
fix: add shared PythonParameterConverter singleton
JMit-dev Feb 2, 2026
2758ecf
fix: add AppLifecycle and PlansCache for startup/shutdown
JMit-dev Feb 2, 2026
1c207e1
fix: update controllers to use StatusBus.addListener and PlansCache
JMit-dev Feb 2, 2026
f4a3621
fix: adjust plan editor/viewer column sizes
JMit-dev Feb 2, 2026
544341b
fix: remove duplicate QueueItemSelectionEvent from view
JMit-dev Feb 2, 2026
f595879
chore: update bluesky-services to Python 3.12 and latest dependencies
JMit-dev Feb 2, 2026
661c169
fix: reduce Python parameter conversion log level to FINE
JMit-dev Feb 11, 2026
e010232
fix: add after_uid support to queue item API models
JMit-dev Feb 11, 2026
bd7b500
fix: add UID-returning add methods to RunEngineService
JMit-dev Feb 11, 2026
f019a35
fix: replace snapshot diff with direct UID selection event
JMit-dev Feb 11, 2026
76003c7
fix: add generation counter and pending UID selection to queue contro…
JMit-dev Feb 11, 2026
9853700
fix: update controllers to insert after selection and auto-select
JMit-dev Feb 11, 2026
62002d0
fix: update history controller with insert-after and parameter format…
JMit-dev Feb 11, 2026
9f1a6f4
refactor: delete monolithic queue-server source files
JMit-dev Feb 11, 2026
9869ffd
feat: add network module with API client controller util and view cla…
JMit-dev Feb 11, 2026
4bd2d4f
feat: add edit-control module with QueueEditControlApp Instance and M…
JMit-dev Feb 11, 2026
14f2b98
feat: add monitor module with QueueMonitorApp Instance and MenuEntry
JMit-dev Feb 11, 2026
1f83a3d
refactor: update queue-server pom.xml for modular child modules
JMit-dev Feb 11, 2026
85a96d8
refactor: remove app-queue-server from phoebus-product pom.xml
JMit-dev Feb 11, 2026
2b77873
Merge branch 'ControlSystemStudio:master' into queue-server-split
JMit-dev Feb 11, 2026
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
142 changes: 76 additions & 66 deletions app/queue-server/README.md
Original file line number Diff line number Diff line change
@@ -1,100 +1,110 @@
# Java Bluesky Interface (JBI)
# Phoebus Queue Server Application

Prototype Java client for the [Bluesky QueueServer](https://blueskyproject.io/bluesky-queueserver/) REST API.
It includes:
A JavaFX-based client for the [Bluesky QueueServer](https://blueskyproject.io/bluesky-queueserver/) that provides a graphical interface for managing experiment queues, monitoring status, and editing plans at beamlines and scientific facilities.

* **BlueskyHttpClient** – thread-safe singleton with rate-limiting, automatic retries and JUL logging
* **BlueskyService** – one blocking call per API route
* **CLI / REPL** – *testing utilities only*
* **JavaFX UI** – the part you actually launch in normal use
## Features

---
### Queue Management
- **View & Edit Queue**: See all queued plans with parameters, reorder items via drag-and-drop
- **Execute Plans**: Start, stop, pause, resume, and abort plan execution
- **Real-time Status**: Live updates via WebSocket connections showing queue state, running plans, and RE Manager status
- **History View**: Browse completed plans with execution results and metadata

## Prerequisites
### Plan Editing
- **Interactive Plan Editor**: Create and modify plans with type-safe parameter editing
- **Python Type Support**: Full support for Python types (strings, lists, dicts, booleans, numbers)
- **Schema Validation**: Parameters validated against plan schemas from the Queue Server
- **Live Preview**: See plan parameters as they will be sent to the server

* Java 17
* Maven
* Running Bluesky HTTP Server at `http://localhost:60610`
*single-user API key `a` assumed below*
### Plan Viewer
- **Plan Details**: View plan parameters, metadata, and execution results
- **Parameter Display**: All parameters shown with correct Python syntax and types
- **Copy to Queue**: Duplicate plans with one click

```bash
# 1) Start RE Manager
start-re-manager --use-ipython-kernel=ON --zmq-publish-console=ON
### Console Monitor
- **Live Console Output**: Real-time streaming of Queue Server console output
- **WebSocket Support**: Efficient streaming via WebSocket connections (fallback to HTTP polling)
- **Autoscroll**: Automatically scroll to latest output with toggle control

## Quick Start

### Prerequisites

# 2) Start HTTP Server
QSERVER_HTTP_SERVER_SINGLE_USER_API_KEY=a \
uvicorn --host localhost --port 60610 bluesky_httpserver.server:app
````
- **Java 17** or later
- **Maven** (for building from source)
- **Bluesky Queue Server** running and accessible

---
### Starting a Local Queue Server

## Configure
Use the provided Docker setup for local development:

```bash
export BLUESKY_API_KEY=a
cd services/bluesky-services
docker-compose --profile container-redis up -d
```

---
This starts:
- Bluesky Queue Server (RE Manager) on ports 60615/60625
- HTTP Server REST API on port 60610
- Redis database on port 6380

## Build & run
For details, see [services/bluesky-services/README.md](../../services/bluesky-services/README.md)

```bash
mvn clean javafx:run
```
### Configuration

### Verbose logging
Set environment variables to connect to your Queue Server:

```bash
mvn -Djava.util.logging.config.file=src/main/resources/logging.properties javafx:run
```
# Queue Server HTTP address (default: http://localhost:60610)
export QSERVER_HTTP_SERVER_URI=http://localhost:60610

---
# API Key authentication
export QSERVER_HTTP_SERVER_API_KEY=a

## CLI / REPL (testing only)
# Or use a file containing the API key
export QSERVER_HTTP_SERVER_API_KEYFILE=~/.phoebus/qserver_api_key.txt
```

| Tool | Start (quiet) | Start with request tracing (`FINE`) |
| -------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **CLI** | `mvn -q -Dexec.mainClass=util.org.phoebus.applications.queueserver.RunEngineCli -Dexec.args="STATUS" exec:java` | `mvn -Djava.util.logging.config.file=src/main/resources/logging.properties -q -Dexec.mainClass=util.org.phoebus.applications.queueserver.RunEngineCli -Dexec.args="STATUS" exec:java` |
| **REPL** | `mvn -q -Dexec.mainClass=util.org.phoebus.applications.queueserver.RunEngineRepl exec:java` | `mvn -Djava.util.logging.config.file=src/main/resources/logging.properties -q -Dexec.mainClass=util.org.phoebus.applications.queueserver.RunEngineRepl -Dexec.args="STATUS" exec:java` |
### Building & Running

*CLI examples*
#### As Part of Phoebus

```bash
# list endpoints
mvn -q -Dexec.mainClass=com.jbi.util.RunEngineClili -Dexec.args="list" exec:java

# start the queue
mvn -q -Dexec.mainClass=com.jbi.util.RunEngineClili -Dexec.args="QUEUE_START" exec:java
# From phoebus root directory
mvn clean install -DskipTests
cd phoebus-product/target
./phoebus
```

`ENDPOINT [body]` accepts a JSON literal, `@file.json`, or `@-` for stdin.
Then open **Applications → Queue Server** from the menu.

---
#### Standalone Build

## How logging works
```bash
# From queue-server directory
cd app/queue-server
mvn clean install
```

* Logger name: **`com.jbi.bluesky`**
* Levels
## Configuration Options

* `INFO` – API errors
* `WARNING` – transport retries
* `FINE` – each HTTP call + latency
* Enable by passing JVM flag
`-Djava.util.logging.config.file=src/main/resources/logging.properties`
Configuration via **Edit → Preferences → Queue Server** or environment variables:

---
| Preference | Environment Variable | Default | Description |
|-------------------|-----------------------------------|--------------------------|---------------------------------------|
| `queue_server_url`| `QSERVER_HTTP_SERVER_URI` | `http://localhost:60610` | Queue Server HTTP address |
| `api_key` | `QSERVER_HTTP_SERVER_API_KEY` | *(none)* | API key for authentication |
| `api_key_file` | `QSERVER_HTTP_SERVER_API_KEYFILE` | *(none)* | Path to file containing API key |
| `use_websockets` | *(none)* | `true` | Use WebSockets for streaming data |
| `connectTimeout` | *(none)* | `5000` | HTTP connection timeout (ms) |
| `debug` | *(none)* | `false` | Enable HTTP request/response logging |

## Tuning
## Contributing

```java
// rate limit (req/sec)
BlueskyHttpClient.initialize("http://localhost:60610",
System.getenv("BLUESKY_API_KEY"),
3.0);
When making changes:

// retry/back-off
// edit src/main/java/com/jbi/util/HttpSupport.java
MAX_RETRIES = 5;
INITIAL_BACKOFF_MS = 500;
BACKOFF_MULTIPLIER = 1.5;
```
1. Ensure proper Python type handling in parameter editor
2. Test with both WebSocket and HTTP fallback modes
3. Verify API key authentication works
4. Update documentation for new features
5. Follow existing code style and patterns
31 changes: 31 additions & 0 deletions app/queue-server/edit-control/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.phoebus</groupId>
<artifactId>app-queue-server</artifactId>
<version>5.0.3-SNAPSHOT</version>
</parent>
<artifactId>app-queue-server-edit-control</artifactId>
<name>${project.groupId}:${project.artifactId}</name>

<dependencies>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>app-queue-server-network</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-framework</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-ui</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.phoebus.applications.queueserver.editcontrol;

import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.phoebus.applications.queueserver.Preferences;
import org.phoebus.applications.queueserver.client.RunEngineHttpClient;
import org.phoebus.applications.queueserver.util.AppLifecycle;
import org.phoebus.applications.queueserver.util.PythonParameterConverter;
import org.phoebus.applications.queueserver.view.ViewFactory;
import javafx.scene.Parent;

import org.phoebus.framework.spi.AppInstance;
import org.phoebus.framework.spi.AppResourceDescriptor;
import org.phoebus.framework.workbench.ApplicationService;
import org.phoebus.ui.docking.DockItem;
import org.phoebus.ui.docking.DockPane;

@SuppressWarnings("nls")
public final class QueueEditControlApp implements AppResourceDescriptor {

public static final Logger logger = Logger.getLogger(QueueEditControlApp.class.getPackageName());

public static final String NAME = "queue_edit_control";
private static final String DISPLAY_NAME = "Edit & Control Queue";

static {
PythonParameterConverter.initializeInBackground();
}

@Override public String getName() { return NAME; }
@Override public String getDisplayName() { return DISPLAY_NAME; }

@Override public URL getIconURL() {
return getClass().getResource("/icons/bluesky.png");
}

@Override public AppInstance create() {
initializeHttpClient();
AppLifecycle.registerApp();

Parent root = ViewFactory.EDIT_AND_CONTROL_QUEUE.get();
QueueEditControlInstance inst = new QueueEditControlInstance(this, root);

DockItem tab = new DockItem(inst, root);
tab.addClosedNotification(AppLifecycle::unregisterApp);
DockPane.getActiveDockPane().addTab(tab);

return inst;
}

@Override public AppInstance create(java.net.URI resource) {
return ApplicationService.createInstance(NAME);
}

private static void initializeHttpClient() {
String serverUrl = Preferences.queue_server_url;
if (serverUrl == null || serverUrl.trim().isEmpty() || serverUrl.startsWith("$(")) {
serverUrl = "http://localhost:60610";
logger.log(Level.INFO, "Using default Queue Server URL: " + serverUrl);
}
String apiKey = resolveApiKey();
RunEngineHttpClient.initialize(serverUrl, apiKey);
}

private static String resolveApiKey() {
String apiKey = Preferences.api_key;
if (apiKey != null && !apiKey.trim().isEmpty() && !apiKey.startsWith("$(")) {
return apiKey.trim();
}
String keyFilePath = Preferences.api_key_file;
if (keyFilePath != null && !keyFilePath.trim().isEmpty() && !keyFilePath.startsWith("$(")) {
try {
Path path = Paths.get(keyFilePath.trim());
if (Files.exists(path)) {
return Files.readString(path).trim();
}
} catch (Exception e) {
logger.log(Level.WARNING, "Failed to read API key from file: " + keyFilePath, e);
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.phoebus.applications.queueserver.editcontrol;

import javafx.scene.Node;
import org.phoebus.framework.persistence.Memento;
import org.phoebus.framework.spi.AppDescriptor;
import org.phoebus.framework.spi.AppInstance;

final class QueueEditControlInstance implements AppInstance {

private final AppDescriptor desc;
private final Node view;

QueueEditControlInstance(AppDescriptor desc, Node view) {
this.desc = desc;
this.view = view;
}

@Override public AppDescriptor getAppDescriptor() { return desc; }
public Node create() { return view; }

@Override public void restore(Memento m) { /* nothing */ }
@Override public void save (Memento m) { /* nothing */ }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.phoebus.applications.queueserver.editcontrol;

import org.phoebus.applications.queueserver.Messages;
import org.phoebus.framework.workbench.ApplicationService;
import org.phoebus.ui.javafx.ImageCache;
import org.phoebus.ui.spi.MenuEntry;
import javafx.scene.image.Image;

public final class QueueEditControlMenuEntry implements MenuEntry {

@Override public String getName() { return Messages.EditControlQueue; }
@Override public Image getIcon() { return ImageCache.getImage(
QueueEditControlApp.class, "/icons/bluesky.png"); }
@Override public String getMenuPath() { return Messages.EditControlQueueMenuPath; }

@Override public Void call() throws Exception {
ApplicationService.createInstance(QueueEditControlApp.NAME);
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.phoebus.applications.queueserver.editcontrol.QueueEditControlApp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.phoebus.applications.queueserver.editcontrol.QueueEditControlMenuEntry
31 changes: 31 additions & 0 deletions app/queue-server/monitor/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.phoebus</groupId>
<artifactId>app-queue-server</artifactId>
<version>5.0.3-SNAPSHOT</version>
</parent>
<artifactId>app-queue-server-monitor</artifactId>
<name>${project.groupId}:${project.artifactId}</name>

<dependencies>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>app-queue-server-network</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-framework</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-ui</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Loading