thurview 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/ui/app.css +98 -5
- package/dist/ui/app.js +270 -143
- package/dist/ui/app.js.map +4 -4
- package/package.json +1 -1
- package/skills/thurview/SKILL.md +12 -4
- package/skills/thurview/references/software-map.md +71 -10
package/dist/ui/app.js
CHANGED
|
@@ -970,12 +970,12 @@
|
|
|
970
970
|
);
|
|
971
971
|
const uc = b.usecases[active];
|
|
972
972
|
body.innerHTML = "";
|
|
973
|
-
const
|
|
973
|
+
const touched2 = /* @__PURE__ */ new Map();
|
|
974
974
|
for (const op of uc.ops) {
|
|
975
975
|
const [s, c, f] = op.store.split(".");
|
|
976
976
|
const key = `${s}.${c}`;
|
|
977
|
-
if (!
|
|
978
|
-
if (f)
|
|
977
|
+
if (!touched2.has(key)) touched2.set(key, /* @__PURE__ */ new Set());
|
|
978
|
+
if (f) touched2.get(key).add(f);
|
|
979
979
|
}
|
|
980
980
|
const actorIds = [...new Set(uc.ops.map((o) => o.actor))];
|
|
981
981
|
body.appendChild(
|
|
@@ -996,7 +996,7 @@
|
|
|
996
996
|
{ class: "store" },
|
|
997
997
|
h("div", { class: "sname" }, s.label, " ", h("span", { class: "badge" }, s.kind)),
|
|
998
998
|
Object.entries(colls).map(([cid, c]) => {
|
|
999
|
-
const hit =
|
|
999
|
+
const hit = touched2.get(`${sid}.${cid}`);
|
|
1000
1000
|
return h(
|
|
1001
1001
|
"div",
|
|
1002
1002
|
{ class: `table ${hit ? "hit" : ""}` },
|
|
@@ -1797,22 +1797,12 @@
|
|
|
1797
1797
|
|
|
1798
1798
|
// src/ui/views/map.ts
|
|
1799
1799
|
init_dom();
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
{ class: "empty-state" },
|
|
1807
|
-
"No software map in this revision. The agent authors ",
|
|
1808
|
-
h("code", null, "map.yaml"),
|
|
1809
|
-
" and publishes again."
|
|
1810
|
-
)
|
|
1811
|
-
);
|
|
1812
|
-
return;
|
|
1813
|
-
}
|
|
1814
|
-
const headNodes = new Map(map.head.nodes.map((n) => [n.id, n]));
|
|
1815
|
-
const baseNodes = new Map((map.base?.nodes ?? []).map((n) => [n.id, n]));
|
|
1800
|
+
|
|
1801
|
+
// src/ui/views/map-model.ts
|
|
1802
|
+
function parentOf(id) {
|
|
1803
|
+
return id.includes(".") ? id.slice(0, id.lastIndexOf(".")) : "";
|
|
1804
|
+
}
|
|
1805
|
+
function collect(map) {
|
|
1816
1806
|
const all = /* @__PURE__ */ new Map();
|
|
1817
1807
|
for (const n of map.head.nodes)
|
|
1818
1808
|
all.set(n.id, {
|
|
@@ -1820,145 +1810,262 @@
|
|
|
1820
1810
|
status: map.diff.added.includes(n.id) ? "added" : map.diff.changed.includes(n.id) ? "changed" : ""
|
|
1821
1811
|
});
|
|
1822
1812
|
for (const id of map.diff.removed) {
|
|
1823
|
-
const n =
|
|
1813
|
+
const n = (map.base?.nodes ?? []).find((x) => x.id === id);
|
|
1824
1814
|
if (n) all.set(id, { ...n, status: "removed" });
|
|
1825
1815
|
}
|
|
1816
|
+
return all;
|
|
1817
|
+
}
|
|
1818
|
+
function changedInside(all, id) {
|
|
1819
|
+
let n = 0;
|
|
1820
|
+
for (const item of all.values()) if (item.id.startsWith(id + ".") && item.status) n++;
|
|
1821
|
+
return n;
|
|
1822
|
+
}
|
|
1823
|
+
function touched(all, item) {
|
|
1824
|
+
return !!item.status || changedInside(all, item.id) > 0;
|
|
1825
|
+
}
|
|
1826
|
+
function childrenOf(all, parent, filesByNode) {
|
|
1827
|
+
const kids = [...all.values()].filter((n) => parentOf(n.id) === parent);
|
|
1828
|
+
const weight = (n) => (filesByNode[n.id]?.length ?? 0) + changedInside(all, n.id);
|
|
1829
|
+
return kids.map((n, i) => ({ n, i })).sort((a, b) => {
|
|
1830
|
+
const t = Number(touched(all, b.n)) - Number(touched(all, a.n));
|
|
1831
|
+
if (t) return t;
|
|
1832
|
+
const w = weight(b.n) - weight(a.n);
|
|
1833
|
+
return w || a.i - b.i;
|
|
1834
|
+
}).map((x) => x.n);
|
|
1835
|
+
}
|
|
1836
|
+
function routeIn(all, filesByNode) {
|
|
1837
|
+
const changed = [...all.values()].filter((n) => n.status);
|
|
1838
|
+
const hasChild = (id) => [...all.keys()].some((k) => parentOf(k) === id);
|
|
1839
|
+
const leaves = changed.filter((n) => !hasChild(n.id));
|
|
1840
|
+
const pool = leaves.length ? leaves : changed;
|
|
1841
|
+
let best = null;
|
|
1842
|
+
let bestFiles = -1;
|
|
1843
|
+
for (const n of pool) {
|
|
1844
|
+
const files = filesByNode[n.id]?.length ?? 0;
|
|
1845
|
+
if (files > bestFiles) {
|
|
1846
|
+
best = n;
|
|
1847
|
+
bestFiles = files;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
return best;
|
|
1851
|
+
}
|
|
1852
|
+
function neighboursOf(map, id) {
|
|
1853
|
+
const out = [];
|
|
1854
|
+
const into = [];
|
|
1855
|
+
for (const e of allEdges(map)) {
|
|
1856
|
+
if (e.from === id)
|
|
1857
|
+
out.push({ dir: "out", other: e.to, ...e.label ? { label: e.label } : {} });
|
|
1858
|
+
if (e.to === id)
|
|
1859
|
+
into.push({ dir: "in", other: e.from, ...e.label ? { label: e.label } : {} });
|
|
1860
|
+
}
|
|
1861
|
+
return [...out, ...into];
|
|
1862
|
+
}
|
|
1863
|
+
function allEdges(map) {
|
|
1826
1864
|
const edges = [...map.head.edges];
|
|
1827
1865
|
for (const e of map.base?.edges ?? [])
|
|
1828
1866
|
if (!edges.some((x) => x.from === e.from && x.to === e.to)) edges.push(e);
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1867
|
+
return edges;
|
|
1868
|
+
}
|
|
1869
|
+
function rankEdges(edges, all) {
|
|
1870
|
+
const hot = (id) => {
|
|
1871
|
+
const item = all.get(id);
|
|
1872
|
+
return item && touched(all, item) ? 1 : 0;
|
|
1873
|
+
};
|
|
1874
|
+
return edges.map((edge, i) => ({ edge, i, ends: hot(edge.from) + hot(edge.to) })).sort((a, b) => b.ends - a.ends || a.i - b.i).map(({ edge, ends }) => ({ edge, touchesChange: ends > 0 }));
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
// src/ui/views/map.ts
|
|
1878
|
+
var statusClass = (s) => s === "added" ? "ok" : s === "removed" ? "del" : "warn";
|
|
1879
|
+
function renderMap(root) {
|
|
1880
|
+
const map = state.data?.map;
|
|
1881
|
+
if (!map || !map.head.nodes.length) {
|
|
1882
|
+
append(root, [
|
|
1883
|
+
h(
|
|
1884
|
+
"div",
|
|
1885
|
+
{ class: "empty-state" },
|
|
1886
|
+
h("p", null, "No map in this review."),
|
|
1887
|
+
h(
|
|
1888
|
+
"p",
|
|
1889
|
+
null,
|
|
1890
|
+
"The map places a change inside the system and shows what sits next to it. ",
|
|
1891
|
+
"A change that lands in one place, where the Files tab already answers that, ships without one."
|
|
1892
|
+
)
|
|
1893
|
+
)
|
|
1894
|
+
]);
|
|
1895
|
+
return;
|
|
1837
1896
|
}
|
|
1897
|
+
const headNodes = new Map(map.head.nodes.map((n) => [n.id, n]));
|
|
1898
|
+
const baseNodes = new Map((map.base?.nodes ?? []).map((n) => [n.id, n]));
|
|
1899
|
+
const all = collect(map);
|
|
1900
|
+
const edges = allEdges(map);
|
|
1901
|
+
const route = routeIn(all, map.filesByNode);
|
|
1902
|
+
const selected = state.params.get("node") ?? "";
|
|
1903
|
+
const hasChildren = (id) => [...all.keys()].some((k) => parentOf(k) === id);
|
|
1904
|
+
let level = selected && all.has(selected) ? hasChildren(selected) ? selected : parentOf(selected) : "";
|
|
1838
1905
|
const canvas = h("div", { class: "map-canvas" });
|
|
1839
1906
|
const side2 = h("div", { class: "map-side" });
|
|
1840
1907
|
root.appendChild(h("div", { class: "map-layout" }, canvas, side2));
|
|
1841
|
-
const
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1908
|
+
const openLevel = (id) => {
|
|
1909
|
+
level = id;
|
|
1910
|
+
draw();
|
|
1911
|
+
};
|
|
1912
|
+
const intro = () => {
|
|
1913
|
+
const counts = [
|
|
1914
|
+
[map.diff.added.length, "ok", "added"],
|
|
1915
|
+
[map.diff.changed.length, "warn", "changed"],
|
|
1916
|
+
[map.diff.removed.length, "del", "removed"]
|
|
1917
|
+
];
|
|
1918
|
+
const marks = counts.filter(([n]) => n > 0);
|
|
1919
|
+
return h(
|
|
1920
|
+
"div",
|
|
1921
|
+
{ class: "map-intro" },
|
|
1922
|
+
h("h2", null, "Where the change landed"),
|
|
1846
1923
|
h(
|
|
1847
|
-
"
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
"
|
|
1924
|
+
"p",
|
|
1925
|
+
null,
|
|
1926
|
+
"The Files tab has the lines. This has the parts of the system they landed in, and what",
|
|
1927
|
+
" those parts connect to \u2014 the neighbours a diff never names. Marked parts are the change;",
|
|
1928
|
+
" the rest is the context you need to judge it."
|
|
1929
|
+
),
|
|
1930
|
+
h(
|
|
1931
|
+
"div",
|
|
1932
|
+
{ class: "map-route" },
|
|
1933
|
+
marks.length ? marks.map(([n, cls, word]) => h("span", { class: `badge ${cls}` }, `${n} ${word}`)) : h("span", { class: "muted" }, "This change touched no part of the map."),
|
|
1934
|
+
route ? h(
|
|
1935
|
+
"button",
|
|
1936
|
+
{
|
|
1937
|
+
class: "small",
|
|
1938
|
+
onclick: () => navigate("map", { node: route.id })
|
|
1939
|
+
},
|
|
1940
|
+
`Start at ${route.label} \u203A`
|
|
1941
|
+
) : null,
|
|
1942
|
+
map.base ? null : h(
|
|
1943
|
+
"span",
|
|
1944
|
+
{ class: "muted" },
|
|
1945
|
+
"No base map, so changed means touched by the diff and nothing reads as added or removed."
|
|
1946
|
+
)
|
|
1855
1947
|
)
|
|
1856
1948
|
);
|
|
1949
|
+
};
|
|
1950
|
+
const crumbs = () => {
|
|
1951
|
+
const el = h("div", { class: "crumbs" });
|
|
1952
|
+
const parts = level ? level.split(".") : [];
|
|
1953
|
+
el.appendChild(h("span", { onclick: () => openLevel("") }, "System"));
|
|
1857
1954
|
parts.forEach((_, i) => {
|
|
1858
1955
|
const id = parts.slice(0, i + 1).join(".");
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
h(
|
|
1862
|
-
"span",
|
|
1863
|
-
{
|
|
1864
|
-
onclick: () => {
|
|
1865
|
-
level = id;
|
|
1866
|
-
draw();
|
|
1867
|
-
}
|
|
1868
|
-
},
|
|
1869
|
-
all.get(id)?.label ?? id
|
|
1870
|
-
)
|
|
1871
|
-
);
|
|
1956
|
+
el.appendChild(document.createTextNode(" \u203A "));
|
|
1957
|
+
el.appendChild(h("span", { onclick: () => openLevel(id) }, all.get(id)?.label ?? id));
|
|
1872
1958
|
});
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1959
|
+
return el;
|
|
1960
|
+
};
|
|
1961
|
+
const card = (n) => {
|
|
1962
|
+
const inside = [...all.keys()].filter((k) => parentOf(k) === n.id).length;
|
|
1963
|
+
const hidden = changedInside(all, n.id);
|
|
1964
|
+
const files = map.filesByNode[n.id]?.length ?? 0;
|
|
1965
|
+
return h(
|
|
1876
1966
|
"div",
|
|
1877
|
-
{
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
h("span", { class:
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
h(
|
|
1892
|
-
"
|
|
1967
|
+
{
|
|
1968
|
+
class: `map-node ${n.status} ${touched(all, n) ? "" : "quiet"} ${n.id === selected ? "selected" : ""}`,
|
|
1969
|
+
onclick: () => navigate("map", { node: n.id }),
|
|
1970
|
+
ondblclick: () => inside && openLevel(n.id)
|
|
1971
|
+
},
|
|
1972
|
+
n.status ? h("span", { class: `status badge ${statusClass(n.status)}` }, n.status) : null,
|
|
1973
|
+
h("div", { class: "kind" }, n.kind),
|
|
1974
|
+
h("div", { class: "label" }, n.label),
|
|
1975
|
+
n.description ? h("div", { class: "desc" }, n.description) : null,
|
|
1976
|
+
h(
|
|
1977
|
+
"div",
|
|
1978
|
+
{ class: "meta" },
|
|
1979
|
+
files ? h("span", { class: "warn-text" }, `${files} changed file${files > 1 ? "s" : ""}`) : null,
|
|
1980
|
+
hidden ? h("span", { class: "warn-text" }, `${hidden} changed inside`) : null,
|
|
1981
|
+
inside ? h(
|
|
1982
|
+
"button",
|
|
1893
1983
|
{
|
|
1894
|
-
class:
|
|
1895
|
-
onclick: () => {
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
ondblclick: () => {
|
|
1899
|
-
if (nk) {
|
|
1900
|
-
level = n.id;
|
|
1901
|
-
draw();
|
|
1902
|
-
}
|
|
1984
|
+
class: "small drill",
|
|
1985
|
+
onclick: (e) => {
|
|
1986
|
+
e.stopPropagation();
|
|
1987
|
+
openLevel(n.id);
|
|
1903
1988
|
}
|
|
1904
1989
|
},
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1990
|
+
`Open ${inside} inside \u203A`
|
|
1991
|
+
) : null
|
|
1992
|
+
)
|
|
1993
|
+
);
|
|
1994
|
+
};
|
|
1995
|
+
const board = () => {
|
|
1996
|
+
const kids = childrenOf(all, level, map.filesByNode);
|
|
1997
|
+
if (!kids.length) return h("div", { class: "empty-state" }, "Nothing at this level.");
|
|
1998
|
+
const hot = kids.filter((n) => touched(all, n));
|
|
1999
|
+
const cold = kids.filter((n) => !touched(all, n));
|
|
2000
|
+
const group = (title, items) => items.length ? h(
|
|
2001
|
+
"div",
|
|
2002
|
+
{ class: "map-group" },
|
|
2003
|
+
title ? h("h3", null, title) : null,
|
|
2004
|
+
h("div", { class: "map-grid" }, items.map(card))
|
|
2005
|
+
) : null;
|
|
2006
|
+
if (!hot.length)
|
|
2007
|
+
return h(
|
|
2008
|
+
"div",
|
|
2009
|
+
null,
|
|
2010
|
+
h("div", { class: "map-note muted" }, "Nothing here was touched. The change is elsewhere."),
|
|
2011
|
+
group(null, cold)
|
|
1923
2012
|
);
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2013
|
+
return h(
|
|
2014
|
+
"div",
|
|
2015
|
+
null,
|
|
2016
|
+
group(cold.length ? "What the change touched" : null, hot),
|
|
2017
|
+
group("Context \u2014 unchanged here", cold)
|
|
2018
|
+
);
|
|
2019
|
+
};
|
|
2020
|
+
const links = () => {
|
|
2021
|
+
const here = new Set(childrenOf(all, level, map.filesByNode).map((k) => k.id));
|
|
1929
2022
|
const top = (id) => {
|
|
1930
2023
|
let x = id;
|
|
1931
2024
|
while (x && !here.has(x)) x = parentOf(x);
|
|
1932
2025
|
return x;
|
|
1933
2026
|
};
|
|
1934
|
-
const
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
2027
|
+
const folded = [];
|
|
2028
|
+
for (const e of edges) {
|
|
2029
|
+
const from = top(e.from) || e.from;
|
|
2030
|
+
const to = top(e.to) || e.to;
|
|
2031
|
+
if (from === to) continue;
|
|
2032
|
+
if (!here.has(from) && !here.has(to)) continue;
|
|
2033
|
+
if (folded.some((x) => x.from === from && x.to === to)) continue;
|
|
2034
|
+
folded.push({ from, to, ...e.label ? { label: e.label } : {} });
|
|
2035
|
+
}
|
|
2036
|
+
if (!folded.length) return null;
|
|
2037
|
+
return h(
|
|
2038
|
+
"div",
|
|
2039
|
+
{ class: "map-edges" },
|
|
2040
|
+
h("h3", null, "What connects to what here"),
|
|
2041
|
+
h(
|
|
2042
|
+
"div",
|
|
2043
|
+
{ class: "muted map-note" },
|
|
2044
|
+
"A link touching a changed part is where the two sides can fall out of step."
|
|
2045
|
+
),
|
|
2046
|
+
rankEdges(folded, all).map(
|
|
2047
|
+
({ edge, touchesChange }) => h(
|
|
1938
2048
|
"div",
|
|
1939
|
-
{ class: "
|
|
1940
|
-
h(
|
|
1941
|
-
|
|
1942
|
-
(
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
"b",
|
|
1953
|
-
{ onclick: () => navigate("map", { node: e.to }) },
|
|
1954
|
-
all.get(e.to)?.label ?? e.to
|
|
1955
|
-
),
|
|
1956
|
-
h("span", { class: "muted" }, e.label ?? "")
|
|
1957
|
-
)
|
|
1958
|
-
)
|
|
2049
|
+
{ class: `edge ${touchesChange ? "hot" : ""}` },
|
|
2050
|
+
h(
|
|
2051
|
+
"b",
|
|
2052
|
+
{ onclick: () => navigate("map", { node: edge.from }) },
|
|
2053
|
+
all.get(edge.from)?.label ?? edge.from
|
|
2054
|
+
),
|
|
2055
|
+
"\u2192",
|
|
2056
|
+
h(
|
|
2057
|
+
"b",
|
|
2058
|
+
{ onclick: () => navigate("map", { node: edge.to }) },
|
|
2059
|
+
all.get(edge.to)?.label ?? edge.to
|
|
2060
|
+
),
|
|
2061
|
+
h("span", { class: "muted" }, edge.label ?? "")
|
|
1959
2062
|
)
|
|
1960
|
-
)
|
|
1961
|
-
|
|
2063
|
+
)
|
|
2064
|
+
);
|
|
2065
|
+
};
|
|
2066
|
+
const draw = () => {
|
|
2067
|
+
canvas.innerHTML = "";
|
|
2068
|
+
append(canvas, [intro(), crumbs(), board(), links()]);
|
|
1962
2069
|
drawSide();
|
|
1963
2070
|
};
|
|
1964
2071
|
const drawSide = () => {
|
|
@@ -1969,7 +2076,7 @@
|
|
|
1969
2076
|
h(
|
|
1970
2077
|
"div",
|
|
1971
2078
|
{ class: "muted" },
|
|
1972
|
-
"
|
|
2079
|
+
"Pick a part to see what changed in it, the code behind it, and what it connects to."
|
|
1973
2080
|
)
|
|
1974
2081
|
);
|
|
1975
2082
|
return;
|
|
@@ -1977,19 +2084,14 @@
|
|
|
1977
2084
|
const anchor = n.anchor ? state.data?.document?.anchors[n.anchor] : null;
|
|
1978
2085
|
const files = map.filesByNode[n.id] ?? [];
|
|
1979
2086
|
const threads = threadsFor((t) => t.type === "map" && t.node === n.id);
|
|
2087
|
+
const neighbours = neighboursOf(map, n.id);
|
|
1980
2088
|
append(side2, [
|
|
1981
2089
|
h(
|
|
1982
2090
|
"div",
|
|
1983
2091
|
{ class: "kind muted", style: { fontSize: "11px", textTransform: "uppercase" } },
|
|
1984
2092
|
n.kind,
|
|
1985
2093
|
" ",
|
|
1986
|
-
n.status ? h(
|
|
1987
|
-
"span",
|
|
1988
|
-
{
|
|
1989
|
-
class: `badge ${n.status === "added" ? "ok" : n.status === "removed" ? "del" : "warn"}`
|
|
1990
|
-
},
|
|
1991
|
-
n.status
|
|
1992
|
-
) : ""
|
|
2094
|
+
n.status ? h("span", { class: `badge ${statusClass(n.status)}` }, n.status) : ""
|
|
1993
2095
|
),
|
|
1994
2096
|
h("h3", { style: { margin: "2px 0 6px" } }, n.label),
|
|
1995
2097
|
h("div", { class: "mono muted", style: { fontSize: "11px" } }, n.id),
|
|
@@ -2015,6 +2117,31 @@
|
|
|
2015
2117
|
(f) => h("span", { class: "file", onclick: () => navigate("files", { path: f }) }, f)
|
|
2016
2118
|
)
|
|
2017
2119
|
) : null,
|
|
2120
|
+
neighbours.length ? h(
|
|
2121
|
+
"div",
|
|
2122
|
+
{ class: "neighbours", style: { marginTop: "12px" } },
|
|
2123
|
+
h("b", null, "Next to it"),
|
|
2124
|
+
h(
|
|
2125
|
+
"div",
|
|
2126
|
+
{ class: "muted", style: { fontSize: "11px" } },
|
|
2127
|
+
"\u2192 this reaches \xB7 \u2190 reaches this"
|
|
2128
|
+
),
|
|
2129
|
+
neighbours.map((x) => {
|
|
2130
|
+
const other = all.get(x.other);
|
|
2131
|
+
return h(
|
|
2132
|
+
"div",
|
|
2133
|
+
{ class: "neighbour" },
|
|
2134
|
+
h("span", { class: "mono muted" }, x.dir === "out" ? "\u2192" : "\u2190"),
|
|
2135
|
+
h(
|
|
2136
|
+
"span",
|
|
2137
|
+
{ class: "nb", onclick: () => navigate("map", { node: x.other }) },
|
|
2138
|
+
other?.label ?? x.other
|
|
2139
|
+
),
|
|
2140
|
+
other?.status ? h("span", { class: `badge ${statusClass(other.status)}` }, other.status) : null,
|
|
2141
|
+
x.label ? h("span", { class: "muted" }, x.label) : null
|
|
2142
|
+
);
|
|
2143
|
+
})
|
|
2144
|
+
) : null,
|
|
2018
2145
|
h(
|
|
2019
2146
|
"div",
|
|
2020
2147
|
{ style: { marginTop: "12px" } },
|
|
@@ -2067,7 +2194,7 @@
|
|
|
2067
2194
|
"div",
|
|
2068
2195
|
{ class: "item", onclick: () => location.href = `/review/${r.id}` },
|
|
2069
2196
|
h("span", { class: "t" }, r.title),
|
|
2070
|
-
h("span", { class: `badge ${
|
|
2197
|
+
h("span", { class: `badge ${statusClass2(r.status)}` }, r.status),
|
|
2071
2198
|
r.openThreads ? h("span", { class: "badge accent" }, `${r.openThreads} open`) : null,
|
|
2072
2199
|
h(
|
|
2073
2200
|
"span",
|
|
@@ -2087,7 +2214,7 @@
|
|
|
2087
2214
|
}
|
|
2088
2215
|
app.appendChild(el);
|
|
2089
2216
|
}
|
|
2090
|
-
function
|
|
2217
|
+
function statusClass2(s) {
|
|
2091
2218
|
return s === "accepted" ? "ok" : s === "awaiting-agent-updates" ? "warn" : s === "closed" ? "del" : s === "awaiting-review" ? "accent" : "";
|
|
2092
2219
|
}
|
|
2093
2220
|
var center;
|
|
@@ -2153,7 +2280,7 @@
|
|
|
2153
2280
|
const identity = h("div", { class: "bar-row bar-identity" }, [
|
|
2154
2281
|
h("a", { href: "/", class: "brand", title: "All reviews" }, "thurview"),
|
|
2155
2282
|
h("span", { class: "title", title: r.title }, r.title),
|
|
2156
|
-
h("span", { class: `badge ${
|
|
2283
|
+
h("span", { class: `badge ${statusClass2(r.status)}` }, r.status),
|
|
2157
2284
|
r.revision > 1 ? revSel : h("span", { class: "badge bar-rev" }, `rev ${r.revision}`),
|
|
2158
2285
|
h(
|
|
2159
2286
|
"span",
|