Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
2343f3f
feat: Model updates to support rasterFrameStyles and raster_style_params
BryonLewis Jul 26, 2026
f576e8c
feat: Add websocket notification suppression context for sync tasks
BryonLewis Jul 26, 2026
9f00087
feat: Add preview regeneration utils and logic
BryonLewis Jul 26, 2026
e872580
feat: Add frame preview generation task
BryonLewis Jul 26, 2026
26dfcab
feat: Add query results and serializers for frame previews
BryonLewis Jul 26, 2026
e1f6046
fix: Update preview regeneration task superseding cancellation
BryonLewis Jul 26, 2026
56a9049
feat: Add preview generation for dataset conversion and flood result …
BryonLewis Jul 26, 2026
320e5f7
test: Add backend tests for frame previews
BryonLewis Jul 26, 2026
395aff0
feat: Add frame preview client types and store
BryonLewis Jul 26, 2026
7220665
feat: Add client preview rendering and viewing
BryonLewis Jul 26, 2026
0504b3c
feat: Update previews when tasks are complete
BryonLewis Jul 26, 2026
ea2342a
style: Apply linting fixes
BryonLewis Jul 26, 2026
5243401
fix: Fix analytics test
BryonLewis Jul 26, 2026
e229c7b
refactor: Remove supersede because fingerprints are unique now
BryonLewis Jul 31, 2026
adaa1cb
refactor: Move store initialization to top of file
BryonLewis Aug 5, 2026
b859a2f
fix: Fix ruff boolean default arguments for async tasks
BryonLewis Aug 9, 2026
0bc66a9
refactor: use is_multiframe_raster where possible
BryonLewis Aug 13, 2026
212c5ce
chore: Resequence migration files
BryonLewis Aug 13, 2026
1a82b8e
refactor: simplify previews_by_frame_id by removing prefetch previews
BryonLewis Aug 13, 2026
dc92b28
refactor: simplify if previews are ready
BryonLewis Aug 13, 2026
9b32957
fix: sync previews for datasets, remove duplicated code
BryonLewis Aug 13, 2026
5549cf2
refactor: remove unsused ensure_default_layer_style function
BryonLewis Aug 13, 2026
4022d63
fix: text tooltip change for preview icon
BryonLewis Aug 13, 2026
c8b6f10
fix: swap mdi-image-filter-hdr to mdi-image-size-select-large
BryonLewis Aug 13, 2026
c6c6f67
Merge branch 'master' into fingerprint-frame-layer-previews
BryonLewis Aug 13, 2026
cf19f92
chore: Resequence migration files
BryonLewis Aug 13, 2026
ca2bfa3
fix: restructure imports for framePreview.ts to prevent circular impo…
BryonLewis Aug 13, 2026
bbb9281
refactor: restructure _dispatch_frame_preview_tasks to not rely on tr…
BryonLewis Aug 14, 2026
37b2e14
refactor: remove run_mode param from convert_dataset and create_layer…
BryonLewis Aug 14, 2026
67a6e9e
refactor: remove unsused Chart stub methods
BryonLewis Aug 14, 2026
c879494
refactor: remove style/layer wrapper functions around layer.is_multif…
BryonLewis Aug 14, 2026
d842468
refactor: drop unused DEFAULT_MULTIFRAME_RASTER_STYLE_SPEC from frame…
BryonLewis Aug 14, 2026
5479c16
refactor: use layerStyleKey for all key creatin in client
BryonLewis Aug 14, 2026
f45437d
refactor: use store import parent when possible for utility functions
BryonLewis Aug 17, 2026
390d799
Merge branch 'master' into fingerprint-frame-layer-previews
BryonLewis Aug 19, 2026
80e1a2b
fix: load and display frame preview overlays before loading tiles
BryonLewis Aug 20, 2026
1eb0f1a
fix: clear frame previews, update layer style for all frames on changes
BryonLewis Aug 20, 2026
fe274a2
fix: debounce scrubbing causing loading of multiple tiles, only load …
BryonLewis Aug 20, 2026
7398399
refactor: add iconState for frame Previews, and change states
BryonLewis Aug 20, 2026
4fddb71
feat: backfill_frame_previews management command
BryonLewis Aug 26, 2026
12f1da7
feat: clear_frame_previews management command
BryonLewis Aug 26, 2026
0325da6
Merge pull request #458 from OpenGeoscience/frame-preview-fixes
BryonLewis Aug 26, 2026
7ef59e2
Merge branch 'master' into fingerprint-frame-layer-previews
BryonLewis Aug 26, 2026
72c5c75
refactor: remote _resolve_preivew_task_project and default to alyer_s…
BryonLewis Aug 27, 2026
a09c6a8
fix: precent frame previews from reordering stack, only update single…
BryonLewis Aug 27, 2026
2c792af
refactor: prevent flashes with preloaded preview data
BryonLewis Aug 27, 2026
b693148
fix: ensure deletion of layers reloads default style previews
BryonLewis Aug 27, 2026
1427287
fix: allow previews to complete while editor is open and reload the p…
BryonLewis Aug 27, 2026
5e219f0
fix: improve scrubbing frame preview performance
BryonLewis Aug 31, 2026
a94c828
fix: handle NODATA transparency in previews
BryonLewis Aug 31, 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
3 changes: 2 additions & 1 deletion sample_data/boston_floods/ingest_mbta.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import requests

