Skip to content

Commit

Permalink
Fix HTML diff output
Browse files Browse the repository at this point in the history
Generate it from the `geojson` diff rather than the `json` one,
because the `json` one now uses hexWKB geometries.

Because the layout's a bit different, this means the JS in the
HTML template needs to do a bit more work, but it's quite achievable.
Yay for ES7
  • Loading branch information
craigds committed May 7, 2020
1 parent cec3a13 commit cb28c3b
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 39 deletions.
75 changes: 51 additions & 24 deletions sno/diff-view.html
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@
}).addTo(map)

var layerGroup = L.featureGroup()
for (let [dataset, diff] of Object.entries(DATA['sno.diff/v1+hexwkb'])) {
if (!diff.featureChanges.length) {
for (let [dataset, diff] of Object.entries(DATA)) {
if (!diff.features.length) {
continue
}

Expand All @@ -139,16 +139,18 @@
layers[dataset] = {}
featureMap[dataset] = {}

for (let change of diff.featureChanges) {
const fOld = change['-']
const fNew = change['+']
if (fOld && fNew) {
fc['updateOld'].push(fOld)
fc['updateNew'].push(fNew)
} else if (fOld) {
fc['delete'].push(fOld)
} else if (fNew) {
fc['insert'].push(fNew)
for (let change of diff.features) {
const id = change['id']
if (id.startsWith('U+::')) {
fc['updateNew'].push(change)
} else if (id.startsWith('U-::')) {
fc['updateOld'].push(change)
} else if (id.startsWith('D::')) {
fc['delete'].push(change)
} else if (id.startsWith('I::')) {
fc['insert'].push(change)
} else {
console.log('unknown ID format: ' + id)
}
}

Expand Down Expand Up @@ -224,14 +226,40 @@
}
selectedFeature = [row, f]
}
function getFeaturesByRealId(diff) {
let featuresByRealId = {}
for (let fc of diff.features) {
const id = fc['id']
const realId = id.split('::')[1]
if (id.startsWith('U')) {
if (!featuresByRealId[realId]) {
featuresByRealId[realId] = [null, null]
}
if (id.startsWith('U+::')) {
// 'new'
featuresByRealId[realId][1] = fc
} else {
// 'old'
featuresByRealId[realId][0] = fc
}
} else if (id.startsWith('D::')) {
featuresByRealId[realId] = [fc, null]
} else if (id.startsWith('I::')) {
featuresByRealId[realId] = [fc, null]
} else {
console.log('unknown ID format: ' + id)
continue
}
}
return featuresByRealId
}

function getSchema(diff) {
function getSchema(featuresByRealId) {
// if schema has changed then it'll show up in every single feature
let oldSchema = null
let newSchema = null
for (let change of diff.featureChanges) {
const fOld = change['-']
const fNew = change['+']
for (let [realId, change] of Object.entries(featuresByRealId)) {
let [fOld, fNew] = change
if (fOld && !oldSchema) {
oldSchema = Object.keys(fOld.properties)
oldSchema.splice(0, 0, GEOM)
Expand Down Expand Up @@ -273,8 +301,8 @@
return isArrayEqual(a.coordinates, b.coordinates)
}

for (let [dataset, diff] of Object.entries(DATA['sno.diff/v1+hexwkb'])) {
if (!diff.featureChanges.length) {
for (let [dataset, diff] of Object.entries(DATA)) {
if (!diff.features.length) {
continue
}

Expand All @@ -288,7 +316,8 @@
let thead = table.createTHead()
let row = thead.insertRow()

let schema = getSchema(diff)
let features = getFeaturesByRealId(diff)
let schema = getSchema(features)

for (let col of schema) {
let th = document.createElement("th")
Expand All @@ -300,18 +329,16 @@
}

let tbody = table.createTBody()
for (let fc of diff.featureChanges) {
let fOld = fc['-']
let fNew = fc['+']
let change;
for (let [realId, fc] of Object.entries(features)) {
let [fOld, fNew] = fc
let change
if (fOld && fNew) {
change = 'update'
} else if (fOld) {
change = 'delete'
} else {
change = 'insert'
}

fOld = fOld || {properties: {}}
fNew = fNew || {properties: {}}
let oldRow = document.createElement('tr')
Expand Down
43 changes: 28 additions & 15 deletions sno/diff_output.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import contextlib
import io
import json
import os
import string
import sys
import tempfile
import webbrowser
from pathlib import Path

import click
from osgeo import ogr

from . import gpkg
from .output_util import dump_json_output, resolve_output_path
Expand Down Expand Up @@ -154,7 +155,7 @@ def repr_row(row, prefix="", exclude=None):


@contextlib.contextmanager
def diff_output_geojson(*, output_path, dataset_count, json_style, **kwargs):
def diff_output_geojson(*, output_path, dataset_count, json_style='pretty', **kwargs):
"""
Contextmanager.
Expand Down Expand Up @@ -196,6 +197,8 @@ def diff_output_geojson(*, output_path, dataset_count, json_style, **kwargs):
def _out(dataset, diff):
if not output_path or output_path == '-':
fp = sys.stdout
elif isinstance(output_path, io.StringIO):
fp = output_path
elif output_path.is_dir():
fp = (output_path / f"{dataset.name}.geojson").open("w")
else:
Expand Down Expand Up @@ -343,27 +346,37 @@ def diff_output_html(*, output_path, repo, base, target, dataset_count, **kwargs
raise click.BadParameter(
"Directory is not valid for --output with --html", param_hint="--output"
)

json_data = io.StringIO()
with diff_output_json(
output_path=json_data, dataset_count=dataset_count
) as json_writer:
yield json_writer

with open(
Path(__file__).resolve().with_name("diff-view.html"), "r", encoding="utf8"
) as ft:
template = string.Template(ft.read())

title = f"{Path(repo.path).name}: {base.short_id} .. {target.short_id if target else 'working-copy'}"

if not output_path:
output_path = Path(repo.path) / "DIFF.html"
fo = resolve_output_path(output_path)
with tempfile.TemporaryDirectory() as tempdir:
tempdir = Path(tempdir)
# Write a bunch of geojson files to a temporary directory
with diff_output_geojson(
output_path=tempdir, dataset_count=dataset_count, json_style="extracompact",
) as json_writer:
yield json_writer

fo.write(
template.substitute({"title": title, "geojson_data": json_data.getvalue()})
)
if not output_path:
output_path = Path(repo.path) / "DIFF.html"
fo = resolve_output_path(output_path)

# Read all the geojson back in, and stick them in a dict
all_datasets_geojson = {}
for filename in os.listdir(tempdir):
with open(tempdir / filename) as json_file:
all_datasets_geojson[os.path.splitext(filename)[0]] = json.load(
json_file
)
fo.write(
template.substitute(
{"title": title, "geojson_data": json.dumps(all_datasets_geojson)}
)
)
if fo != sys.stdout:
fo.close()
webbrowser.open_new(f"file://{output_path.resolve()}")

0 comments on commit cb28c3b

Please sign in to comment.