From fdf4c6628f2690b3a21e3e801224db12f45c03c3 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Tue, 5 Jan 2021 22:04:31 +0100 Subject: [PATCH 01/19] Add browserSearch bridge command --- qt/aqt/stats.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index 055a81424..fd7a195a7 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -51,6 +51,7 @@ class NewDeckStats(QDialog): gui_hooks.stats_dialog_will_show(self) self.show() self.refresh() + self.form.web.set_bridge_command(self._on_bridge_cmd, self) self.activateWindow() def reject(self): @@ -89,6 +90,14 @@ class NewDeckStats(QDialog): def changeScope(self, type): pass + def _on_bridge_cmd(self, cmd: str) -> bool: + if cmd.startswith("browserSearch"): + _, query = cmd.split(':', 1) + browser = aqt.dialogs.open("Browser", self.mw) + browser.search_for(query) + + return False + def refresh(self): self.form.web.load_ts_page("graphs") From c8f0ee8b3b4823ceeab5fdf588837a4bd92e56a7 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Tue, 5 Jan 2021 22:28:51 +0100 Subject: [PATCH 02/19] Add search event listeners on graphs --- ts/graphs/GraphsPage.svelte | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ts/graphs/GraphsPage.svelte b/ts/graphs/GraphsPage.svelte index cd3928d7e..78f8141af 100644 --- a/ts/graphs/GraphsPage.svelte +++ b/ts/graphs/GraphsPage.svelte @@ -24,7 +24,9 @@ const preferencesPromise = getPreferences(); - const refreshWith = async (search: string, days: number) => { + const refreshWith = async (searchNew: string, days: number) => { + search = searchNew + active = true; try { [sourceData, preferences] = await Promise.all([ @@ -44,6 +46,11 @@ }; refreshWith(search, days); + + const browserSearch = (event: CustomEvent) => { + const query = `${search} ${event.detail.query}` + bridgeCommand(`browserSearch:${query}`) + } {#if controller} @@ -65,7 +72,8 @@ {preferences} {revlogRange} {i18n} - {nightMode} /> + {nightMode} + on:search={browserSearch} /> {/each} {/if} From 3ab92b34277f97e53cc4d05e1428a6a84b4b69d4 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Wed, 6 Jan 2021 13:40:05 +0100 Subject: [PATCH 03/19] Add a working example of searching from the stats screen in the Card Counts --- ts/graphs/CardCounts.svelte | 12 ++++++++- ts/graphs/GraphsPage.svelte | 8 +++--- ts/graphs/card-counts.ts | 51 ++++++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/ts/graphs/CardCounts.svelte b/ts/graphs/CardCounts.svelte index 7835f7e10..3667c8bde 100644 --- a/ts/graphs/CardCounts.svelte +++ b/ts/graphs/CardCounts.svelte @@ -1,4 +1,5 @@ {#if controller} diff --git a/ts/graphs/card-counts.ts b/ts/graphs/card-counts.ts index f45bca720..12b0b7799 100644 --- a/ts/graphs/card-counts.ts +++ b/ts/graphs/card-counts.ts @@ -23,7 +23,7 @@ import type { GraphBounds } from "./graph-helpers"; import { cumsum } from "d3-array"; import type { I18n } from "anki/i18n"; -type Count = [string, number, boolean]; +type Count = [string, number, boolean, string]; export interface GraphData { title: string; counts: Count[]; @@ -86,18 +86,51 @@ function countCards( } } + const extraQuery = separateInactive ? " -(is:buried or is:suspended)" : ""; + const counts: Count[] = [ - [i18n.tr(i18n.TR.STATISTICS_COUNTS_NEW_CARDS), newCards, true], - [i18n.tr(i18n.TR.STATISTICS_COUNTS_LEARNING_CARDS), learn, true], - [i18n.tr(i18n.TR.STATISTICS_COUNTS_RELEARNING_CARDS), relearn, true], - [i18n.tr(i18n.TR.STATISTICS_COUNTS_YOUNG_CARDS), young, true], - [i18n.tr(i18n.TR.STATISTICS_COUNTS_MATURE_CARDS), mature, true], + [ + i18n.tr(i18n.TR.STATISTICS_COUNTS_NEW_CARDS), + newCards, + true, + `is:new${extraQuery}`, + ], + [ + i18n.tr(i18n.TR.STATISTICS_COUNTS_LEARNING_CARDS), + learn, + true, + `(-is:review is:learn)${extraQuery}`, + ], + [ + i18n.tr(i18n.TR.STATISTICS_COUNTS_RELEARNING_CARDS), + relearn, + true, + `(is:review is:learn)${extraQuery}`, + ], + [ + i18n.tr(i18n.TR.STATISTICS_COUNTS_YOUNG_CARDS), + young, + true, + `(is:review -is:learn) prop:ivl<21${extraQuery}`, + ], + [ + i18n.tr(i18n.TR.STATISTICS_COUNTS_MATURE_CARDS), + mature, + true, + `(is:review -is:learn) prop:ivl>=21${extraQuery}`, + ], [ i18n.tr(i18n.TR.STATISTICS_COUNTS_SUSPENDED_CARDS), suspended, separateInactive, + "is:suspended", + ], + [ + i18n.tr(i18n.TR.STATISTICS_COUNTS_BURIED_CARDS), + buried, + separateInactive, + "is:buried", ], - [i18n.tr(i18n.TR.STATISTICS_COUNTS_BURIED_CARDS), buried, separateInactive], ]; return counts; @@ -132,6 +165,7 @@ export interface SummedDatum { count: number; // show up in the table show: boolean; + query: string; // running total total: number; } @@ -139,6 +173,7 @@ export interface SummedDatum { export interface TableDatum { label: string; count: number; + query: string; percent: string; colour: string; } @@ -155,6 +190,7 @@ export function renderCards( label: count[0], count: count[1], show: count[2], + query: count[3], idx, total: n, } as SummedDatum; @@ -205,6 +241,7 @@ export function renderCards( count: d.count, percent: `${percent}%`, colour: barColours[idx], + query: d.query, } as TableDatum) : []; }); From 6a0f2a0ebbb188c4ab7253fc2260a6a4de942f74 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Wed, 6 Jan 2021 19:26:47 +0100 Subject: [PATCH 04/19] Export bridgeCommandsSupported from graphs.rs for stats --- ts/graphs/CardCounts.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ts/graphs/CardCounts.svelte b/ts/graphs/CardCounts.svelte index 3667c8bde..55b1ea47f 100644 --- a/ts/graphs/CardCounts.svelte +++ b/ts/graphs/CardCounts.svelte @@ -89,7 +89,11 @@ ■  - dispatch('search', { query: d.query })}>{d.label} + {#if sourceData.bridgeCommandsSupported} + dispatch('search', { query: d.query })}>{d.label} + {:else} + {d.label} + {/if} {d.count} {d.percent} From a7c8b021dd76d02c97a4aabefd57e70c8fa778e3 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Thu, 7 Jan 2021 01:09:55 +0100 Subject: [PATCH 05/19] Satisfy formatter --- qt/aqt/stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index fd7a195a7..2903f1917 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -92,7 +92,7 @@ class NewDeckStats(QDialog): def _on_bridge_cmd(self, cmd: str) -> bool: if cmd.startswith("browserSearch"): - _, query = cmd.split(':', 1) + _, query = cmd.split(":", 1) browser = aqt.dialogs.open("Browser", self.mw) browser.search_for(query) From 58950452e409d0a01cc33d6260ea22074b791243 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Thu, 7 Jan 2021 12:22:50 +0100 Subject: [PATCH 06/19] Add search to added graph --- ts/graphs/AddedGraph.svelte | 2 +- ts/graphs/HistogramGraph.svelte | 5 ++++- ts/graphs/added.ts | 18 +++++++++++++++++- ts/graphs/histogram-graph.ts | 20 ++++++++++++++++++-- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/ts/graphs/AddedGraph.svelte b/ts/graphs/AddedGraph.svelte index 7d9485611..5ff7af8b9 100644 --- a/ts/graphs/AddedGraph.svelte +++ b/ts/graphs/AddedGraph.svelte @@ -39,7 +39,7 @@ - + diff --git a/ts/graphs/HistogramGraph.svelte b/ts/graphs/HistogramGraph.svelte index d178d33af..86347ad58 100644 --- a/ts/graphs/HistogramGraph.svelte +++ b/ts/graphs/HistogramGraph.svelte @@ -1,4 +1,5 @@ diff --git a/ts/graphs/added.ts b/ts/graphs/added.ts index 74caf2206..0e9b8f2fe 100644 --- a/ts/graphs/added.ts +++ b/ts/graphs/added.ts @@ -102,8 +102,24 @@ export function buildHistogram( return `${day}:
${cards}
${total}: ${totalCards}`; } + function makeQuery( + data: HistogramData, + binIdx: number, + ): string { + const start = Math.abs(data.bins[binIdx].x0!) + 1; + const include = `added:${start}` + + if (start === 1) { + return include + } + + const end = Math.abs(data.bins[binIdx].x1!) + 1; + const exclude = `-added:${end}` + return `${include} ${exclude}` + } + return [ - { scale, bins, total: totalInPeriod, hoverText, colourScale, showArea: true }, + { scale, bins, total: totalInPeriod, hoverText, makeQuery, colourScale, showArea: true }, tableData, ]; } diff --git a/ts/graphs/histogram-graph.ts b/ts/graphs/histogram-graph.ts index aa067c66a..5f995f9d4 100644 --- a/ts/graphs/histogram-graph.ts +++ b/ts/graphs/histogram-graph.ts @@ -25,6 +25,10 @@ export interface HistogramData { cumulative: number, percent: number ) => string; + makeQuery?: ( + data: HistogramData, + binIdx: number, + ) => string; showArea: boolean; colourScale: ScaleSequential; binValue?: (bin: Bin) => number; @@ -34,7 +38,8 @@ export interface HistogramData { export function histogramGraph( svgElem: SVGElement, bounds: GraphBounds, - data: HistogramData | null + data: HistogramData | null, + dispatch: any, ): void { const svg = select(svgElem); const trans = svg.transition().duration(600) as any; @@ -152,10 +157,21 @@ export function histogramGraph( .attr("y", () => y(yMax!)!) .attr("width", barWidth) .attr("height", () => y(0)! - y(yMax!)!) + .on("mouseover", function (this: any) { + this.style = "cursor: pointer;"; + }) .on("mousemove", function (this: any, d: any, idx) { const [x, y] = mouse(document.body); const pct = data.showArea ? (areaData[idx + 1] / data.total) * 100 : 0; showTooltip(data.hoverText(data, idx, areaData[idx + 1], pct), x, y); }) - .on("mouseout", hideTooltip); + .on("mouseout", function (this: any) { + hideTooltip; + this.style = ""; + }) + .on('click', function(this: any, d: any, idx: number) { + console.log('clicked', this) + if (!data.makeQuery) { return } + dispatch("search", { query: data.makeQuery(data, idx) }) + }); } From 1232fd70691cd40d9a418aa17ee16c1a59815c97 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Thu, 7 Jan 2021 12:44:58 +0100 Subject: [PATCH 07/19] Add search functional on interval graph --- ts/graphs/IntervalsGraph.svelte | 2 +- ts/graphs/intervals.ts | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/ts/graphs/IntervalsGraph.svelte b/ts/graphs/IntervalsGraph.svelte index 5f94b9fc2..aca20542b 100644 --- a/ts/graphs/IntervalsGraph.svelte +++ b/ts/graphs/IntervalsGraph.svelte @@ -59,7 +59,7 @@ - + diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts index 624701f60..0038e20b5 100644 --- a/ts/graphs/intervals.ts +++ b/ts/graphs/intervals.ts @@ -134,6 +134,26 @@ export function prepareIntervalData( return `${interval}
${total}: \u200e${percent.toFixed(1)}%`; } + function makeQuery( + data: HistogramData, + binIdx: number, + ): string { + const onlyReview = "-(is:new or is:learn or is:suspended or is:buried)" + + const bin = data.bins[binIdx]; + const start = bin.x0!; + const end = bin.x1! - 1; + + if (start === end) { + return `prop:ivl=${start} ${onlyReview}` + } + + const fromQuery = `prop:ivl>=${start}` + const tillQuery = `prop:ivl<=${end}` + + return `${fromQuery} ${tillQuery} ${onlyReview}` + } + const meanInterval = Math.round(mean(allIntervals) ?? 0); const meanIntervalString = timeSpan(i18n, meanInterval * 86400, false); const tableData = [ @@ -143,7 +163,7 @@ export function prepareIntervalData( }, ]; return [ - { scale, bins, total: totalInPeriod, hoverText, colourScale, showArea: true }, + { scale, bins, total: totalInPeriod, hoverText, makeQuery, colourScale, showArea: true }, tableData, ]; } From 8a43745f837be7286d0dfd5fcec0b8d185c21145 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 8 Jan 2021 13:48:42 +0100 Subject: [PATCH 08/19] Remove onlyReview from intervals query --- ts/graphs/intervals.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts index 0038e20b5..a87361e78 100644 --- a/ts/graphs/intervals.ts +++ b/ts/graphs/intervals.ts @@ -138,20 +138,18 @@ export function prepareIntervalData( data: HistogramData, binIdx: number, ): string { - const onlyReview = "-(is:new or is:learn or is:suspended or is:buried)" - const bin = data.bins[binIdx]; const start = bin.x0!; const end = bin.x1! - 1; if (start === end) { - return `prop:ivl=${start} ${onlyReview}` + return `prop:ivl=${start}` } const fromQuery = `prop:ivl>=${start}` const tillQuery = `prop:ivl<=${end}` - return `${fromQuery} ${tillQuery} ${onlyReview}` + return `${fromQuery} ${tillQuery}` } const meanInterval = Math.round(mean(allIntervals) ?? 0); From 2fd40394943082a34b6c5bf141cef959892c6efd Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 8 Jan 2021 13:59:33 +0100 Subject: [PATCH 09/19] Add query functionality to FutureDue graph --- ts/graphs/FutureDue.svelte | 2 +- ts/graphs/future-due.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ts/graphs/FutureDue.svelte b/ts/graphs/FutureDue.svelte index 984707a09..a10560b8f 100644 --- a/ts/graphs/FutureDue.svelte +++ b/ts/graphs/FutureDue.svelte @@ -53,7 +53,7 @@ - + diff --git a/ts/graphs/future-due.ts b/ts/graphs/future-due.ts index 1ae73c0bf..085a987e6 100644 --- a/ts/graphs/future-due.ts +++ b/ts/graphs/future-due.ts @@ -145,6 +145,24 @@ export function buildHistogram( return `${days}:
${cards}
${totalLabel}: ${cumulative}`; } + function makeQuery( + data: HistogramData, + binIdx: number, + ): string { + const bin = data.bins[binIdx]; + const start = bin.x0!; + const end = bin.x1! - 1; + + if (start === end) { + return `"prop:due=${start}"` + } + + const fromQuery = `"prop:due>=${start}"` + const tillQuery = `"prop:due<=${end}"` + + return `${fromQuery} AND ${tillQuery}` + } + const periodDays = xMax! - xMin!; const tableData = [ { @@ -171,6 +189,7 @@ export function buildHistogram( bins, total, hoverText, + makeQuery, showArea: true, colourScale, binValue, From 740dcedbe66928e634157241448379034d4be404 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 8 Jan 2021 14:00:18 +0100 Subject: [PATCH 10/19] Normalize intervals query --- ts/graphs/intervals.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts index a87361e78..4ef512fae 100644 --- a/ts/graphs/intervals.ts +++ b/ts/graphs/intervals.ts @@ -143,13 +143,13 @@ export function prepareIntervalData( const end = bin.x1! - 1; if (start === end) { - return `prop:ivl=${start}` + return `"prop:ivl=${start}"` } - const fromQuery = `prop:ivl>=${start}` - const tillQuery = `prop:ivl<=${end}` + const fromQuery = `"prop:ivl>=${start}"` + const tillQuery = `"prop:ivl<=${end}"` - return `${fromQuery} ${tillQuery}` + return `${fromQuery} AND ${tillQuery}` } const meanInterval = Math.round(mean(allIntervals) ?? 0); From fd58f73f13f76c101d3aba6eaeaae347d16b759b Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 8 Jan 2021 14:22:20 +0100 Subject: [PATCH 11/19] Fix up histogram code to correctly hide tooltip again --- ts/graphs/graphs.scss | 4 ++++ ts/graphs/histogram-graph.ts | 27 ++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/ts/graphs/graphs.scss b/ts/graphs/graphs.scss index 75c4eddf7..bd2aa4615 100644 --- a/ts/graphs/graphs.scss +++ b/ts/graphs/graphs.scss @@ -197,3 +197,7 @@ .no-focus-outline:focus { outline: 0; } + +.clickable { + cursor: pointer; +} diff --git a/ts/graphs/histogram-graph.ts b/ts/graphs/histogram-graph.ts index 5f995f9d4..8a4b90d90 100644 --- a/ts/graphs/histogram-graph.ts +++ b/ts/graphs/histogram-graph.ts @@ -136,7 +136,7 @@ export function histogramGraph( "d", area() .curve(curveBasis) - .x((d, idx) => { + .x((_d, idx) => { if (idx === 0) { return x(data.bins[0].x0!)!; } else { @@ -149,7 +149,7 @@ export function histogramGraph( } // hover/tooltip - svg.select("g.hoverzone") + const hoverzone = svg.select("g.hoverzone") .selectAll("rect") .data(data.bins) .join("rect") @@ -157,21 +157,18 @@ export function histogramGraph( .attr("y", () => y(yMax!)!) .attr("width", barWidth) .attr("height", () => y(0)! - y(yMax!)!) - .on("mouseover", function (this: any) { - this.style = "cursor: pointer;"; - }) - .on("mousemove", function (this: any, d: any, idx) { + .on("mousemove", function (this: any, _d: any, idx: number) { const [x, y] = mouse(document.body); const pct = data.showArea ? (areaData[idx + 1] / data.total) * 100 : 0; showTooltip(data.hoverText(data, idx, areaData[idx + 1], pct), x, y); }) - .on("mouseout", function (this: any) { - hideTooltip; - this.style = ""; - }) - .on('click', function(this: any, d: any, idx: number) { - console.log('clicked', this) - if (!data.makeQuery) { return } - dispatch("search", { query: data.makeQuery(data, idx) }) - }); + .on("mouseout", hideTooltip); + + if (data.makeQuery) { + hoverzone + .attr("class", "clickable") + .on("click", function (this: any, _d: any, idx: number) { + dispatch("search", { query: data.makeQuery!(data, idx) }) + }); + } } From 0e98bd7db2d558b087994430ce7c6bd3cc2807e9 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 8 Jan 2021 14:28:38 +0100 Subject: [PATCH 12/19] Normalize the remaining queries --- ts/graphs/added.ts | 23 ++++++++++++++--------- ts/graphs/card-counts.ts | 16 ++++++++-------- ts/graphs/future-due.ts | 13 +++++-------- ts/graphs/histogram-graph.ts | 12 +++++------- ts/graphs/intervals.ts | 23 ++++++++++++++--------- 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/ts/graphs/added.ts b/ts/graphs/added.ts index 0e9b8f2fe..c22ea73a7 100644 --- a/ts/graphs/added.ts +++ b/ts/graphs/added.ts @@ -102,24 +102,29 @@ export function buildHistogram( return `${day}:
${cards}
${total}: ${totalCards}`; } - function makeQuery( - data: HistogramData, - binIdx: number, - ): string { + function makeQuery(data: HistogramData, binIdx: number): string { const start = Math.abs(data.bins[binIdx].x0!) + 1; - const include = `added:${start}` + const include = `"added:${start}"`; if (start === 1) { - return include + return include; } const end = Math.abs(data.bins[binIdx].x1!) + 1; - const exclude = `-added:${end}` - return `${include} ${exclude}` + const exclude = `-"added:${end}"`; + return `${include} AND ${exclude}`; } return [ - { scale, bins, total: totalInPeriod, hoverText, makeQuery, colourScale, showArea: true }, + { + scale, + bins, + total: totalInPeriod, + hoverText, + makeQuery, + colourScale, + showArea: true, + }, tableData, ]; } diff --git a/ts/graphs/card-counts.ts b/ts/graphs/card-counts.ts index 12b0b7799..0eb2fba8f 100644 --- a/ts/graphs/card-counts.ts +++ b/ts/graphs/card-counts.ts @@ -86,50 +86,50 @@ function countCards( } } - const extraQuery = separateInactive ? " -(is:buried or is:suspended)" : ""; + const extraQuery = separateInactive ? 'AND -("is:buried" OR "is:suspended")' : ""; const counts: Count[] = [ [ i18n.tr(i18n.TR.STATISTICS_COUNTS_NEW_CARDS), newCards, true, - `is:new${extraQuery}`, + `"is:new"${extraQuery}`, ], [ i18n.tr(i18n.TR.STATISTICS_COUNTS_LEARNING_CARDS), learn, true, - `(-is:review is:learn)${extraQuery}`, + `(-"is:review" AND "is:learn")${extraQuery}`, ], [ i18n.tr(i18n.TR.STATISTICS_COUNTS_RELEARNING_CARDS), relearn, true, - `(is:review is:learn)${extraQuery}`, + `("is:review" AND "is:learn")${extraQuery}`, ], [ i18n.tr(i18n.TR.STATISTICS_COUNTS_YOUNG_CARDS), young, true, - `(is:review -is:learn) prop:ivl<21${extraQuery}`, + `("is:review" AND -"is:learn") AND "prop:ivl<21"${extraQuery}`, ], [ i18n.tr(i18n.TR.STATISTICS_COUNTS_MATURE_CARDS), mature, true, - `(is:review -is:learn) prop:ivl>=21${extraQuery}`, + `("is:review" -"is:learn") AND "prop:ivl>=21"${extraQuery}`, ], [ i18n.tr(i18n.TR.STATISTICS_COUNTS_SUSPENDED_CARDS), suspended, separateInactive, - "is:suspended", + '"is:suspended"', ], [ i18n.tr(i18n.TR.STATISTICS_COUNTS_BURIED_CARDS), buried, separateInactive, - "is:buried", + '"is:buried"', ], ]; diff --git a/ts/graphs/future-due.ts b/ts/graphs/future-due.ts index 085a987e6..d1f09018e 100644 --- a/ts/graphs/future-due.ts +++ b/ts/graphs/future-due.ts @@ -145,22 +145,19 @@ export function buildHistogram( return `${days}:
${cards}
${totalLabel}: ${cumulative}`; } - function makeQuery( - data: HistogramData, - binIdx: number, - ): string { + function makeQuery(data: HistogramData, binIdx: number): string { const bin = data.bins[binIdx]; const start = bin.x0!; const end = bin.x1! - 1; if (start === end) { - return `"prop:due=${start}"` + return `"prop:due=${start}"`; } - const fromQuery = `"prop:due>=${start}"` - const tillQuery = `"prop:due<=${end}"` + const fromQuery = `"prop:due>=${start}"`; + const tillQuery = `"prop:due<=${end}"`; - return `${fromQuery} AND ${tillQuery}` + return `${fromQuery} AND ${tillQuery}`; } const periodDays = xMax! - xMin!; diff --git a/ts/graphs/histogram-graph.ts b/ts/graphs/histogram-graph.ts index 8a4b90d90..93f5ddad9 100644 --- a/ts/graphs/histogram-graph.ts +++ b/ts/graphs/histogram-graph.ts @@ -25,10 +25,7 @@ export interface HistogramData { cumulative: number, percent: number ) => string; - makeQuery?: ( - data: HistogramData, - binIdx: number, - ) => string; + makeQuery?: (data: HistogramData, binIdx: number) => string; showArea: boolean; colourScale: ScaleSequential; binValue?: (bin: Bin) => number; @@ -39,7 +36,7 @@ export function histogramGraph( svgElem: SVGElement, bounds: GraphBounds, data: HistogramData | null, - dispatch: any, + dispatch: any ): void { const svg = select(svgElem); const trans = svg.transition().duration(600) as any; @@ -149,7 +146,8 @@ export function histogramGraph( } // hover/tooltip - const hoverzone = svg.select("g.hoverzone") + const hoverzone = svg + .select("g.hoverzone") .selectAll("rect") .data(data.bins) .join("rect") @@ -168,7 +166,7 @@ export function histogramGraph( hoverzone .attr("class", "clickable") .on("click", function (this: any, _d: any, idx: number) { - dispatch("search", { query: data.makeQuery!(data, idx) }) + dispatch("search", { query: data.makeQuery!(data, idx) }); }); } } diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts index 4ef512fae..b31f88def 100644 --- a/ts/graphs/intervals.ts +++ b/ts/graphs/intervals.ts @@ -134,22 +134,19 @@ export function prepareIntervalData( return `${interval}
${total}: \u200e${percent.toFixed(1)}%`; } - function makeQuery( - data: HistogramData, - binIdx: number, - ): string { + function makeQuery(data: HistogramData, binIdx: number): string { const bin = data.bins[binIdx]; const start = bin.x0!; const end = bin.x1! - 1; if (start === end) { - return `"prop:ivl=${start}"` + return `"prop:ivl=${start}"`; } - const fromQuery = `"prop:ivl>=${start}"` - const tillQuery = `"prop:ivl<=${end}"` + const fromQuery = `"prop:ivl>=${start}"`; + const tillQuery = `"prop:ivl<=${end}"`; - return `${fromQuery} AND ${tillQuery}` + return `${fromQuery} AND ${tillQuery}`; } const meanInterval = Math.round(mean(allIntervals) ?? 0); @@ -161,7 +158,15 @@ export function prepareIntervalData( }, ]; return [ - { scale, bins, total: totalInPeriod, hoverText, makeQuery, colourScale, showArea: true }, + { + scale, + bins, + total: totalInPeriod, + hoverText, + makeQuery, + colourScale, + showArea: true, + }, tableData, ]; } From f1c8879830b98f122db5d934c9fb704a0bcf7f9d Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 8 Jan 2021 17:16:52 +0100 Subject: [PATCH 13/19] Add search functionality for ease graph --- ts/graphs/EaseGraph.svelte | 2 +- ts/graphs/ease.ts | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ts/graphs/EaseGraph.svelte b/ts/graphs/EaseGraph.svelte index 76725fb6e..89c728b44 100644 --- a/ts/graphs/EaseGraph.svelte +++ b/ts/graphs/EaseGraph.svelte @@ -26,7 +26,7 @@
{subtitle}
- + diff --git a/ts/graphs/ease.ts b/ts/graphs/ease.ts index 872efa77d..05d3212fb 100644 --- a/ts/graphs/ease.ts +++ b/ts/graphs/ease.ts @@ -61,6 +61,21 @@ export function prepareData( }); } + function makeQuery(data: HistogramData, binIdx: number): string { + const bin = data.bins[binIdx]; + const start = bin.x0!; + const end = (bin.x1! - 1); + + if (start === end) { + return `"prop:ease=${start / 100}"`; + } + + const fromQuery = `"prop:ease>=${start / 100}"`; + const tillQuery = `"prop:ease<${end / 100}"`; + + return `${fromQuery} AND ${tillQuery}`; + } + const xTickFormat = (num: number): string => `${num.toFixed(0)}%`; const tableData = [ { @@ -70,7 +85,7 @@ export function prepareData( ]; return [ - { scale, bins, total, hoverText, colourScale, showArea: false, xTickFormat }, + { scale, bins, total, hoverText, makeQuery, colourScale, showArea: false, xTickFormat }, tableData, ]; } From 7f671cf837e4803ad54c4f25c47e6902703f42b0 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Mon, 18 Jan 2021 01:24:32 +0100 Subject: [PATCH 14/19] Add search functionality to Calendar view --- ts/graphs/CalendarGraph.svelte | 4 ++++ ts/graphs/calendar.ts | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/ts/graphs/CalendarGraph.svelte b/ts/graphs/CalendarGraph.svelte index 0ad08d0b8..5296f6027 100644 --- a/ts/graphs/CalendarGraph.svelte +++ b/ts/graphs/CalendarGraph.svelte @@ -1,4 +1,5 @@ diff --git a/ts/graphs/IntervalsGraph.svelte b/ts/graphs/IntervalsGraph.svelte index 50d979be4..f77348bae 100644 --- a/ts/graphs/IntervalsGraph.svelte +++ b/ts/graphs/IntervalsGraph.svelte @@ -13,9 +13,11 @@ import type { TableDatum } from "./graph-helpers"; import TableData from "./TableData.svelte"; import { createEventDispatcher } from "svelte"; + import type { PreferenceStore } from "./preferences"; export let sourceData: pb.BackendProto.GraphsOut | null = null; export let i18n: I18n; + export let preferences: PreferenceStore; const dispatch = createEventDispatcher(); @@ -23,13 +25,20 @@ let histogramData = null as HistogramData | null; let tableData: TableDatum[] = []; let range = IntervalRange.Percentile95; + let { browserLinksSupported } = preferences; $: if (sourceData) { intervalData = gatherIntervalData(sourceData); } $: if (intervalData) { - [histogramData, tableData] = prepareIntervalData(intervalData, range, i18n, dispatch); + [histogramData, tableData] = prepareIntervalData( + intervalData, + range, + i18n, + dispatch, + $browserLinksSupported + ); } const title = i18n.tr(i18n.TR.STATISTICS_INTERVALS_TITLE); @@ -62,7 +71,7 @@ - + diff --git a/ts/graphs/added.ts b/ts/graphs/added.ts index 3574cf959..a68fd875f 100644 --- a/ts/graphs/added.ts +++ b/ts/graphs/added.ts @@ -44,6 +44,7 @@ export function buildHistogram( range: GraphRange, i18n: I18n, dispatch: any, + browserLinksSupported: boolean ): [HistogramData | null, TableDatum[]] { // get min/max const total = data.daysAdded.length; @@ -127,7 +128,7 @@ export function buildHistogram( bins, total: totalInPeriod, hoverText, - onClick, + onClick: browserLinksSupported ? onClick : null, colourScale, showArea: true, }, diff --git a/ts/graphs/ease.ts b/ts/graphs/ease.ts index a083960d4..9468f7c04 100644 --- a/ts/graphs/ease.ts +++ b/ts/graphs/ease.ts @@ -41,6 +41,7 @@ export function prepareData( data: GraphData, i18n: I18n, dispatch: any, + browserLinksSupported: boolean ): [HistogramData | null, TableDatum[]] { // get min/max const allEases = data.eases; @@ -94,7 +95,7 @@ export function prepareData( bins, total, hoverText, - onClick, + onClick: browserLinksSupported ? onClick : null, colourScale, showArea: false, xTickFormat, diff --git a/ts/graphs/future-due.ts b/ts/graphs/future-due.ts index 498e8dff9..fbd0f880f 100644 --- a/ts/graphs/future-due.ts +++ b/ts/graphs/future-due.ts @@ -75,8 +75,7 @@ export interface FutureDueOut { function makeQuery(start: number, end: number): string { if (start === end) { return `"prop:due=${start}"`; - } - else { + } else { const fromQuery = `"prop:due>=${start}"`; const tillQuery = `"prop:due<=${end}"`; return `${fromQuery} AND ${tillQuery}`; @@ -89,6 +88,7 @@ export function buildHistogram( backlog: boolean, i18n: I18n, dispatch: any, + browserLinksSupported: boolean ): FutureDueOut { const output = { histogramData: null, tableData: [] }; // get min/max @@ -190,7 +190,7 @@ export function buildHistogram( bins, total, hoverText, - onClick, + onClick: browserLinksSupported ? onClick : null, showArea: true, colourScale, binValue, diff --git a/ts/graphs/histogram-graph.ts b/ts/graphs/histogram-graph.ts index f22b31850..4cf1a0d76 100644 --- a/ts/graphs/histogram-graph.ts +++ b/ts/graphs/histogram-graph.ts @@ -25,7 +25,7 @@ export interface HistogramData { cumulative: number, percent: number ) => string; - onClick?: (data: Bin) => void; + onClick: ((data: Bin) => void) | null; showArea: boolean; colourScale: ScaleSequential; binValue?: (bin: Bin) => number; @@ -35,7 +35,7 @@ export interface HistogramData { export function histogramGraph( svgElem: SVGElement, bounds: GraphBounds, - data: HistogramData | null, + data: HistogramData | null ): void { const svg = select(svgElem); const trans = svg.transition().duration(600) as any; @@ -162,8 +162,6 @@ export function histogramGraph( .on("mouseout", hideTooltip); if (data.onClick) { - hoverzone - .attr("class", "clickable") - .on("click", data.onClick); + hoverzone.attr("class", "clickable").on("click", data.onClick); } } diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts index 9d652eb2f..91741e3dc 100644 --- a/ts/graphs/intervals.ts +++ b/ts/graphs/intervals.ts @@ -72,6 +72,7 @@ export function prepareIntervalData( range: IntervalRange, i18n: I18n, dispatch: any, + browserLinksSupported: boolean ): [HistogramData | null, TableDatum[]] { // get min/max const allIntervals = data.intervals; @@ -161,13 +162,14 @@ export function prepareIntervalData( value: meanIntervalString, }, ]; + return [ { scale, bins, total: totalInPeriod, hoverText, - onClick, + onClick: browserLinksSupported ? onClick : null, colourScale, showArea: true, }, From 5abd7ae6f3fdb7d9736a0f2993617df0a086670d Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Tue, 26 Jan 2021 01:25:22 +0100 Subject: [PATCH 19/19] Add bridgeCommand helper function --- ts/graphs/GraphsPage.svelte | 1 + ts/lib/bridgecommand.ts | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/ts/graphs/GraphsPage.svelte b/ts/graphs/GraphsPage.svelte index f26aae9fa..2597a09f0 100644 --- a/ts/graphs/GraphsPage.svelte +++ b/ts/graphs/GraphsPage.svelte @@ -8,6 +8,7 @@ import type pb from "anki/backend_proto"; import { getGraphData, RevlogRange, daysToRevlogRange } from "./graph-helpers"; import { getPreferences } from "./preferences"; + import { bridgeCommand } from "anki/bridgecommand"; export let i18n: I18n; export let nightMode: boolean; diff --git a/ts/lib/bridgecommand.ts b/ts/lib/bridgecommand.ts index b7a0f721b..927e7dd03 100644 --- a/ts/lib/bridgecommand.ts +++ b/ts/lib/bridgecommand.ts @@ -1,7 +1,17 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +declare global { + interface Window { + bridgeCommand(command: string, callback?: (value: T) => void): void; + } +} + /// HTML tag pointing to a bridge command. export function bridgeLink(command: string, label: string): string { return `${label}`; } + +export function bridgeCommand(command: string, callback?: (value: T) => void): void { + window.bridgeCommand(command, callback); +}