from uvdat.core.models import NetworkNode, VectorData, VectorFeature
from uvdat.core.tasks.run_mode import TaskRunMode

LINE_COLORS = {
"RED": "#D31414",
Expand All @@ -30,7 +31,7 @@ def convert_dataset(dataset, options):
layer_options=options.get("layers"),
network_options=options.get("network_options"),
region_options=options.get("region_options"),
asynchronous=False,
run_mode=TaskRunMode.SYNC,
)

# Post-processing
Expand Down
3 changes: 2 additions & 1 deletion sample_data/new_york_energy/ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pathlib import Path

from uvdat.core.tasks.dataset import create_layers_and_frames
from uvdat.core.tasks.run_mode import TaskRunMode

from .export_networks import perform_export
from .import_networks import perform_import
Expand Down Expand Up @@ -34,5 +35,5 @@ def convert_dataset(dataset, options):
layer_options=options.get("layers"),
network_options=options.get("network_options"),
region_options=options.get("region_options"),
asynchronous=False,
run_mode=TaskRunMode.SYNC,
)
15 changes: 15 additions & 0 deletions uvdat/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
NetworkNode,
Project,
RasterData,
RasterFramePreview,
Region,
SizeConfig,
SizeRangeConfig,
Expand Down Expand Up @@ -69,6 +70,20 @@ class LayerStyleAdmin(admin.ModelAdmin):
list_display = ["id", "name", "layer"]


@admin.register(RasterFramePreview)
class RasterFramePreviewAdmin(admin.ModelAdmin):
list_display = [
"id",
"layer_frame",
"style_fingerprint",
"raster_style_params",
"width",
"height",
"status",
]
list_select_related = ["layer_frame"]


@admin.register(Colormap)
class ColormapAdmin(admin.ModelAdmin):
list_display = ["id", "name"]
Expand Down
Empty file.
23 changes: 23 additions & 0 deletions uvdat/core/frame_previews/fingerprint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from __future__ import annotations

import hashlib
import json
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from uvdat.core.models import LayerStyle


def _fingerprint_payload(params: dict[str, Any] | None) -> str:
return json.dumps(params or {}, sort_keys=True, default=str)


def params_fingerprint(params: dict[str, Any] | None) -> str:
"""Sha256 of ``raster_style_params`` JSON used to render preview PNGs."""
payload = _fingerprint_payload(params)
return hashlib.sha256(payload.encode()).hexdigest()


def style_fingerprint(layer_style: LayerStyle) -> str:
"""Sha256 of a style's ``raster_style_params``."""
return params_fingerprint(layer_style.raster_style_params)
93 changes: 93 additions & 0 deletions uvdat/core/frame_previews/lookup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from uvdat.core.frame_previews.fingerprint import params_fingerprint, style_fingerprint
from uvdat.core.frame_previews.types import FramePreviewData
from uvdat.core.models.frame_preview import PreviewStatus, RasterFramePreview

if TYPE_CHECKING:
from uvdat.core.models import Layer, LayerFrame


def serialize_frame_preview(preview: RasterFramePreview) -> FramePreviewData:
return FramePreviewData(
url=preview.image.url,
width=preview.width,
height=preview.height,
bounds=preview.bounds,
)


def previews_by_frame_id(
frames: list[LayerFrame],
fingerprint: str,
) -> dict[int, RasterFramePreview]:
"""Return ``{frame_id: RasterFramePreview}`` for ``fingerprint``."""
if not frames:
return {}
return {
preview.layer_frame_id: preview
for preview in RasterFramePreview.objects.filter(
layer_frame_id__in=[frame.id for frame in frames],
style_fingerprint=fingerprint,
)
}


def ordered_complete_previews(
layer: Layer,
fingerprint: str,
) -> list[FramePreviewData] | None:
"""Return serialized previews in frame order, or None if any frame is incomplete."""
if not layer.is_multiframe_raster():
return None

frames = layer.raster_frames()
by_frame = previews_by_frame_id(frames, fingerprint)
ordered = [by_frame.get(frame.id) for frame in frames]
if not all(
preview is not None and preview.status == PreviewStatus.COMPLETE and preview.image
for preview in ordered
):
return None
return [serialize_frame_preview(preview) for preview in ordered]


def preview_status_for_fingerprint(
layer: Layer,
fingerprint: str,
) -> str | None:
if not layer.is_multiframe_raster():
return None

frames = layer.raster_frames()
by_frame = previews_by_frame_id(frames, fingerprint)
if all(
(preview := by_frame.get(frame.id))
and preview.status == PreviewStatus.COMPLETE
and preview.image
for frame in frames
):
return "ready"
return "notready"


def previews_current_for_fingerprint(layer: Layer, fingerprint: str) -> bool:
"""Return whether every frame already has a complete preview for this fingerprint."""
return preview_status_for_fingerprint(layer, fingerprint) == "ready"


def layer_default_fingerprint(layer: Layer) -> str:
"""Fingerprint for layer-level default previews (default style params, else ``{}``)."""
if layer.default_style_id is not None:
return style_fingerprint(layer.default_style)
return params_fingerprint({})


def layer_default_multiframe_previews(layer: Layer) -> list[FramePreviewData] | None:
"""Previews for the layer default fingerprint (default style params or ``{}``)."""
return ordered_complete_previews(
layer,
layer_default_fingerprint(layer),
)
Loading