@bitcobblers/wod-wiki-ui 0.10.42 → 0.11.43
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/dist/{chunk-S77JRUQM.mjs → chunk-PZXX6GBK.mjs} +375 -343
- package/dist/chunk-PZXX6GBK.mjs.map +1 -0
- package/dist/extensions/index.cjs +371 -334
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.mjs +1 -1
- package/dist/index.cjs +377 -356
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -83
- package/dist/index.d.ts +20 -83
- package/dist/index.mjs +8 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-S77JRUQM.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1663,7 +1663,6 @@ var CONTENT_SOURCES = wodWikiWql.WQL_SOURCES.filter((s) => s !== "metrics");
|
|
|
1663
1663
|
function sourcePlane(source) {
|
|
1664
1664
|
return source === "metrics" ? "metrics" : "content";
|
|
1665
1665
|
}
|
|
1666
|
-
var METRICS_ONLY_TYPES = /* @__PURE__ */ new Set(["agg", "metric", "groupby", "rollup", "unit"]);
|
|
1667
1666
|
var SOURCE_OPTIONS = [
|
|
1668
1667
|
{ value: "journal", label: "Journal", description: "Find notes in the personal journal" },
|
|
1669
1668
|
{ value: "collections", label: "Collections", description: "Find notes in workout catalogs" },
|
|
@@ -1741,263 +1740,6 @@ function getClauseMeta(type) {
|
|
|
1741
1740
|
description: ""
|
|
1742
1741
|
};
|
|
1743
1742
|
}
|
|
1744
|
-
function clauseToWql(clause) {
|
|
1745
|
-
if (!clause.value.trim()) return {};
|
|
1746
|
-
const val = clause.value.trim();
|
|
1747
|
-
switch (clause.type) {
|
|
1748
|
-
case "text": {
|
|
1749
|
-
const needsQuotes = /\s/.test(val) && !(val.startsWith('"') && val.endsWith('"'));
|
|
1750
|
-
return { filterStr: `text:${needsQuotes ? `"${val}"` : val}` };
|
|
1751
|
-
}
|
|
1752
|
-
case "catalog":
|
|
1753
|
-
return { filterStr: `catalog:${val}` };
|
|
1754
|
-
case "tag":
|
|
1755
|
-
return { filterStr: `tags:${val}` };
|
|
1756
|
-
case "effort":
|
|
1757
|
-
return { filterStr: `effort:${val}` };
|
|
1758
|
-
case "discipline":
|
|
1759
|
-
return { filterStr: `discipline:${val}` };
|
|
1760
|
-
case "intensity":
|
|
1761
|
-
return { filterStr: `intensity:${val}` };
|
|
1762
|
-
case "origin":
|
|
1763
|
-
return { filterStr: `origin:${val}` };
|
|
1764
|
-
case "type":
|
|
1765
|
-
return { filterStr: `type:${val}` };
|
|
1766
|
-
case "has":
|
|
1767
|
-
return { filterStr: `has:${val}` };
|
|
1768
|
-
case "result":
|
|
1769
|
-
return { filterStr: `result:${val}` };
|
|
1770
|
-
case "block":
|
|
1771
|
-
return { filterStr: `block:${val}` };
|
|
1772
|
-
case "note":
|
|
1773
|
-
return { filterStr: `note:${val}` };
|
|
1774
|
-
default: {
|
|
1775
|
-
const def = composerRegistry.getSlot(clause.type);
|
|
1776
|
-
if (!def) return {};
|
|
1777
|
-
if (!def.parseValue) return {};
|
|
1778
|
-
const value = def.parseValue(val);
|
|
1779
|
-
if (value === void 0) return {};
|
|
1780
|
-
const fragment = def.wqlGenerator(value);
|
|
1781
|
-
return fragment.trim() ? { filterStr: fragment } : {};
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
function clausesToWql(clauses) {
|
|
1786
|
-
const whereClause = clauses.find((c) => c.type === "where");
|
|
1787
|
-
const whereStr = whereClause?.value?.trim() ? `where ${whereClause.value.trim()}` : "";
|
|
1788
|
-
const filterParts = [];
|
|
1789
|
-
for (const c of clauses) {
|
|
1790
|
-
const res = clauseToWql(c);
|
|
1791
|
-
if (res.filterStr) {
|
|
1792
|
-
filterParts.push(res.filterStr);
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
const filterBraces = filterParts.length > 0 ? `{${filterParts.join(", ")}}` : "";
|
|
1796
|
-
const source = clauseValue(clauses, "source", "notes");
|
|
1797
|
-
if (source === "rows") {
|
|
1798
|
-
const output = clauseValue(clauses, "output", "") || "all";
|
|
1799
|
-
const timeClause2 = clauses.find((c) => c.type === "time");
|
|
1800
|
-
let timeStr2 = "";
|
|
1801
|
-
if (timeClause2 && timeClause2.value && timeClause2.value !== "all") {
|
|
1802
|
-
const rawVal = timeClause2.value.trim();
|
|
1803
|
-
timeStr2 = rawVal.startsWith("last") ? rawVal : `last ${rawVal}`;
|
|
1804
|
-
}
|
|
1805
|
-
return [
|
|
1806
|
-
`rows:${output}${filterBraces}`,
|
|
1807
|
-
timeStr2
|
|
1808
|
-
].filter(Boolean).join(" ").trim();
|
|
1809
|
-
}
|
|
1810
|
-
if (source === "metrics") {
|
|
1811
|
-
const agg = clauseValue(clauses, "agg", "sum");
|
|
1812
|
-
const metric = clauseValue(clauses, "metric", "");
|
|
1813
|
-
const dims = clauses.filter((c) => c.type === "groupby" && c.value.trim()).map((c) => c.value.trim());
|
|
1814
|
-
const rollup = clauseValue(clauses, "rollup", "");
|
|
1815
|
-
const unit = clauseValue(clauses, "unit", "");
|
|
1816
|
-
const byStr = dims.length ? `by {${dims.join(", ")}}` : "";
|
|
1817
|
-
const rollupStr = rollup ? `.rollup(${rollup})` : "";
|
|
1818
|
-
const head = byStr ? `${agg}:${metric}${filterBraces}` : `${agg}:${metric}${filterBraces}${rollupStr}`;
|
|
1819
|
-
return [
|
|
1820
|
-
head,
|
|
1821
|
-
`${byStr}${byStr ? rollupStr : ""}`,
|
|
1822
|
-
unit ? `in ${unit}` : "",
|
|
1823
|
-
whereStr
|
|
1824
|
-
].filter(Boolean).join(" ").trim();
|
|
1825
|
-
}
|
|
1826
|
-
const target = source === "blocks" ? "block" : source === "efforts" ? "effort" : "note";
|
|
1827
|
-
const scope = source === "notes" || source === "blocks" || source === "efforts" ? "all" : source;
|
|
1828
|
-
const timeClause = clauses.find((c) => c.type === "time");
|
|
1829
|
-
let timeStr = "";
|
|
1830
|
-
if (timeClause && timeClause.value && timeClause.value !== "all") {
|
|
1831
|
-
const rawVal = timeClause.value.trim();
|
|
1832
|
-
timeStr = rawVal.startsWith("last") ? rawVal : `last ${rawVal}`;
|
|
1833
|
-
}
|
|
1834
|
-
return [
|
|
1835
|
-
`find:${target}${filterBraces}`,
|
|
1836
|
-
`in ${scope}`,
|
|
1837
|
-
timeStr,
|
|
1838
|
-
whereStr
|
|
1839
|
-
].filter(Boolean).join(" ").trim();
|
|
1840
|
-
}
|
|
1841
|
-
var POSITIONAL_CLAUSE_TYPES = /* @__PURE__ */ new Set(["source", "time", "where", "agg", "metric", "groupby", "rollup", "unit", "output"]);
|
|
1842
|
-
var FILTER_KEY_TO_CLAUSE_TYPE = Object.fromEntries(
|
|
1843
|
-
Object.entries(CLAUSE_META).filter(([type]) => !POSITIONAL_CLAUSE_TYPES.has(type)).map(([type, meta]) => [meta.prefix.replace(/:$/, ""), type])
|
|
1844
|
-
);
|
|
1845
|
-
function splitTopLevel(body) {
|
|
1846
|
-
const parts = [];
|
|
1847
|
-
let depth = 0;
|
|
1848
|
-
let inQuote = false;
|
|
1849
|
-
let start = 0;
|
|
1850
|
-
for (let i = 0; i < body.length; i++) {
|
|
1851
|
-
const c = body[i];
|
|
1852
|
-
if (c === '"') inQuote = !inQuote;
|
|
1853
|
-
else if (!inQuote && c === "{") depth++;
|
|
1854
|
-
else if (!inQuote && c === "}") depth = Math.max(0, depth - 1);
|
|
1855
|
-
else if (!inQuote && c === "," && depth === 0) {
|
|
1856
|
-
parts.push(body.slice(start, i));
|
|
1857
|
-
start = i + 1;
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
parts.push(body.slice(start));
|
|
1861
|
-
return parts;
|
|
1862
|
-
}
|
|
1863
|
-
var RESTORE_FIND_HEAD_RE = /^find:([a-zA-Z0-9_-]*)/;
|
|
1864
|
-
var RESTORE_AGG_HEAD_RE = /^([a-zA-Z0-9_-]+):([a-zA-Z0-9_.-]*)/;
|
|
1865
|
-
function restoreClause(id, type, value) {
|
|
1866
|
-
return { id, type, ...getClauseMeta(type), value };
|
|
1867
|
-
}
|
|
1868
|
-
function filterFragmentToClause(fragment, index) {
|
|
1869
|
-
if (fragment.startsWith("!")) return null;
|
|
1870
|
-
const colon2 = fragment.indexOf(":");
|
|
1871
|
-
if (colon2 <= 0) return null;
|
|
1872
|
-
const key = fragment.slice(0, colon2);
|
|
1873
|
-
const value = fragment.slice(colon2 + 1);
|
|
1874
|
-
if (!value.trim()) return null;
|
|
1875
|
-
if (key === "source") {
|
|
1876
|
-
return restoreClause(`c-source-${index}`, "source", value);
|
|
1877
|
-
}
|
|
1878
|
-
const builtin = FILTER_KEY_TO_CLAUSE_TYPE[key];
|
|
1879
|
-
if (builtin) {
|
|
1880
|
-
const restoredValue = builtin === "text" && value.length >= 2 && value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
|
1881
|
-
return restoreClause(`c-${builtin}-${index}`, builtin, restoredValue);
|
|
1882
|
-
}
|
|
1883
|
-
for (const slot of composerRegistry.getAllSlots()) {
|
|
1884
|
-
if (!slot.parseValue || !slot.formatValue) continue;
|
|
1885
|
-
const typed = slot.parseValue(value);
|
|
1886
|
-
if (typed !== void 0 && slot.wqlGenerator(typed) === fragment) {
|
|
1887
|
-
return restoreClause(`c-${slot.type}-${index}`, slot.type, slot.formatValue(typed));
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
return null;
|
|
1891
|
-
}
|
|
1892
|
-
function restoreFilters(rest) {
|
|
1893
|
-
if (!rest) return [];
|
|
1894
|
-
if (!rest.startsWith("{") || !rest.endsWith("}")) return null;
|
|
1895
|
-
const body = rest.slice(1, -1);
|
|
1896
|
-
const fragments = splitTopLevel(body).map((f) => f.trim()).filter(Boolean);
|
|
1897
|
-
const clauses = [];
|
|
1898
|
-
for (let i = 0; i < fragments.length; i++) {
|
|
1899
|
-
const clause = filterFragmentToClause(fragments[i], i);
|
|
1900
|
-
if (!clause) return null;
|
|
1901
|
-
clauses.push(clause);
|
|
1902
|
-
}
|
|
1903
|
-
return clauses;
|
|
1904
|
-
}
|
|
1905
|
-
function wqlToClauses(wql2) {
|
|
1906
|
-
const suffixes = wodWikiWql.parseWqlSuffixes(wql2.trim());
|
|
1907
|
-
if (suffixes.conflicts?.length) return null;
|
|
1908
|
-
const { where, displayUnit, groupBy, rollup, window: window2, legacyScope, primaryText } = suffixes;
|
|
1909
|
-
if (window2?.kind === "range") return null;
|
|
1910
|
-
const rowsMatch = /^rows(?:\:([a-zA-Z0-9_-]+))?\:?/.exec(primaryText);
|
|
1911
|
-
if (rowsMatch) {
|
|
1912
|
-
if (where || groupBy || rollup) return null;
|
|
1913
|
-
const rest2 = primaryText.slice(rowsMatch[0].length).trim();
|
|
1914
|
-
const filterClauses2 = restoreFilters(rest2);
|
|
1915
|
-
if (!filterClauses2) return null;
|
|
1916
|
-
const clauses2 = [
|
|
1917
|
-
restoreClause("c-source", "source", "rows"),
|
|
1918
|
-
restoreClause("c-time", "time", window2?.kind === "relative" ? `last ${window2.size}${window2.unit}` : "all"),
|
|
1919
|
-
...rowsMatch[1] ? [restoreClause("c-output", "output", rowsMatch[1])] : [],
|
|
1920
|
-
...filterClauses2
|
|
1921
|
-
];
|
|
1922
|
-
return clauses2;
|
|
1923
|
-
}
|
|
1924
|
-
if (primaryText.startsWith("find:")) {
|
|
1925
|
-
const headMatch2 = RESTORE_FIND_HEAD_RE.exec(primaryText);
|
|
1926
|
-
if (!headMatch2) return null;
|
|
1927
|
-
const targetValue = headMatch2[1];
|
|
1928
|
-
if (!wodWikiWql.WQL_FIND_TARGETS.includes(targetValue)) return null;
|
|
1929
|
-
const rest2 = primaryText.slice(headMatch2[0].length).trim();
|
|
1930
|
-
const filterClauses2 = restoreFilters(rest2);
|
|
1931
|
-
if (!filterClauses2) return null;
|
|
1932
|
-
const timeValue = window2?.kind === "relative" ? `last ${window2.size}${window2.unit}` : "all";
|
|
1933
|
-
const sourceClauseIdx = filterClauses2.findIndex((c) => c.type === "source");
|
|
1934
|
-
const sourceFromFilter = sourceClauseIdx !== -1 ? filterClauses2[sourceClauseIdx].value : void 0;
|
|
1935
|
-
const scopeValue = legacyScope ?? sourceFromFilter;
|
|
1936
|
-
const remainingFilterClauses = sourceClauseIdx !== -1 ? filterClauses2.filter((_, idx) => idx !== sourceClauseIdx) : filterClauses2;
|
|
1937
|
-
const sourceValue = targetValue === "block" ? "blocks" : targetValue === "effort" ? "efforts" : !scopeValue || scopeValue === "all" ? "notes" : scopeValue;
|
|
1938
|
-
const clauses2 = [
|
|
1939
|
-
restoreClause("c-source", "source", sourceValue),
|
|
1940
|
-
restoreClause("c-time", "time", timeValue),
|
|
1941
|
-
...remainingFilterClauses
|
|
1942
|
-
];
|
|
1943
|
-
if (where) clauses2.push(restoreClause("c-where", "where", where));
|
|
1944
|
-
return clauses2;
|
|
1945
|
-
}
|
|
1946
|
-
if (window2) return null;
|
|
1947
|
-
const headMatch = RESTORE_AGG_HEAD_RE.exec(primaryText);
|
|
1948
|
-
if (!headMatch) return null;
|
|
1949
|
-
const aggValue = headMatch[1];
|
|
1950
|
-
const metricValue = headMatch[2] ?? "";
|
|
1951
|
-
const rest = primaryText.slice(headMatch[0].length).trim();
|
|
1952
|
-
const filterClauses = restoreFilters(rest);
|
|
1953
|
-
if (!filterClauses) return null;
|
|
1954
|
-
const dimValues = groupBy ?? [];
|
|
1955
|
-
const rollupValue = rollup?.raw ?? "";
|
|
1956
|
-
const unitValue = displayUnit ?? "";
|
|
1957
|
-
const clauses = [
|
|
1958
|
-
restoreClause("c-source", "source", "metrics"),
|
|
1959
|
-
restoreClause("c-agg", "agg", aggValue),
|
|
1960
|
-
restoreClause("c-metric", "metric", metricValue),
|
|
1961
|
-
...filterClauses,
|
|
1962
|
-
...dimValues.map((d, i) => restoreClause(`c-groupby-${i}`, "groupby", d))
|
|
1963
|
-
];
|
|
1964
|
-
if (rollupValue) clauses.push(restoreClause("c-rollup", "rollup", rollupValue));
|
|
1965
|
-
if (unitValue) clauses.push(restoreClause("c-unit", "unit", unitValue));
|
|
1966
|
-
if (where) clauses.push(restoreClause("c-where", "where", where));
|
|
1967
|
-
return clauses;
|
|
1968
|
-
}
|
|
1969
|
-
function setMetricClause(clauses, metric) {
|
|
1970
|
-
const withSource = clauses.some((c) => c.type === "source") ? clauses : [restoreClause("c-source", "source", "metrics"), ...clauses];
|
|
1971
|
-
const pivoted = clauseValue(withSource, "source") === "metrics" ? withSource : pivotClauses(withSource, "metrics");
|
|
1972
|
-
return pivoted.some((c) => c.type === "metric") ? pivoted.map((c) => c.type === "metric" ? { ...c, value: metric } : c) : [...pivoted, restoreClause("c-metric", "metric", metric)];
|
|
1973
|
-
}
|
|
1974
|
-
function pivotClauses(clauses, source) {
|
|
1975
|
-
const next = clauses.filter((c) => !METRICS_ONLY_TYPES.has(c.type) && c.type !== "time" && c.type !== "where").map((c) => c.type === "source" ? { ...c, value: source } : c);
|
|
1976
|
-
if (source === "metrics") {
|
|
1977
|
-
const sourceIdx = next.findIndex((c) => c.type === "source");
|
|
1978
|
-
const head = [];
|
|
1979
|
-
if (!next.some((c) => c.type === "agg")) head.push(restoreClause("c-agg", "agg", "sum"));
|
|
1980
|
-
if (!next.some((c) => c.type === "metric")) head.push(restoreClause("c-metric", "metric", ""));
|
|
1981
|
-
next.splice(sourceIdx >= 0 ? sourceIdx + 1 : next.length, 0, ...head);
|
|
1982
|
-
}
|
|
1983
|
-
return next;
|
|
1984
|
-
}
|
|
1985
|
-
function defaultClauses() {
|
|
1986
|
-
return [
|
|
1987
|
-
{ id: "c-source", type: "source", ...CLAUSE_META.source, value: "notes" },
|
|
1988
|
-
{ id: "c-time", type: "time", ...CLAUSE_META.time, value: "last 2w" }
|
|
1989
|
-
];
|
|
1990
|
-
}
|
|
1991
|
-
function defaultMetricsClauses() {
|
|
1992
|
-
return [
|
|
1993
|
-
{ id: "c-source", type: "source", ...CLAUSE_META.source, value: "metrics" },
|
|
1994
|
-
{ id: "c-agg", type: "agg", ...CLAUSE_META.agg, value: "sum" },
|
|
1995
|
-
{ id: "c-metric", type: "metric", ...CLAUSE_META.metric, value: "" }
|
|
1996
|
-
];
|
|
1997
|
-
}
|
|
1998
|
-
function clauseValue(clauses, type, fallback = "") {
|
|
1999
|
-
return clauses.find((c) => c.type === type)?.value?.trim() || fallback;
|
|
2000
|
-
}
|
|
2001
1743
|
function TokenSlotPill({
|
|
2002
1744
|
clause,
|
|
2003
1745
|
isActive,
|
|
@@ -2449,6 +2191,247 @@ function AddCalcDropdown({
|
|
|
2449
2191
|
)
|
|
2450
2192
|
] });
|
|
2451
2193
|
}
|
|
2194
|
+
var PILL_KEY = {
|
|
2195
|
+
text: "text",
|
|
2196
|
+
catalog: "catalog",
|
|
2197
|
+
tag: "tags",
|
|
2198
|
+
effort: "effort",
|
|
2199
|
+
discipline: "discipline",
|
|
2200
|
+
intensity: "intensity",
|
|
2201
|
+
origin: "origin",
|
|
2202
|
+
type: "type",
|
|
2203
|
+
has: "has",
|
|
2204
|
+
result: "result",
|
|
2205
|
+
block: "block",
|
|
2206
|
+
note: "note"
|
|
2207
|
+
};
|
|
2208
|
+
var KEY_PILL = Object.fromEntries(
|
|
2209
|
+
Object.entries(PILL_KEY).map(([pill, key]) => [key, pill])
|
|
2210
|
+
);
|
|
2211
|
+
function pillValueToFilter(type, rawValue) {
|
|
2212
|
+
const key = PILL_KEY[type];
|
|
2213
|
+
if (!key) return null;
|
|
2214
|
+
const values2 = rawValue.split("|").map((v) => v.trim()).filter(Boolean).map((v) => ({
|
|
2215
|
+
value: v.endsWith("*") ? v.slice(0, -1) : v,
|
|
2216
|
+
wildcard: v.endsWith("*")
|
|
2217
|
+
}));
|
|
2218
|
+
if (values2.length === 0) return null;
|
|
2219
|
+
return { key, negate: false, values: values2 };
|
|
2220
|
+
}
|
|
2221
|
+
function filterFragment(f) {
|
|
2222
|
+
const render = (v) => {
|
|
2223
|
+
const bare = /^[a-zA-Z0-9_-]+(:[a-zA-Z0-9_-]+)?$/.test(v.value);
|
|
2224
|
+
return `${bare ? v.value : `"${v.value}"`}${v.wildcard ? "*" : ""}`;
|
|
2225
|
+
};
|
|
2226
|
+
return `${f.negate ? "!" : ""}${f.key}:${f.values.map(render).join("|")}`;
|
|
2227
|
+
}
|
|
2228
|
+
function filterToPill(f, index) {
|
|
2229
|
+
if (f.negate) return null;
|
|
2230
|
+
const pillValue2 = f.values.map((v) => `${v.value}${v.wildcard ? "*" : ""}`).join("|");
|
|
2231
|
+
if (!pillValue2.trim()) return null;
|
|
2232
|
+
if (f.key === "source") {
|
|
2233
|
+
return restorePill(`c-source-${index}`, "source", pillValue2);
|
|
2234
|
+
}
|
|
2235
|
+
const builtin = KEY_PILL[f.key];
|
|
2236
|
+
if (builtin) {
|
|
2237
|
+
const value = builtin === "text" && f.values.length === 1 && /\s/.test(f.values[0].value) ? f.values[0].value : pillValue2;
|
|
2238
|
+
return restorePill(`c-${builtin}-${index}`, builtin, value);
|
|
2239
|
+
}
|
|
2240
|
+
const fragment = filterFragment(f);
|
|
2241
|
+
for (const slot of composerRegistry.getAllSlots()) {
|
|
2242
|
+
if (!slot.parseValue || !slot.formatValue) continue;
|
|
2243
|
+
const typed = slot.parseValue(pillValue2);
|
|
2244
|
+
if (typed !== void 0 && slot.wqlGenerator(typed) === fragment) {
|
|
2245
|
+
return restorePill(`c-${slot.type}-${index}`, slot.type, slot.formatValue(typed));
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
return null;
|
|
2249
|
+
}
|
|
2250
|
+
function restorePill(id, type, value) {
|
|
2251
|
+
return { id, type, ...getClauseMeta(type), value };
|
|
2252
|
+
}
|
|
2253
|
+
function astToPills(ast) {
|
|
2254
|
+
if (ast.error) return null;
|
|
2255
|
+
if (wodWikiWql.isRowsQuery(ast)) {
|
|
2256
|
+
if (ast.window?.kind === "range") return null;
|
|
2257
|
+
if (ast.filters.some((f) => f.key === "source")) return null;
|
|
2258
|
+
const filterPills = [];
|
|
2259
|
+
for (let i = 0; i < ast.filters.length; i++) {
|
|
2260
|
+
const p = filterToPill(ast.filters[i], i);
|
|
2261
|
+
if (!p) return null;
|
|
2262
|
+
filterPills.push(p);
|
|
2263
|
+
}
|
|
2264
|
+
return [
|
|
2265
|
+
restorePill("c-source", "source", "rows"),
|
|
2266
|
+
restorePill("c-time", "time", windowPillValue(ast.window)),
|
|
2267
|
+
restorePill("c-output", "output", ast.outputType ?? "all"),
|
|
2268
|
+
...filterPills
|
|
2269
|
+
];
|
|
2270
|
+
}
|
|
2271
|
+
if (wodWikiWql.isFindQuery(ast)) {
|
|
2272
|
+
if (ast.window?.kind === "range") return null;
|
|
2273
|
+
const sourceFilter = ast.filters.find((f) => f.key === "source" && !f.negate);
|
|
2274
|
+
const nonIdentitySource = sourceFilter && !sourceFilter.values.every((v) => v.value === "all");
|
|
2275
|
+
if ((ast.target === "block" || ast.target === "effort") && nonIdentitySource) return null;
|
|
2276
|
+
const sourceValue = ast.target === "block" ? "blocks" : ast.target === "effort" ? "efforts" : !sourceFilter || sourceFilter.values.every((v) => v.value === "all") ? "notes" : sourceFilter.values.map((v) => v.value).join("|");
|
|
2277
|
+
const rest = ast.filters.filter((f) => f !== sourceFilter);
|
|
2278
|
+
const filterPills = [];
|
|
2279
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2280
|
+
const p = filterToPill(rest[i], i);
|
|
2281
|
+
if (!p) return null;
|
|
2282
|
+
filterPills.push(p);
|
|
2283
|
+
}
|
|
2284
|
+
const pills = [
|
|
2285
|
+
restorePill("c-source", "source", sourceValue),
|
|
2286
|
+
restorePill("c-time", "time", windowPillValue(ast.window)),
|
|
2287
|
+
...filterPills
|
|
2288
|
+
];
|
|
2289
|
+
if (ast.join) {
|
|
2290
|
+
const j = ast.join;
|
|
2291
|
+
const head = wodWikiWql.serialize({
|
|
2292
|
+
family: "aggregate",
|
|
2293
|
+
raw: "",
|
|
2294
|
+
agg: j.agg,
|
|
2295
|
+
metric: j.metric,
|
|
2296
|
+
filters: j.filters,
|
|
2297
|
+
groupBy: []
|
|
2298
|
+
});
|
|
2299
|
+
pills.push(restorePill("c-where", "where", `${head} ${j.operator} ${j.threshold}`));
|
|
2300
|
+
}
|
|
2301
|
+
return pills;
|
|
2302
|
+
}
|
|
2303
|
+
if (wodWikiWql.isAggregateQuery(ast)) {
|
|
2304
|
+
if (ast.window?.kind === "range") return null;
|
|
2305
|
+
const filterPills = [];
|
|
2306
|
+
for (let i = 0; i < ast.filters.length; i++) {
|
|
2307
|
+
const p = filterToPill(ast.filters[i], i);
|
|
2308
|
+
if (!p) return null;
|
|
2309
|
+
filterPills.push(p);
|
|
2310
|
+
}
|
|
2311
|
+
const pills = [
|
|
2312
|
+
restorePill("c-source", "source", "metrics"),
|
|
2313
|
+
restorePill("c-agg", "agg", ast.agg),
|
|
2314
|
+
restorePill("c-metric", "metric", ast.metric),
|
|
2315
|
+
...filterPills,
|
|
2316
|
+
...ast.groupBy.map((d, i) => restorePill(`c-groupby-${i}`, "groupby", d))
|
|
2317
|
+
];
|
|
2318
|
+
if (ast.rollup) pills.push(restorePill("c-rollup", "rollup", `${ast.rollup.size}${ast.rollup.unit}`));
|
|
2319
|
+
if (ast.displayUnit) pills.push(restorePill("c-unit", "unit", ast.displayUnit));
|
|
2320
|
+
if (ast.window) pills.push(restorePill("c-time", "time", windowPillValue(ast.window)));
|
|
2321
|
+
if (ast.join) {
|
|
2322
|
+
pills.push(
|
|
2323
|
+
restorePill(
|
|
2324
|
+
"c-where",
|
|
2325
|
+
"where",
|
|
2326
|
+
wodWikiWql.serialize({
|
|
2327
|
+
family: "find",
|
|
2328
|
+
raw: "",
|
|
2329
|
+
target: ast.join.target,
|
|
2330
|
+
filters: ast.join.filters,
|
|
2331
|
+
window: ast.join.last ? { kind: "relative", size: ast.join.last.size, unit: ast.join.last.unit } : void 0
|
|
2332
|
+
})
|
|
2333
|
+
)
|
|
2334
|
+
);
|
|
2335
|
+
}
|
|
2336
|
+
return pills;
|
|
2337
|
+
}
|
|
2338
|
+
return null;
|
|
2339
|
+
}
|
|
2340
|
+
function windowPillValue(w) {
|
|
2341
|
+
if (!w) return "all";
|
|
2342
|
+
return `last ${w.size}${w.unit}`;
|
|
2343
|
+
}
|
|
2344
|
+
function wqlToPills(wql2) {
|
|
2345
|
+
const direct = astToPills(wodWikiWql.parseQuery(wql2.trim()));
|
|
2346
|
+
if (direct) return direct;
|
|
2347
|
+
const probed = wql2.trim().replace(/^([a-zA-Z_]\w*):(\s*\{)/, "$1:__placeholder__$2");
|
|
2348
|
+
if (probed === wql2.trim()) return null;
|
|
2349
|
+
const salvaged = astToPills(wodWikiWql.parseQuery(probed));
|
|
2350
|
+
if (!salvaged) return null;
|
|
2351
|
+
return salvaged.map((p) => p.type === "metric" ? { ...p, value: "" } : p);
|
|
2352
|
+
}
|
|
2353
|
+
function timePillText(raw) {
|
|
2354
|
+
const v = raw.trim();
|
|
2355
|
+
if (!v || v === "all") return "";
|
|
2356
|
+
if (v.startsWith("last") || v.startsWith("from")) return v;
|
|
2357
|
+
return `last ${v}`;
|
|
2358
|
+
}
|
|
2359
|
+
function buildCandidateText(pills) {
|
|
2360
|
+
const source = pillValue(pills, "source", "notes");
|
|
2361
|
+
const filterParts = [];
|
|
2362
|
+
for (const pill of pills) {
|
|
2363
|
+
const v = pill.value.trim();
|
|
2364
|
+
if (!v) continue;
|
|
2365
|
+
const builtin = pillValueToFilter(pill.type, v);
|
|
2366
|
+
if (builtin) {
|
|
2367
|
+
filterParts.push(filterFragment(builtin));
|
|
2368
|
+
continue;
|
|
2369
|
+
}
|
|
2370
|
+
const def = composerRegistry.getSlot(pill.type);
|
|
2371
|
+
if (!def?.parseValue) continue;
|
|
2372
|
+
const typed = def.parseValue(v);
|
|
2373
|
+
if (typed === void 0) continue;
|
|
2374
|
+
const fragment = def.wqlGenerator(typed).trim();
|
|
2375
|
+
if (fragment) filterParts.push(fragment);
|
|
2376
|
+
}
|
|
2377
|
+
const timePill = pills.find((c) => c.type === "time");
|
|
2378
|
+
const timeText = timePill ? timePillText(timePill.value) : "";
|
|
2379
|
+
const wherePill = pills.find((c) => c.type === "where");
|
|
2380
|
+
const whereText = wherePill?.value.trim() ? `where ${wherePill.value.trim()}` : "";
|
|
2381
|
+
if (source === "rows") {
|
|
2382
|
+
const output = pillValue(pills, "output", "all") || "all";
|
|
2383
|
+
return [`rows:${output}{${filterParts.join(",")}}`, timeText].filter(Boolean).join(" ").trim();
|
|
2384
|
+
}
|
|
2385
|
+
if (sourcePlane(source) === "metrics") {
|
|
2386
|
+
const agg = pillValue(pills, "agg", "sum");
|
|
2387
|
+
const metric = pillValue(pills, "metric", "");
|
|
2388
|
+
const dims = pills.filter((c) => c.type === "groupby" && c.value.trim()).map((c) => c.value.trim());
|
|
2389
|
+
const rollup = pillValue(pills, "rollup", "");
|
|
2390
|
+
const unit = pillValue(pills, "unit", "");
|
|
2391
|
+
return [
|
|
2392
|
+
`${agg}:${metric}{${filterParts.join(",")}}`,
|
|
2393
|
+
dims.length ? `by {${dims.join(", ")}}` : "",
|
|
2394
|
+
rollup ? `.rollup(${rollup})` : "",
|
|
2395
|
+
unit ? `in ${unit}` : "",
|
|
2396
|
+
timeText,
|
|
2397
|
+
whereText
|
|
2398
|
+
].filter(Boolean).join(" ").trim();
|
|
2399
|
+
}
|
|
2400
|
+
const target = source === "blocks" ? "block" : source === "efforts" ? "effort" : "note";
|
|
2401
|
+
const withSource = source === "notes" || source === "blocks" || source === "efforts" ? filterParts : [`source:${source}`, ...filterParts];
|
|
2402
|
+
const braces = withSource.length ? `{${withSource.join(",")}}` : "";
|
|
2403
|
+
return [`find:${target}${braces}`, timeText, whereText].filter(Boolean).join(" ").trim();
|
|
2404
|
+
}
|
|
2405
|
+
function pillsToAst(pills) {
|
|
2406
|
+
return wodWikiWql.parseQuery(buildCandidateText(pills));
|
|
2407
|
+
}
|
|
2408
|
+
var METRICS_HEAD_TYPES = /* @__PURE__ */ new Set(["agg", "metric", "groupby", "rollup", "unit"]);
|
|
2409
|
+
function pivotPills(pills, source) {
|
|
2410
|
+
const next = pills.filter((c) => !METRICS_HEAD_TYPES.has(c.type) && c.type !== "where").map((c) => c.type === "source" ? { ...c, value: source } : c);
|
|
2411
|
+
if (source === "metrics") {
|
|
2412
|
+
const sourceIdx = next.findIndex((c) => c.type === "source");
|
|
2413
|
+
const head = [];
|
|
2414
|
+
if (!next.some((c) => c.type === "agg")) head.push(restorePill("c-agg", "agg", "sum"));
|
|
2415
|
+
if (!next.some((c) => c.type === "metric")) head.push(restorePill("c-metric", "metric", ""));
|
|
2416
|
+
next.splice(sourceIdx >= 0 ? sourceIdx + 1 : next.length, 0, ...head);
|
|
2417
|
+
}
|
|
2418
|
+
if (source === "rows" && !next.some((c) => c.type === "output")) {
|
|
2419
|
+
const sourceIdx = next.findIndex((c) => c.type === "source");
|
|
2420
|
+
next.splice(sourceIdx >= 0 ? sourceIdx + 1 : next.length, 0, restorePill("c-output", "output", "all"));
|
|
2421
|
+
}
|
|
2422
|
+
return next;
|
|
2423
|
+
}
|
|
2424
|
+
function defaultPills() {
|
|
2425
|
+
return [
|
|
2426
|
+
restorePill("c-source", "source", "notes"),
|
|
2427
|
+
restorePill("c-time", "time", "last 2w")
|
|
2428
|
+
];
|
|
2429
|
+
}
|
|
2430
|
+
function pillValue(pills, type, fallback = "") {
|
|
2431
|
+
return pills.find((c) => c.type === type)?.value?.trim() || fallback;
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
// src/composer/diagnostics.ts
|
|
2452
2435
|
function summarizeFind(ast) {
|
|
2453
2436
|
const sourceFilter = ast.filters.find((f) => f.key === "source");
|
|
2454
2437
|
const scope = sourceFilter ? sourceFilter.values.map((v) => v.value).join(",") : "all";
|
|
@@ -2480,21 +2463,21 @@ function customSlotError(clause) {
|
|
|
2480
2463
|
if (parsed === void 0) return `Invalid ${custom.label} value`;
|
|
2481
2464
|
return custom.validate ? custom.validate(parsed) : null;
|
|
2482
2465
|
}
|
|
2483
|
-
function
|
|
2484
|
-
for (const
|
|
2485
|
-
const error = customSlotError(
|
|
2466
|
+
function diagnosePills(pills) {
|
|
2467
|
+
for (const pill of pills) {
|
|
2468
|
+
const error = customSlotError(pill);
|
|
2486
2469
|
if (error) {
|
|
2487
2470
|
return {
|
|
2488
2471
|
valid: false,
|
|
2489
|
-
wql:
|
|
2472
|
+
wql: wodWikiWql.serialize(pillsToAst(pills)),
|
|
2490
2473
|
ast: { family: "aggregate", raw: "", agg: "sum", metric: "", filters: [], groupBy: [], error },
|
|
2491
2474
|
error,
|
|
2492
|
-
offendingClauseId:
|
|
2475
|
+
offendingClauseId: pill.id
|
|
2493
2476
|
};
|
|
2494
2477
|
}
|
|
2495
2478
|
}
|
|
2496
|
-
const
|
|
2497
|
-
const
|
|
2479
|
+
const ast = pillsToAst(pills);
|
|
2480
|
+
const wql2 = wodWikiWql.serialize(ast);
|
|
2498
2481
|
if (ast.error) {
|
|
2499
2482
|
return {
|
|
2500
2483
|
valid: false,
|
|
@@ -2622,10 +2605,9 @@ function useWqlStageCounts(ast, valid, execute, debounceMs = DEFAULT_DIAGNOSTICS
|
|
|
2622
2605
|
return runnable ? stages : void 0;
|
|
2623
2606
|
}
|
|
2624
2607
|
function WqlComposer({
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
onWqlChange,
|
|
2608
|
+
initialQuery,
|
|
2609
|
+
query: controlledQuery,
|
|
2610
|
+
onQueryChange,
|
|
2629
2611
|
onValidationChange,
|
|
2630
2612
|
onAstChange,
|
|
2631
2613
|
onSubmit,
|
|
@@ -2639,52 +2621,91 @@ function WqlComposer({
|
|
|
2639
2621
|
placeholder = "Type search term and press Enter...",
|
|
2640
2622
|
className
|
|
2641
2623
|
}) {
|
|
2642
|
-
const [
|
|
2643
|
-
() =>
|
|
2624
|
+
const [internalPills, setInternalPills] = React.useState(
|
|
2625
|
+
() => wqlToPills(initialQuery ?? "") ?? defaultPills()
|
|
2626
|
+
);
|
|
2627
|
+
const controlledPills = React.useMemo(
|
|
2628
|
+
() => controlledQuery === void 0 ? void 0 : wqlToPills(controlledQuery),
|
|
2629
|
+
[controlledQuery]
|
|
2644
2630
|
);
|
|
2645
|
-
const
|
|
2631
|
+
const pills = controlledPills ?? internalPills;
|
|
2646
2632
|
const hiddenTypes = React.useMemo(() => new Set(hiddenClauseTypes), [hiddenClauseTypes]);
|
|
2647
2633
|
const [activeSlotIdx, setActiveSlotIdx] = React.useState(null);
|
|
2648
2634
|
const [freeText, setFreeText] = React.useState("");
|
|
2649
2635
|
const inputRef = React.useRef(null);
|
|
2636
|
+
const freeTextInitRef = React.useRef(null);
|
|
2637
|
+
React.useEffect(() => {
|
|
2638
|
+
if (controlledQuery === void 0) return;
|
|
2639
|
+
if (controlledPills === null) {
|
|
2640
|
+
if (freeTextInitRef.current !== controlledQuery) {
|
|
2641
|
+
freeTextInitRef.current = controlledQuery;
|
|
2642
|
+
setFreeText(controlledQuery);
|
|
2643
|
+
}
|
|
2644
|
+
} else if (freeTextInitRef.current !== null) {
|
|
2645
|
+
freeTextInitRef.current = null;
|
|
2646
|
+
setFreeText("");
|
|
2647
|
+
}
|
|
2648
|
+
}, [controlledQuery, controlledPills]);
|
|
2650
2649
|
React.useEffect(() => {
|
|
2651
2650
|
if (!autoFocus) return;
|
|
2652
2651
|
const t = setTimeout(() => inputRef.current?.focus(), 0);
|
|
2653
2652
|
return () => clearTimeout(t);
|
|
2654
2653
|
}, [autoFocus]);
|
|
2655
|
-
const
|
|
2654
|
+
const setPills = React.useCallback(
|
|
2656
2655
|
(next) => {
|
|
2657
|
-
if (
|
|
2658
|
-
onClausesChange?.(next);
|
|
2656
|
+
if (controlledQuery === void 0) setInternalPills(next);
|
|
2659
2657
|
},
|
|
2660
|
-
[
|
|
2658
|
+
[controlledQuery]
|
|
2661
2659
|
);
|
|
2662
2660
|
const registeredSlots = useComposerSlots();
|
|
2663
|
-
const
|
|
2664
|
-
const
|
|
2665
|
-
|
|
2661
|
+
const rawEscape = controlledQuery !== void 0 && controlledPills === null;
|
|
2662
|
+
const diagnostics = React.useMemo(() => {
|
|
2663
|
+
if (rawEscape) {
|
|
2664
|
+
const ast = wodWikiWql.parseQuery(controlledQuery);
|
|
2665
|
+
return {
|
|
2666
|
+
valid: !ast.error,
|
|
2667
|
+
wql: controlledQuery,
|
|
2668
|
+
ast,
|
|
2669
|
+
error: ast.error
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2672
|
+
return diagnosePills(pills);
|
|
2673
|
+
}, [rawEscape, controlledQuery, pills, registeredSlots]);
|
|
2674
|
+
const callbacksRef = React.useRef({ onQueryChange, onValidationChange, onAstChange });
|
|
2675
|
+
callbacksRef.current = { onQueryChange, onValidationChange, onAstChange };
|
|
2666
2676
|
React.useEffect(() => {
|
|
2667
2677
|
const validation = diagnostics.valid ? { valid: true } : { valid: false, error: diagnostics.error };
|
|
2668
|
-
callbacksRef.current.
|
|
2678
|
+
if (controlledQuery === void 0) callbacksRef.current.onQueryChange?.(diagnostics.wql);
|
|
2669
2679
|
callbacksRef.current.onAstChange?.(diagnostics.ast);
|
|
2670
2680
|
callbacksRef.current.onValidationChange?.(validation);
|
|
2671
2681
|
}, [diagnostics]);
|
|
2672
2682
|
const stages = useWqlStageCounts(diagnostics.ast, diagnostics.valid, execute, debounceMs);
|
|
2673
|
-
const
|
|
2674
|
-
const offendingLabel =
|
|
2675
|
-
const
|
|
2676
|
-
const updated =
|
|
2677
|
-
const edited =
|
|
2683
|
+
const offendingPill = diagnostics.offendingClauseId ? pills.find((c) => c.id === diagnostics.offendingClauseId) : void 0;
|
|
2684
|
+
const offendingLabel = offendingPill ? getClauseMeta(offendingPill.type).label : void 0;
|
|
2685
|
+
const updatePill = (idx, patch) => {
|
|
2686
|
+
const updated = pills.map((c, i) => i === idx ? { ...c, ...patch } : c);
|
|
2687
|
+
const edited = pills[idx];
|
|
2678
2688
|
if (edited?.type === "source" && patch.value !== void 0 && patch.value !== edited.value) {
|
|
2679
|
-
|
|
2689
|
+
setPills(pivotPills(updated, patch.value));
|
|
2690
|
+
emitIfControlled(pivotPills(updated, patch.value));
|
|
2680
2691
|
return;
|
|
2681
2692
|
}
|
|
2682
|
-
|
|
2693
|
+
setPills(updated);
|
|
2694
|
+
emitIfControlled(updated);
|
|
2683
2695
|
};
|
|
2684
|
-
const
|
|
2685
|
-
|
|
2696
|
+
const removePill = (idx) => {
|
|
2697
|
+
const next = pills.filter((_, i) => i !== idx);
|
|
2698
|
+
setPills(next);
|
|
2699
|
+
emitIfControlled(next);
|
|
2686
2700
|
};
|
|
2687
|
-
const
|
|
2701
|
+
const emitIfControlled = (next) => {
|
|
2702
|
+
if (controlledQuery !== void 0) {
|
|
2703
|
+
const nextAst = pillsToAst(next);
|
|
2704
|
+
const nextWql = wodWikiWql.serialize(nextAst);
|
|
2705
|
+
if (nextWql !== controlledQuery) callbacksRef.current.onQueryChange?.(nextWql);
|
|
2706
|
+
}
|
|
2707
|
+
};
|
|
2708
|
+
const makePill = (type, value) => {
|
|
2688
2709
|
const meta = getClauseMeta(type);
|
|
2689
2710
|
return {
|
|
2690
2711
|
id: `c-${Date.now()}-${Math.random()}`,
|
|
@@ -2698,10 +2719,13 @@ function WqlComposer({
|
|
|
2698
2719
|
const pending = React.useMemo(() => {
|
|
2699
2720
|
const raw = freeText.trim();
|
|
2700
2721
|
if (!raw) return null;
|
|
2701
|
-
const restored =
|
|
2702
|
-
if (restored) {
|
|
2703
|
-
|
|
2704
|
-
|
|
2722
|
+
const restored = wqlToPills(raw);
|
|
2723
|
+
if (restored) return { kind: "query", pills: restored };
|
|
2724
|
+
const parsed = wodWikiWql.parseQuery(raw);
|
|
2725
|
+
if (!parsed.error && /[:{]/.test(raw)) {
|
|
2726
|
+
return { kind: "raw", value: raw };
|
|
2727
|
+
}
|
|
2728
|
+
if (parsed.error && /[:{]/.test(raw)) {
|
|
2705
2729
|
return { kind: "invalid", reason: String(parsed.error) };
|
|
2706
2730
|
}
|
|
2707
2731
|
const words = raw.match(/[a-zA-Z0-9_-]+/g);
|
|
@@ -2713,42 +2737,48 @@ function WqlComposer({
|
|
|
2713
2737
|
}
|
|
2714
2738
|
return { kind: "text", value: words[0] };
|
|
2715
2739
|
}, [freeText]);
|
|
2716
|
-
const
|
|
2717
|
-
const type =
|
|
2718
|
-
const seed = type === "time" ? "last 2w" : type === "where" ? "sum:totalVolume{} > 5000" : type === "agg" ? "sum" : type === "groupby" ? "week" : type === "rollup" ? "1w" :
|
|
2719
|
-
|
|
2740
|
+
const addPill = (pill) => {
|
|
2741
|
+
const type = pill.type;
|
|
2742
|
+
const seed = type === "time" ? "last 2w" : type === "where" ? "sum:totalVolume{} > 5000" : type === "agg" ? "sum" : type === "groupby" ? "week" : type === "rollup" ? "1w" : pill.value;
|
|
2743
|
+
const next = [...pills, { ...pill, value: seed }];
|
|
2744
|
+
setPills(next);
|
|
2745
|
+
emitIfControlled(next);
|
|
2720
2746
|
};
|
|
2721
|
-
const addCalc = (
|
|
2722
|
-
const { type, value } =
|
|
2747
|
+
const addCalc = (pill) => {
|
|
2748
|
+
const { type, value } = pill;
|
|
2723
2749
|
if (type === "metric") {
|
|
2724
|
-
if (
|
|
2750
|
+
if (pills.some((c) => c.type === "metric")) return;
|
|
2725
2751
|
const afterIdx = Math.max(
|
|
2726
|
-
|
|
2727
|
-
|
|
2752
|
+
pills.findIndex((c) => c.type === "agg"),
|
|
2753
|
+
pills.findIndex((c) => c.type === "source")
|
|
2728
2754
|
);
|
|
2729
|
-
const next2 = [...
|
|
2730
|
-
next2.splice(afterIdx + 1, 0,
|
|
2731
|
-
|
|
2755
|
+
const next2 = [...pills];
|
|
2756
|
+
next2.splice(afterIdx + 1, 0, makePill("metric", value));
|
|
2757
|
+
setPills(next2);
|
|
2758
|
+
emitIfControlled(next2);
|
|
2732
2759
|
return;
|
|
2733
2760
|
}
|
|
2734
2761
|
if (type !== "agg") {
|
|
2735
|
-
|
|
2762
|
+
addPill(pill);
|
|
2736
2763
|
return;
|
|
2737
2764
|
}
|
|
2738
2765
|
const agg = value || "sum";
|
|
2739
|
-
const existingIdx =
|
|
2766
|
+
const existingIdx = pills.findIndex((c) => c.type === "agg");
|
|
2740
2767
|
if (existingIdx >= 0) {
|
|
2741
|
-
|
|
2768
|
+
updatePill(existingIdx, { value: agg });
|
|
2742
2769
|
return;
|
|
2743
2770
|
}
|
|
2744
|
-
if (sourcePlane(
|
|
2745
|
-
|
|
2771
|
+
if (sourcePlane(pillValue(pills, "source", "notes")) !== "metrics") {
|
|
2772
|
+
const next2 = pivotPills(pills, "metrics").map((c) => c.type === "agg" ? { ...c, value: agg } : c);
|
|
2773
|
+
setPills(next2);
|
|
2774
|
+
emitIfControlled(next2);
|
|
2746
2775
|
return;
|
|
2747
2776
|
}
|
|
2748
|
-
const sourceIdx =
|
|
2749
|
-
const next = [...
|
|
2750
|
-
next.splice(sourceIdx + 1, 0,
|
|
2751
|
-
|
|
2777
|
+
const sourceIdx = pills.findIndex((c) => c.type === "source");
|
|
2778
|
+
const next = [...pills];
|
|
2779
|
+
next.splice(sourceIdx + 1, 0, makePill("agg", agg));
|
|
2780
|
+
setPills(next);
|
|
2781
|
+
emitIfControlled(next);
|
|
2752
2782
|
};
|
|
2753
2783
|
const handleKeyDown = (e) => {
|
|
2754
2784
|
if (e.key !== "Enter") return;
|
|
@@ -2756,10 +2786,15 @@ function WqlComposer({
|
|
|
2756
2786
|
e.preventDefault();
|
|
2757
2787
|
e.stopPropagation();
|
|
2758
2788
|
if (pending?.kind === "query") {
|
|
2759
|
-
|
|
2789
|
+
setPills(pending.pills);
|
|
2790
|
+
emitIfControlled(pending.pills);
|
|
2760
2791
|
setFreeText("");
|
|
2792
|
+
} else if (pending?.kind === "raw") {
|
|
2793
|
+
onSubmit?.(pending.value);
|
|
2761
2794
|
} else if (pending?.kind === "text") {
|
|
2762
|
-
|
|
2795
|
+
const next = [...pills, makePill("text", pending.value)];
|
|
2796
|
+
setPills(next);
|
|
2797
|
+
emitIfControlled(next);
|
|
2763
2798
|
setFreeText("");
|
|
2764
2799
|
}
|
|
2765
2800
|
return;
|
|
@@ -2782,20 +2817,20 @@ function WqlComposer({
|
|
|
2782
2817
|
"data-testid": "wql-composer",
|
|
2783
2818
|
children: [
|
|
2784
2819
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Command, { className: "size-4 text-amber-500 shrink-0 mr-0.5" }),
|
|
2785
|
-
|
|
2786
|
-
(
|
|
2820
|
+
pills.map(
|
|
2821
|
+
(pill, idx) => hiddenTypes.has(pill.type) ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2787
2822
|
TokenSlotPill,
|
|
2788
2823
|
{
|
|
2789
|
-
clause,
|
|
2824
|
+
clause: pill,
|
|
2790
2825
|
isActive: activeSlotIdx === idx,
|
|
2791
|
-
invalid: diagnostics.offendingClauseId ===
|
|
2792
|
-
invalidReason: diagnostics.offendingClauseId ===
|
|
2826
|
+
invalid: diagnostics.offendingClauseId === pill.id,
|
|
2827
|
+
invalidReason: diagnostics.offendingClauseId === pill.id ? diagnostics.error : void 0,
|
|
2793
2828
|
onClick: () => setActiveSlotIdx(idx),
|
|
2794
|
-
onChange: (patch) =>
|
|
2795
|
-
onRemove: () =>
|
|
2829
|
+
onChange: (patch) => updatePill(idx, patch),
|
|
2830
|
+
onRemove: () => removePill(idx),
|
|
2796
2831
|
compact: true
|
|
2797
2832
|
},
|
|
2798
|
-
|
|
2833
|
+
pill.id
|
|
2799
2834
|
)
|
|
2800
2835
|
),
|
|
2801
2836
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2826,6 +2861,7 @@ function WqlComposer({
|
|
|
2826
2861
|
role: pending.kind === "invalid" ? "alert" : void 0,
|
|
2827
2862
|
children: [
|
|
2828
2863
|
pending.kind === "query" && "\u21B5 Use as query",
|
|
2864
|
+
pending.kind === "raw" && "\u21B5 Run query",
|
|
2829
2865
|
pending.kind === "text" && `\u21B5 Search text: ${pending.value}`,
|
|
2830
2866
|
pending.kind === "invalid" && pending.reason
|
|
2831
2867
|
]
|
|
@@ -2838,14 +2874,14 @@ function WqlComposer({
|
|
|
2838
2874
|
offendingLabel,
|
|
2839
2875
|
stages,
|
|
2840
2876
|
actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2841
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddCalcDropdown, { clauses, onAdd: addCalc }),
|
|
2842
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddFilterDropdown, { clauses, onAdd:
|
|
2877
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddCalcDropdown, { clauses: pills, onAdd: addCalc }),
|
|
2878
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddFilterDropdown, { clauses: pills, onAdd: addPill }),
|
|
2843
2879
|
diagnosticsActions
|
|
2844
2880
|
] })
|
|
2845
2881
|
}
|
|
2846
2882
|
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1.5 px-1.5", "data-testid": "wql-add-row", children: [
|
|
2847
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddCalcDropdown, { clauses, onAdd: addCalc }),
|
|
2848
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddFilterDropdown, { clauses, onAdd:
|
|
2883
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddCalcDropdown, { clauses: pills, onAdd: addCalc }),
|
|
2884
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddFilterDropdown, { clauses: pills, onAdd: addPill }),
|
|
2849
2885
|
diagnosticsActions
|
|
2850
2886
|
] })
|
|
2851
2887
|
] });
|
|
@@ -2936,13 +2972,10 @@ function WqlQueryInspectorModal({
|
|
|
2936
2972
|
subtitle = "Use the Omni-Composer to edit this block query.",
|
|
2937
2973
|
executor
|
|
2938
2974
|
}) {
|
|
2939
|
-
const [
|
|
2975
|
+
const [wql2, setWql] = React.useState(initialQuery);
|
|
2940
2976
|
const [isValid, setIsValid] = React.useState(true);
|
|
2941
2977
|
React.useEffect(() => {
|
|
2942
|
-
if (isOpen)
|
|
2943
|
-
const restored = wqlToClauses(initialQuery);
|
|
2944
|
-
setClauses(restored ?? defaultMetricsClauses());
|
|
2945
|
-
}
|
|
2978
|
+
if (isOpen) setWql(initialQuery);
|
|
2946
2979
|
}, [isOpen, initialQuery]);
|
|
2947
2980
|
const diagnosticsExecutor = React.useCallback(
|
|
2948
2981
|
(ast) => {
|
|
@@ -2960,8 +2993,7 @@ function WqlQueryInspectorModal({
|
|
|
2960
2993
|
);
|
|
2961
2994
|
const handleApply = () => {
|
|
2962
2995
|
if (!isValid) return;
|
|
2963
|
-
|
|
2964
|
-
onApply(nextWql);
|
|
2996
|
+
onApply(wql2);
|
|
2965
2997
|
onClose();
|
|
2966
2998
|
};
|
|
2967
2999
|
if (!isOpen) return null;
|
|
@@ -2992,15 +3024,15 @@ function WqlQueryInspectorModal({
|
|
|
2992
3024
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 overflow-y-auto space-y-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2993
3025
|
WqlComposer,
|
|
2994
3026
|
{
|
|
2995
|
-
|
|
2996
|
-
|
|
3027
|
+
query: wql2,
|
|
3028
|
+
onQueryChange: setWql,
|
|
2997
3029
|
onValidationChange: (v) => setIsValid(v.valid),
|
|
2998
3030
|
execute: diagnosticsExecutor,
|
|
2999
3031
|
showDiagnostics: true
|
|
3000
3032
|
}
|
|
3001
3033
|
) }),
|
|
3002
3034
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-3 border-t border-border/80 bg-muted/10", children: [
|
|
3003
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground font-mono", children:
|
|
3035
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground font-mono", children: wql2 }),
|
|
3004
3036
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3005
3037
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3006
3038
|
"button",
|
|
@@ -10796,13 +10828,13 @@ function editorPreset(optionsOrDialect = "markdown") {
|
|
|
10796
10828
|
}
|
|
10797
10829
|
|
|
10798
10830
|
// src/version.ts
|
|
10799
|
-
var VERSION = "0.
|
|
10800
|
-
var GIT_SHA = "
|
|
10801
|
-
var BUILD_TIME = "2026-08-
|
|
10831
|
+
var VERSION = "0.11.43";
|
|
10832
|
+
var GIT_SHA = "ed28149";
|
|
10833
|
+
var BUILD_TIME = "2026-08-26T16:34:15.927Z";
|
|
10802
10834
|
var SEMVER = {
|
|
10803
|
-
version: "0.
|
|
10804
|
-
gitSha: "
|
|
10805
|
-
buildTime: "2026-08-
|
|
10835
|
+
version: "0.11.43",
|
|
10836
|
+
gitSha: "ed28149",
|
|
10837
|
+
buildTime: "2026-08-26T16:34:15.927Z"
|
|
10806
10838
|
};
|
|
10807
10839
|
|
|
10808
10840
|
exports.AGG_OPTIONS = AGG_OPTIONS;
|
|
@@ -10811,7 +10843,6 @@ exports.AddCalcDropdown = AddCalcDropdown;
|
|
|
10811
10843
|
exports.AddFilterDropdown = AddFilterDropdown;
|
|
10812
10844
|
exports.AnalyticsUnitPreference = AnalyticsUnitPreference;
|
|
10813
10845
|
exports.BUILD_TIME = BUILD_TIME;
|
|
10814
|
-
exports.CLAUSE_META = CLAUSE_META;
|
|
10815
10846
|
exports.CODEMIRROR_SINGLETON_DEPS = CODEMIRROR_SINGLETON_DEPS;
|
|
10816
10847
|
exports.CONTENT_SOURCES = CONTENT_SOURCES;
|
|
10817
10848
|
exports.ClausePopover = ClausePopover;
|
|
@@ -10863,18 +10894,12 @@ exports.addRuntimePanel = addRuntimePanel;
|
|
|
10863
10894
|
exports.blockContentId = blockContentId;
|
|
10864
10895
|
exports.blockTypesFromBlocks = blockTypesFromBlocks;
|
|
10865
10896
|
exports.catalogIdsFromBlocks = catalogIdsFromBlocks;
|
|
10866
|
-
exports.clauseToWql = clauseToWql;
|
|
10867
|
-
exports.clauseValue = clauseValue;
|
|
10868
|
-
exports.clausesToWql = clausesToWql;
|
|
10869
10897
|
exports.cn = cn;
|
|
10870
10898
|
exports.compactNumber = compactNumber;
|
|
10871
10899
|
exports.composerRegistry = composerRegistry;
|
|
10872
10900
|
exports.configureOverlayActions = configureOverlayActions;
|
|
10873
10901
|
exports.cursorFocusExtension = cursorFocusExtension;
|
|
10874
10902
|
exports.dateRangeSlot = dateRangeSlot;
|
|
10875
|
-
exports.defaultClauses = defaultClauses;
|
|
10876
|
-
exports.defaultMetricsClauses = defaultMetricsClauses;
|
|
10877
|
-
exports.diagnoseClauses = diagnoseClauses;
|
|
10878
10903
|
exports.dispatchAddRuntimePanel = dispatchAddRuntimePanel;
|
|
10879
10904
|
exports.dispatchExpandRuntimePanel = dispatchExpandRuntimePanel;
|
|
10880
10905
|
exports.dispatchGutterHighlights = dispatchGutterHighlights;
|
|
@@ -10892,7 +10917,6 @@ exports.forceSectionParse = forceSectionParse;
|
|
|
10892
10917
|
exports.formatTimestamp = formatTimestamp;
|
|
10893
10918
|
exports.frontmatterPreview = frontmatterPreview;
|
|
10894
10919
|
exports.frontmatterPreviewField = frontmatterPreviewField;
|
|
10895
|
-
exports.getClauseMeta = getClauseMeta;
|
|
10896
10920
|
exports.getCursorFocusState = getCursorFocusState;
|
|
10897
10921
|
exports.getDashboardEffectiveUnit = getDashboardEffectiveUnit;
|
|
10898
10922
|
exports.getEffectiveAnalyticsUnit = getEffectiveAnalyticsUnit;
|
|
@@ -10913,7 +10937,6 @@ exports.mergeSeries = mergeSeries;
|
|
|
10913
10937
|
exports.mergeTagSuggestions = mergeTagSuggestions;
|
|
10914
10938
|
exports.navigationFacet = navigationFacet;
|
|
10915
10939
|
exports.patchBlockQuery = patchBlockQuery;
|
|
10916
|
-
exports.pivotClauses = pivotClauses;
|
|
10917
10940
|
exports.previewDecorations = previewDecorations;
|
|
10918
10941
|
exports.queryBlockPreview = queryBlockPreview;
|
|
10919
10942
|
exports.readSessionRpe = readSessionRpe;
|
|
@@ -10927,7 +10950,6 @@ exports.sectionGeometry = sectionGeometry;
|
|
|
10927
10950
|
exports.sessionQueryInsert = sessionQueryInsert;
|
|
10928
10951
|
exports.sessionQueryWql = sessionQueryWql;
|
|
10929
10952
|
exports.setGutterHighlights = setGutterHighlights;
|
|
10930
|
-
exports.setMetricClause = setMetricClause;
|
|
10931
10953
|
exports.setSuggestionBinding = setSuggestionBinding;
|
|
10932
10954
|
exports.smartIncrement = smartIncrement;
|
|
10933
10955
|
exports.sourcePlane = sourcePlane;
|
|
@@ -10950,7 +10972,6 @@ exports.wodEditorKeymap = wodEditorKeymap;
|
|
|
10950
10972
|
exports.wodLinter = wodLinter;
|
|
10951
10973
|
exports.wodOverlayPanel = wodOverlayPanel;
|
|
10952
10974
|
exports.workoutLintSource = workoutLintSource;
|
|
10953
|
-
exports.wqlToClauses = wqlToClauses;
|
|
10954
10975
|
exports.wrapInTimeFence = wrapInTimeFence;
|
|
10955
10976
|
//# sourceMappingURL=index.cjs.map
|
|
10956
10977
|
//# sourceMappingURL=index.cjs.map
|