Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions .github/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,46 @@
- [x] Name the image frame (50), FilterDistance overlay (95), and loader z-indices in `src/blobs.js`; loader sits above `"above_annotations"` overlays.
- [x] Drop `resize_overlay_canvases()`: overlays carry `imgsz_class`, so rezoom already resizes them. Restore the FilterDistance resize call; `overlay_canvases` holds embedder canvases only.
- [x] Lint, build, jest 521/521 (both builds), Chromium e2e 94/94.

## Set class in <subtask> (context menu)

- [x] `set_counterparts_class()` in `src/index.js` + undo/redo (`set_counterparts_class` action).
- [x] Context menu item `Set class in` (only counterparts that can take the source class and differ).
- [x] Types (`index.d.ts`), `api_spec.md`, changelog.
- [x] Jest tests; lint, build, jest.

## counterpart_class_meta_key config option

- [x] `_get_counterpart_class_name` helper; override in `get_counterpart_class_changes` and `match_paste_class_id` (Copy to / Move to / paste).
- [x] Config default, `index.d.ts`, `api_spec.md`, changelog.
- [x] Jest tests; lint, build, jest.
- [x] Copies drop the `counterpart_class_meta_key` entry (like the link key).

## Review fixes (REVIEW-feature-sync-class.md)

- [x] #1 A copy/paste back into the source subtask ignores `counterpart_class_meta_key` (`use_meta_override` param).
- [x] #2 Counterpart actions' `annotation_id` is foreign: `action_owns_annotation_id` guards stamping, undo revert, fly-to boxes, `remove_recorded_events_for_annotation` and `find_stamp_before_last_action`.
- [x] Regression tests; docs; lint, build, jest.

## Class confidence display

- [x] Details menu lists non-zero class confidences (sorted; only when more than one is non-zero).
- [x] `confidence_card_classes` config (default 1): confidence card shows the top N non-zero classes.
- [x] Class pie shows the class name on slice hover.
- [x] Types, `api_spec.md`, changelog; tests; lint, build, jest; live check in browser.
- [x] Demo: mixed confidences + `confidence_card_classes: 2` in `demo/live_demo.html`.
- [x] Pie centre label: wrap only between words, shrink font to fit the circle.
- [x] Pie centre label: 8px floor, then truncate with an ellipsis.

## hover_card_text config callback

- [x] `hover_card_text(annotation, subtask_key) => string | string[] | null`: extra plain-text lines in the confidence card.
- [x] Called once per hovered annotation (cached), errors caught and logged, capped at 5 lines.
- [x] Card shows host text for every hovered spatial annotation; card toggle still wins.
- [x] Types, `api_spec.md`, changelog, demo; tests; lint, build, jest; live check.

## PR review: linked-annotation demo + local landing page

- [x] `demo/linked-subtasks.html`: Predictions (read-only) / Diff / GT with link meta key + counterpart class meta key; A/B/C direct-links case.
- [x] `demo/index.html` landing page listing every demo; `demo.js` prints the landing URL.
- [x] Lint, build; live check in browser.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

All notable changes to this project will be documented here.

## [0.32.0] - Oct 23rd, 2026
#### Added
- **Set class in `<subtask>`** context-menu item: sets an annotation's counterparts in another writable subtask to its class (matched by id, then name). Counterparts that can't take that class, or already have it, are left alone, and the item only shows when at least one would change. New `get_counterpart_class_changes()` and `set_counterparts_class()`, recorded as one undoable `set_counterparts_class` action on the target subtask.
- `counterpart_class_meta_key` config option (default `null`): an annotation's string value under this `annotation_meta` key names the class it gives its counterparts (Set class in) and copies (Copy to / Move to, paste), replacing the id/name match. Set class in leaves a counterpart alone when no class has that name. Copies drop the entry, and copies/pastes back into the source subtask ignore it.
- `Details` in the context menu lists every non-zero class confidence, highest first, when more than one class has one.
- `confidence_card_classes` config option (default `1`): the hover confidence card also lists up to N - 1 runner-up classes with non-zero confidence.
- `hover_card_text` config callback (default `null`): returns up to 5 plain-text lines that the hover confidence card shows for an annotation. Called once per hovered annotation and again after it changes.
- `demo/linked-subtasks.html`: demo of linked annotations across Diff, GT and read-only Predictions subtasks. `demo/index.html`: local landing page listing every demo.
- The class pie shows the hovered class's name in its centre. Long names break only between words, and the text shrinks to fit the circle, down to 8px, then ends in "…".

#### Fixed
- `delete_counterparts` no longer stamps, reverts or drops history for an unrelated target annotation that happens to share the source annotation's id.
## [0.31.1] - Oct 22nd, 2026
#### Changed
- Simplified ternary syntax into nullish coalescing in several locations
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ for an example of how to integrate ULabel into a React project.

## Development

The recommended way to develop new features is to use the tool as if you were running the demo. For testing new API features, you can create a new HTML file in `demo/`. The server in `demo.js` runs a static server from `demo/` so it will be served at `localhost:8080/<new-file>.html` automatically.
The recommended way to develop new features is to use the tool as if you were running the demo. For testing new API features, you can create a new HTML file in `demo/`. The server in `demo.js` runs a static server from `demo/` so it will be served at `localhost:8080/<new-file>.html` automatically. `localhost:8080/` opens a landing page (`demo/index.html`) listing every demo; add new demos there too.

### Requirements

Expand Down
Loading
Loading