Skip to content

refactor web app routes#76

Merged
mzouink merged 2 commits intomainfrom
refactor_web_app
Feb 11, 2026
Merged

refactor web app routes#76
mzouink merged 2 commits intomainfrom
refactor_web_app

Conversation

@mzouink
Copy link
Copy Markdown
Member

@mzouink mzouink commented Feb 11, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 11, 2026 19:58
@mzouink
Copy link
Copy Markdown
Member Author

mzouink commented Feb 11, 2026

@krokicki

@mzouink mzouink merged commit 38160e0 into main Feb 11, 2026
@mzouink mzouink deleted the refactor_web_app branch February 11, 2026 19:59
Copy link
Copy Markdown
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 refactors the dashboard Flask app from a monolithic app.py into a blueprint-based route structure, introducing a shared state.py module for cross-route state (log streaming buffers, BBX generator state, and server URLs).

Changes:

  • Split dashboard endpoints into dedicated Flask blueprints under cellmap_flow/dashboard/routes/.
  • Added shared dashboard state in cellmap_flow/dashboard/state.py (log streaming + BBX generator state + configurable paths).
  • Updated the main dashboard app to register blueprints and wire up log streaming support.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
cellmap_flow/dashboard/app.py Creates the Flask app, attaches a log handler, and registers all dashboard blueprints.
cellmap_flow/dashboard/state.py Introduces shared global state (log buffers/clients, BBX generator state, and helper for blockwise task dir).
cellmap_flow/dashboard/routes/index_page.py Serves the main index page and injects global state into templates.
cellmap_flow/dashboard/routes/pipeline_builder_page.py Serves the pipeline builder UI and hydrates UI state from g.
cellmap_flow/dashboard/routes/pipeline.py Adds pipeline APIs (apply/validate/process, dataset path, blockwise config).
cellmap_flow/dashboard/routes/models.py Adds model catalog and model-config related APIs.
cellmap_flow/dashboard/routes/blockwise.py Adds blockwise pipeline validation, YAML generation, precheck, and submission endpoints.
cellmap_flow/dashboard/routes/bbx_generator.py Adds BBX generator endpoints backed by a Neuroglancer viewer.
cellmap_flow/dashboard/routes/logging_routes.py Adds SSE log streaming and serves a bbox JSON template.
cellmap_flow/dashboard/routes/init.py Package marker for routes.
Comments suppressed due to low confidence (1)

cellmap_flow/dashboard/app.py:48

  • create_and_run_app() sets port=0, which lets the OS choose an ephemeral port; without explicitly logging/returning the chosen port this can make the dashboard hard to discover/connect to. Consider using get_free_port() (as elsewhere in the repo) or a configurable fixed port, and log the final bind address for users.
    hostname = socket.gethostname()
    port = 0
    logger.warning(f"Host name: {hostname}")
    app.run(host="0.0.0.0", port=port, debug=False, use_reloader=False)

input_norms = get_input_normalizers()
output_postprocessors = get_postprocessors_list()
model_mergers = get_model_mergers_list()
model_catalog = g.model_catalog
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

index() assigns model_catalog = g.model_catalog and then mutates it by adding a "User" category. This modifies global state for all subsequent requests and endpoints that use g.model_catalog. Consider copying (e.g., dict(g.model_catalog)) before adding request-specific entries.

Suggested change
model_catalog = g.model_catalog
model_catalog = dict(g.model_catalog)

Copilot uses AI. Check for mistakes.
Comment on lines +250 to +254
return {
"success": True,
"task_yaml": yaml_content,
"task_config": task_yaml,
"task_paths": yaml_paths,
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

When separate_bounding_boxes_zarrs is enabled, multiple bbox-specific YAML files are written, but the response still returns task_yaml/yaml_content from the base config. This means task_yaml/task_config won’t match the YAMLs referenced by task_paths. Consider returning per-bbox YAML/config (or a mapping of path->content) when generating multiple YAMLs.

Copilot uses AI. Check for mistakes.
Comment on lines +171 to +175
with viewer.txn() as s:
try:
annotations_layer = s.layers["annotations"]
if hasattr(annotations_layer, 'annotations'):
for ann in annotations_layer.annotations:
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

finalize_bbx_generation() reads s.layers["annotations"], but the layer created in start_bbx_generator() is named "bboxes". This prevents returning the final bounding boxes.

Copilot uses AI. Check for mistakes.
Comment on lines +121 to +123
model_entry = {
"name": model.get("name"),
**model.get("params", model.get("config", {}))
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

model_entry currently expands model.get("params", model.get("config", {})). If the frontend always includes a "params" key (even as an empty dict), the model's "config" will be ignored and the generated YAML will miss required model configuration. Prefer merging config+params (with params overriding) or falling back to config when params is empty.

Suggested change
model_entry = {
"name": model.get("name"),
**model.get("params", model.get("config", {}))
config = model.get("config") or {}
if not isinstance(config, dict):
config = {}
params = model.get("params")
if not params:
combined_params = config
else:
if not isinstance(params, dict):
params = {}
combined_params = {**config, **params}
model_entry = {
"name": model.get("name"),
**combined_params

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +33
if not pipeline.get("inputs") or len(pipeline["inputs"]) == 0:
return {"valid": False, "error": "No input nodes defined"}

if not pipeline.get("outputs") or len(pipeline["outputs"]) == 0:
return {"valid": False, "error": "No output nodes defined"}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

This validation route returns plain dicts (defaulting to HTTP 200) even for validation failures. For an API endpoint, return jsonify(...) and use 4xx status codes for invalid pipelines so client-side error handling is reliable.

Copilot uses AI. Check for mistakes.
Comment on lines +125 to +129
with viewer.txn() as s:
try:
annotations_layer = s.layers["annotations"]
if hasattr(annotations_layer, 'annotations'):
for ann in annotations_layer.annotations:
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

The viewer creates an annotation layer named "bboxes", but status extraction reads from s.layers["annotations"]. This will raise KeyError and prevent returning any bounding boxes. Read from the same layer name that was created ("bboxes").

Copilot uses AI. Check for mistakes.
# Build bsub command
cores_master = blockwise_config["params"]["nb_cores_master"]
charge_group = blockwise_config["params"]["charge_group"]
queue = blockwise_config["params"]["queue"]
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Variable queue is not used.

Suggested change
queue = blockwise_config["params"]["queue"]

Copilot uses AI. Check for mistakes.


@logging_bp.route("/api/templates/bbox-json")
def get_bbox_json_template():
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

get_bbox_json_template returns tuple of size 2 and tuple of size 3.

Copilot uses AI. Check for mistakes.
import yaml
from flask import Blueprint, request

from cellmap_flow.globals import g
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Import of 'g' is not used.

Suggested change
from cellmap_flow.globals import g

Copilot uses AI. Check for mistakes.
for client_queue in log_clients:
try:
client_queue.put_nowait(log_entry)
except queue.Full:
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except queue.Full:
except queue.Full:
# Intentionally drop log entries when a client's queue is full.
# Logging should never block or raise due to slow consumers.

Copilot uses AI. Check for mistakes.
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