Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
151bee3
Add README files, eslint and gitignore
QSparks Mar 18, 2026
d1f426c
Add css styles
QSparks Mar 18, 2026
e82f88f
Add THREDDS config and Dockerfile
QSparks Mar 18, 2026
2af8b62
Add core config constants and DOM bindings
QSparks Mar 18, 2026
ab8247e
Add time parsing, metadata, and UI controllers
QSparks Mar 18, 2026
d868e71
Add map controller: WMS, palettes, projections
QSparks Mar 18, 2026
9d931db
Add portal menu and dataset loading
QSparks Mar 18, 2026
89594c5
Add spatial/temporal subsetting and download
QSparks Mar 18, 2026
37490cc
Add app entry point and event wiring
QSparks Mar 18, 2026
66ad46a
Add Dockerfile, nginx config, favicon, and viewer html
QSparks Mar 18, 2026
0141236
Set threddsRoot to expected treafik prefix
QSparks Mar 18, 2026
e2d367e
Add docker publish and ESlint workflows
QSparks Mar 18, 2026
34c41a7
Include traefik prefix for ncpartitioner
QSparks Mar 18, 2026
c92dbd8
Add portal-meta route
QSparks Mar 18, 2026
79e2564
Use absolute pdp-next asset paths in viewer HTML
QSparks Mar 18, 2026
9822281
Use PDP title
QSparks Mar 19, 2026
63ef5ff
Add default portal, validate portal Ids
QSparks Mar 19, 2026
1164de1
Use tiled WMS
QSparks Mar 19, 2026
8d842da
Add map scale constraints
QSparks Mar 19, 2026
1b3e575
Fix time slider wrap
QSparks Mar 19, 2026
52c145b
Draw BBOX on top, reproject on proj change
QSparks Mar 19, 2026
9fc9fac
Prevent subset download double or spam clicks
QSparks Mar 19, 2026
e859300
Fix feedback panel
QSparks Mar 19, 2026
d6710c8
Fix mobile overflow from logo
QSparks Mar 19, 2026
18cf760
Use radio buttons for time subsetting options
QSparks Mar 19, 2026
ef724d3
Logic fixes and proj defaults
QSparks Mar 19, 2026
57a76e2
Demo only Canada Mosaics and PRISM
QSparks Mar 25, 2026
c90b056
Fix radio button visibility bug
QSparks Mar 26, 2026
6b74b3b
Add varnish default.vcl
QSparks Mar 27, 2026
95914fe
Set min COLORSCALERANGE for pr
QSparks Apr 1, 2026
d73a7d6
Fix Legend, portal and variable labels
QSparks Apr 1, 2026
1f42a03
Fix Legend header and units
QSparks Apr 1, 2026
77bd77e
Pin monthly averages at top of of PRISM portal
QSparks Apr 1, 2026
98aa58c
Normalize legend temperature units to °C
QSparks Apr 1, 2026
3191e98
Add followup changes for labels and limits
QSparks Apr 1, 2026
d969ace
Use thredds service name in default.vcl
QSparks Apr 2, 2026
06bb590
WIP: async subsets, refactor download.js, poll status url
QSparks Jun 18, 2026
3f589a0
download.js: fix statusUrl
QSparks Jun 18, 2026
1b1910d
Align URLs with BE
QSparks Jun 19, 2026
49a7e91
Add queue position
QSparks Jun 22, 2026
a21d9bc
Add switch to full download option for large subsets
QSparks Jun 22, 2026
7a20aeb
Fix time range, guard extension
QSparks Jun 29, 2026
5054a6e
Improve full download prompt
QSparks Jun 29, 2026
8f64b0a
Add click-out to cancel large subset
QSparks Jun 30, 2026
43f9f53
Add chunk progress details
QSparks Jul 3, 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
40 changes: 40 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Docker Publishing

on:
push:
branches:
- '*'
tags:
- '[0-9]+.[0-9]+.[0-9]+'

jobs:
publish-images:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.pcicdevops_at_dockerhub_username }}
password: ${{ secrets.pcicdevops_at_dockerhub_password }}

- name: Build and Publish Viewer
uses: docker/build-push-action@v4
with:
context: .
file: ./viewer/Dockerfile
push: true
tags: |
pcic/pdp-next-viewer:${{ github.ref_name }}
${{ github.ref_name == 'main' && 'pcic/pdp-next-viewer:latest' || '' }}

- name: Build and Publish THREDDS
uses: docker/build-push-action@v4
with:
context: ./thredds
file: ./thredds/Dockerfile.thredds
push: true
tags: |
pcic/pdp-next-thredds:${{ github.ref_name }}
${{ github.ref_name == 'main' && 'pcic/pdp-next-thredds:latest' || '' }}
32 changes: 32 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Lint

on:
push:
branches: [main]
paths:
- 'viewer/js/**'
- 'eslint.config.mjs'
- 'package.json'
pull_request:
paths:
- 'viewer/js/**'
- 'eslint.config.mjs'
- 'package.json'

