Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

### Added
- DZDP concentration view in geolocation explorer with hero stats, anchor point map, country bar chart, ASN concentration list, and CTA banner (#550)
- View switcher (QA Explorer / DZDP Concentration / DZDP Validators) with URL query param sync (#550)
8 changes: 6 additions & 2 deletions api/handlers/geo_concentration.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"math"
"net/http"
"sort"
Expand Down Expand Up @@ -150,9 +151,12 @@ func (a *API) FetchGeoConcentrationData(ctx context.Context) (*GeoConcentrationR
rows, err := a.DB.Query(ctx, query)
metrics.RecordClickHouseQuery(time.Since(start), err)
if err != nil {
// Return empty response when DZDP tables aren't available or accessible
// Return empty response when DZDP tables aren't available or accessible.
// Code 60 = UNKNOWN_TABLE, Code 81 = UNKNOWN_DATABASE, Code 497 = NOT_ENOUGH_PRIVILEGES.
var chErr *proto.Exception
if errors.As(err, &chErr) && (chErr.Code == 60 || chErr.Code == 497) {
if errors.As(err, &chErr) && (chErr.Code == 60 || chErr.Code == 81 || chErr.Code == 497) {
slog.Warn("geo concentration: DZDP tables not available, returning empty response",
"dzdp_db", dzdpDB, "ch_error_code", chErr.Code, "error", err)
return &GeoConcentrationResponse{
Metros: []GeoConcentrationMetro{},
Countries: []GeoConcentrationCountry{},
Expand Down
8 changes: 6 additions & 2 deletions api/handlers/geo_validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"math"
"net/http"
"sort"
Expand Down Expand Up @@ -181,9 +182,12 @@ func (a *API) FetchGeoValidatorsData(ctx context.Context, metro, dzFilter string
rows, err := a.DB.Query(ctx, query)
metrics.RecordClickHouseQuery(time.Since(start), err)
if err != nil {
// Return empty response when DZDP tables aren't available or accessible
// Return empty response when DZDP tables aren't available or accessible.
// Code 60 = UNKNOWN_TABLE, Code 81 = UNKNOWN_DATABASE, Code 497 = NOT_ENOUGH_PRIVILEGES.
var chErr *proto.Exception
if errors.As(err, &chErr) && (chErr.Code == 60 || chErr.Code == 497) {
if errors.As(err, &chErr) && (chErr.Code == 60 || chErr.Code == 81 || chErr.Code == 497) {
slog.Warn("geo validators: DZDP tables not available, returning empty response",
"dzdp_db", dzdpDB, "ch_error_code", chErr.Code, "error", err)
return &GeoValidatorsResponse{
Validators: []GeoValidatorItem{},
TierDistribution: []GeoTierDistribution{},
Expand Down
29 changes: 29 additions & 0 deletions docs/work-plan-550.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Work Plan: Issue #550 — Geolocation Explorer DZDP Concentration View

## Requirements

1. **View switcher** in `geoloc-explorer-page.tsx` with tabs: QA Explorer / DZDP Concentration / DZDP Validators
2. **URL query param sync** — `?view=concentration` etc., default to explorer
3. **DZDP Concentration view** (`dzdp-concentration-view.tsx`):
- Hero stat row (4 metric cards with warning states)
- Anchor point map (MapLibre, metro dots with proportional rings, hover tooltips)
- Stake by country horizontal bar chart (Recharts, warning badges for >8%)
- ASN concentration list (concentrated/normal badges)
- "How it works" explainer strip
- CTA banner linking to https://doublezero.xyz/geolocation-interest
4. **DZDP Validators** tab — placeholder "Coming soon"

## Design

- View switcher uses `useSearchParams` for URL state
- Concentration view uses existing `fetchGeoConcentration` API + `fetchMetros` for coordinates
- API types added to `web/src/lib/api.ts` (will be superseded when #549 merges)
- All components follow existing patterns (Tailwind v4, lucide icons, Recharts, MapLibre)

## Status

- [x] View switcher with URL param sync
- [x] DZDP Concentration view implementation
- [x] TypeScript types for API response
- [x] CHANGELOG updated
- [ ] Reviews and PR
Loading
Loading