jobs:
eslint:
name: ESLint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Lint (errors fail, warnings annotate)
run: npm run lint:ci
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
__pycache__/
*.pyc
*.pyo
.venv/
.env
*/logs/*
*/ncpartitioner-output/*
node_modules/
23 changes: 23 additions & 0 deletions MENU_STRUCTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Menu Structure

This file describes the menu schemas currently generated into `portal-meta/<portal>.json`.

## Schemas

- `prism`: `period -> frequency -> variable`
- `canada_mosaic`: `period -> frequency -> variable`
- `gridded_daily`: `source -> variable`
- `vicgl`: `scenario -> model -> variable`
- `bccaqv2`: `scenario -> model -> run -> variable`
- `bccaqv2_u5`: `scenario -> model -> run -> variable`
- `bccaqv2_u6`: `scenario -> model -> run -> variable`
- `canesm5_u6`: `scenario -> model -> run -> variable`
- `canesm5_m6`: `scenario -> model -> run -> variable`
- `mbcn`: `scenario -> model -> run -> variable`

## Notes

- Menu labels and portal-specific derivation live in `portal_meta_builder/portals.py`.
- Normalized metadata used by menu builders is created in `portal_meta_builder/metadata.py` under `metadata.derived`.
- `bccaqv2_u6` also emits alternate scenario labels with a `(PCIC12)` suffix for the PCIC12 subset.
- `vicgl` uses metadata fields such as forcing type, experiment, model, and dataset identifiers to distinguish historical baseline output from downscaled GCM runs.
63 changes: 61 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,61 @@
# pdp-next
THREDDS-backed, database-free replacement for the PCIC Data Portal (PDP) with projection support, efficient subsetting, and improved map styling.
# PDP-Next

THREDDS-backed, database-free replacement for the Pacific Climate Data Portal (PDP) with projection support, faster subsetting, additional palettes, and portal-based interactive map viewing.

## Layout

- `scripts/`: operational entrypoints
- `portal_meta_builder/`: shared metadata parsing and menu-building code
- `portal-prep/portal-file-patterns/`: source-of-truth file patterns for each portal
- `portal-meta/`: generated per-portal metadata JSON consumed by the viewer
- `viewer/`: current frontend/viewer assets
- `thredds/`: local THREDDS config and support files

## Current Metadata Flow

1. Build or refresh the `/pdp/<portal>/<file>.nc` hardlink mirror from portal file patterns.
2. Optionally compute min/max rendering metadata for selected files.
3. Build `portal-meta/<portal>.json` from NetCDF metadata and normalized derived fields.

The metadata builder reads NetCDF metadata, normalizes common fields into `metadata.derived`, and applies per-portal
menu rules from `portal_meta_builder/portals.py`.

## Scripts

### Build hardlink mirror

```bash
python3 scripts/gen_hardlinks.py
python3 scripts/gen_hardlinks.py --portal prism --portal vicgl
```

Uses file-pattern definitions from `portal-prep/portal-file-patterns/`.

### Compute rendering min/max CSV

```bash
python3 scripts/calculate-portal-minmax.py
python3 scripts/calculate-portal-minmax.py --portal prism
```

Writes `portal-prep/pdp_min_max.csv`.

### Build portal metadata JSON

```bash
python3 scripts/update-portal-meta.py
python3 scripts/update-portal-meta.py --portal prism
```

Writes `portal-meta/<portal>.json`.

## Adding A New Portal

1. Add a portal pattern file at `portal-prep/portal-file-patterns/<portal>.txt`.
2. Add a portal definition in `portal_meta_builder/portals.py`.
3. Run `scripts/gen_hardlinks.py` for the portal.
4. Run `scripts/update-portal-meta.py --portal <portal>`.

If the portal needs custom menu labels or grouping, add a focused menu builder in
`portal_meta_builder/portals.py`. If it needs additional normalized metadata, add that in
`portal_meta_builder/metadata.py`.
45 changes: 45 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import js from '@eslint/js';

export default [
js.configs.recommended,
{
files: ['viewer/js/**/*.js', 'viewer/js/*.js'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
globals: {
// Browser globals
window: 'readonly',
document: 'readonly',
console: 'readonly',
fetch: 'readonly',
URL: 'readonly',
URLSearchParams: 'readonly',
DOMParser: 'readonly',
Event: 'readonly',
alert: 'readonly',
setTimeout: 'readonly',
setInterval: 'readonly',
clearInterval: 'readonly',
// CDN globals (ol and proj4 loaded via script tags)
ol: 'readonly',
proj4: 'readonly',
// Browser performance API
performance: 'readonly'
}
},
rules: {
// Errors
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-undef': 'error',
'eqeqeq': ['error', 'always', { null: 'ignore' }],
'no-implicit-coercion': ['error', { allow: ['!!', '+'] }],

// Warnings
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-alert': 'warn',

'no-prototype-builtins': 'off'
}
}
];
Loading
Loading