diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py
index a3641fd95..3b0b16666 100644
--- a/qt/aqt/deckbrowser.py
+++ b/qt/aqt/deckbrowser.py
@@ -65,7 +65,7 @@ class DeckBrowser:
def _linkHandler(self, url):
if ":" in url:
- (cmd, arg) = url.split(":")
+ (cmd, arg) = url.split(":", 1)
else:
cmd = url
if cmd == "open":
diff --git a/rslib/backend.proto b/rslib/backend.proto
index 392ed3388..1dcb9dac5 100644
--- a/rslib/backend.proto
+++ b/rslib/backend.proto
@@ -1092,7 +1092,6 @@ message GraphsOut {
uint32 scheduler_version = 5;
/// Seconds to add to UTC timestamps to get local time.
int32 local_offset_secs = 7;
- bool bridge_commands_supported = 8;
}
message GraphPreferences {
@@ -1104,6 +1103,7 @@ message GraphPreferences {
}
Weekday calendar_first_day_of_week = 1;
bool card_counts_separate_inactive = 2;
+ bool browser_links_supported = 3;
}
message RevlogEntry {
diff --git a/rslib/src/stats/graphs.rs b/rslib/src/stats/graphs.rs
index 73ae77836..704625575 100644
--- a/rslib/src/stats/graphs.rs
+++ b/rslib/src/stats/graphs.rs
@@ -44,7 +44,6 @@ impl Collection {
next_day_at_secs: timing.next_day_at as u32,
scheduler_version: self.sched_ver() as u32,
local_offset_secs: local_offset_secs as i32,
- bridge_commands_supported: true,
})
}
@@ -52,6 +51,7 @@ impl Collection {
Ok(pb::GraphPreferences {
calendar_first_day_of_week: self.get_first_day_of_week() as i32,
card_counts_separate_inactive: self.get_card_counts_separate_inactive(),
+ browser_links_supported: true,
})
}
diff --git a/ts/graphs/AddedGraph.svelte b/ts/graphs/AddedGraph.svelte
index 5ff7af8b9..ed30aec2b 100644
--- a/ts/graphs/AddedGraph.svelte
+++ b/ts/graphs/AddedGraph.svelte
@@ -9,6 +9,7 @@
import HistogramGraph from "./HistogramGraph.svelte";
import GraphRangeRadios from "./GraphRangeRadios.svelte";
import TableData from "./TableData.svelte";
+ import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
@@ -17,13 +18,15 @@
let tableData: TableDatum[] = [];
let graphRange: GraphRange = GraphRange.Month;
+ const dispatch = createEventDispatcher();
+
let addedData: GraphData | null = null;
$: if (sourceData) {
addedData = gatherData(sourceData);
}
$: if (addedData) {
- [histogramData, tableData] = buildHistogram(addedData, graphRange, i18n);
+ [histogramData, tableData] = buildHistogram(addedData, graphRange, i18n, dispatch);
}
const title = i18n.tr(i18n.TR.STATISTICS_ADDED_TITLE);
diff --git a/ts/graphs/CardCounts.svelte b/ts/graphs/CardCounts.svelte
index 55b1ea47f..6434de646 100644
--- a/ts/graphs/CardCounts.svelte
+++ b/ts/graphs/CardCounts.svelte
@@ -11,7 +11,7 @@
export let i18n: I18n;
export let preferences: PreferenceStore;
- let { cardCountsSeparateInactive } = preferences;
+ let { cardCountsSeparateInactive, browserLinksSupported } = preferences;
const dispatch = createEventDispatcher();
let svg = null as HTMLElement | SVGElement | null;
@@ -89,7 +89,7 @@
■
- {#if sourceData.bridgeCommandsSupported}
+ {#if browserLinksSupported}
dispatch('search', { query: d.query })}>{d.label}
{:else}
{d.label}
diff --git a/ts/graphs/EaseGraph.svelte b/ts/graphs/EaseGraph.svelte
index 89c728b44..559334e9f 100644
--- a/ts/graphs/EaseGraph.svelte
+++ b/ts/graphs/EaseGraph.svelte
@@ -6,15 +6,18 @@
import type { I18n } from "anki/i18n";
import type { TableDatum } from "./graph-helpers";
import TableData from "./TableData.svelte";
+ import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
+ const dispatch = createEventDispatcher();
+
let histogramData = null as HistogramData | null;
let tableData: TableDatum[] = [];
$: if (sourceData) {
- [histogramData, tableData] = prepareData(gatherData(sourceData), i18n);
+ [histogramData, tableData] = prepareData(gatherData(sourceData), i18n, dispatch);
}
const title = i18n.tr(i18n.TR.STATISTICS_CARD_EASE_TITLE);
diff --git a/ts/graphs/FutureDue.svelte b/ts/graphs/FutureDue.svelte
index a10560b8f..ffb27fe75 100644
--- a/ts/graphs/FutureDue.svelte
+++ b/ts/graphs/FutureDue.svelte
@@ -9,10 +9,13 @@
import HistogramGraph from "./HistogramGraph.svelte";
import GraphRangeRadios from "./GraphRangeRadios.svelte";
import TableData from "./TableData.svelte";
+ import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
+ const dispatch = createEventDispatcher();
+
let graphData = null as GraphData | null;
let histogramData = null as HistogramData | null;
let tableData: TableDatum[] = [] as any;
@@ -28,7 +31,8 @@
graphData,
graphRange,
backlog,
- i18n
+ i18n,
+ dispatch,
));
}
diff --git a/ts/graphs/IntervalsGraph.svelte b/ts/graphs/IntervalsGraph.svelte
index aca20542b..50d979be4 100644
--- a/ts/graphs/IntervalsGraph.svelte
+++ b/ts/graphs/IntervalsGraph.svelte
@@ -12,10 +12,13 @@
import HistogramGraph from "./HistogramGraph.svelte";
import type { TableDatum } from "./graph-helpers";
import TableData from "./TableData.svelte";
+ import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
+ const dispatch = createEventDispatcher();
+
let intervalData: IntervalGraphData | null = null;
let histogramData = null as HistogramData | null;
let tableData: TableDatum[] = [];
@@ -26,7 +29,7 @@
}
$: if (intervalData) {
- [histogramData, tableData] = prepareIntervalData(intervalData, range, i18n);
+ [histogramData, tableData] = prepareIntervalData(intervalData, range, i18n, dispatch);
}
const title = i18n.tr(i18n.TR.STATISTICS_INTERVALS_TITLE);
diff --git a/ts/graphs/added.ts b/ts/graphs/added.ts
index c22ea73a7..3574cf959 100644
--- a/ts/graphs/added.ts
+++ b/ts/graphs/added.ts
@@ -7,7 +7,7 @@
*/
import type pb from "anki/backend_proto";
-import { extent, histogram, sum } from "d3-array";
+import { extent, histogram, sum, Bin } from "d3-array";
import { scaleLinear, scaleSequential } from "d3-scale";
import type { HistogramData } from "./histogram-graph";
import { interpolateBlues } from "d3-scale-chromatic";
@@ -28,10 +28,22 @@ export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
return { daysAdded };
}
+function makeQuery(start: number, end: number): string {
+ const include = `"added:${start}"`;
+
+ if (start === 1) {
+ return include;
+ }
+
+ const exclude = `-"added:${end}"`;
+ return `${include} AND ${exclude}`;
+}
+
export function buildHistogram(
data: GraphData,
range: GraphRange,
- i18n: I18n
+ i18n: I18n,
+ dispatch: any,
): [HistogramData | null, TableDatum[]] {
// get min/max
const total = data.daysAdded.length;
@@ -102,17 +114,11 @@ 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} AND ${exclude}`;
+ function onClick(bin: Bin): void {
+ const start = Math.abs(bin.x0!) + 1;
+ const end = Math.abs(bin.x1!) + 1;
+ const query = makeQuery(start, end);
+ dispatch("search", { query });
}
return [
@@ -121,7 +127,7 @@ export function buildHistogram(
bins,
total: totalInPeriod,
hoverText,
- makeQuery,
+ onClick,
colourScale,
showArea: true,
},
diff --git a/ts/graphs/calendar.ts b/ts/graphs/calendar.ts
index fbc2fe964..0dae1a530 100644
--- a/ts/graphs/calendar.ts
+++ b/ts/graphs/calendar.ts
@@ -114,7 +114,6 @@ export function renderCalendar(
maxCount = count;
}
}
- console.log("sourceData", sourceData, dayMap);
if (!maxCount) {
setDataAvailable(svg, false);
diff --git a/ts/graphs/ease.ts b/ts/graphs/ease.ts
index 4f13e200f..a083960d4 100644
--- a/ts/graphs/ease.ts
+++ b/ts/graphs/ease.ts
@@ -7,7 +7,7 @@
*/
import type pb from "anki/backend_proto";
-import { extent, histogram, sum } from "d3-array";
+import { extent, histogram, sum, Bin } from "d3-array";
import { scaleLinear, scaleSequential } from "d3-scale";
import { CardType } from "anki/cards";
import type { HistogramData } from "./histogram-graph";
@@ -26,9 +26,21 @@ export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
return { eases };
}
+function makeQuery(start: number, end: number): string {
+ if (start === end) {
+ return `"prop:ease=${start / 100}"`;
+ }
+
+ const fromQuery = `"prop:ease>=${start / 100}"`;
+ const tillQuery = `"prop:ease<${end / 100}"`;
+
+ return `${fromQuery} AND ${tillQuery}`;
+}
+
export function prepareData(
data: GraphData,
- i18n: I18n
+ i18n: I18n,
+ dispatch: any,
): [HistogramData | null, TableDatum[]] {
// get min/max
const allEases = data.eases;
@@ -61,19 +73,11 @@ export function prepareData(
});
}
- function makeQuery(data: HistogramData, binIdx: number): string {
- const bin = data.bins[binIdx];
+ function onClick(bin: Bin): void {
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 query = makeQuery(start, end);
+ dispatch("search", { query });
}
const xTickFormat = (num: number): string => `${num.toFixed(0)}%`;
@@ -90,7 +94,7 @@ export function prepareData(
bins,
total,
hoverText,
- makeQuery,
+ onClick,
colourScale,
showArea: false,
xTickFormat,
diff --git a/ts/graphs/future-due.ts b/ts/graphs/future-due.ts
index d1f09018e..498e8dff9 100644
--- a/ts/graphs/future-due.ts
+++ b/ts/graphs/future-due.ts
@@ -72,11 +72,23 @@ export interface FutureDueOut {
tableData: TableDatum[];
}
+function makeQuery(start: number, end: number): string {
+ if (start === end) {
+ return `"prop:due=${start}"`;
+ }
+ else {
+ const fromQuery = `"prop:due>=${start}"`;
+ const tillQuery = `"prop:due<=${end}"`;
+ return `${fromQuery} AND ${tillQuery}`;
+ }
+}
+
export function buildHistogram(
sourceData: GraphData,
range: GraphRange,
backlog: boolean,
- i18n: I18n
+ i18n: I18n,
+ dispatch: any,
): FutureDueOut {
const output = { histogramData: null, tableData: [] };
// get min/max
@@ -145,19 +157,11 @@ export function buildHistogram(
return `${days}: ${cards} ${totalLabel}: ${cumulative}`;
}
- function makeQuery(data: HistogramData, binIdx: number): string {
- const bin = data.bins[binIdx];
+ function onClick(bin: Bin): void {
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 query = makeQuery(start, end);
+ dispatch("search", { query });
}
const periodDays = xMax! - xMin!;
@@ -186,7 +190,7 @@ export function buildHistogram(
bins,
total,
hoverText,
- makeQuery,
+ onClick,
showArea: true,
colourScale,
binValue,
diff --git a/ts/graphs/histogram-graph.ts b/ts/graphs/histogram-graph.ts
index 93f5ddad9..f22b31850 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;
- makeQuery?: (data: HistogramData, binIdx: number) => string;
+ onClick?: (data: Bin) => void;
showArea: boolean;
colourScale: ScaleSequential;
binValue?: (bin: Bin) => number;
@@ -36,7 +36,6 @@ export function histogramGraph(
svgElem: SVGElement,
bounds: GraphBounds,
data: HistogramData | null,
- dispatch: any
): void {
const svg = select(svgElem);
const trans = svg.transition().duration(600) as any;
@@ -162,11 +161,9 @@ export function histogramGraph(
})
.on("mouseout", hideTooltip);
- if (data.makeQuery) {
+ if (data.onClick) {
hoverzone
.attr("class", "clickable")
- .on("click", function (this: any, _d: any, idx: number) {
- dispatch("search", { query: data.makeQuery!(data, idx) });
- });
+ .on("click", data.onClick);
}
}
diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts
index b31f88def..9d652eb2f 100644
--- a/ts/graphs/intervals.ts
+++ b/ts/graphs/intervals.ts
@@ -7,7 +7,7 @@
*/
import type pb from "anki/backend_proto";
-import { extent, histogram, quantile, sum, mean } from "d3-array";
+import { extent, histogram, quantile, sum, mean, Bin } from "d3-array";
import { scaleLinear, scaleSequential } from "d3-scale";
import { CardType } from "anki/cards";
import type { HistogramData } from "./histogram-graph";
@@ -56,10 +56,22 @@ export function intervalLabel(
}
}
+function makeQuery(start: number, end: number): string {
+ if (start === end) {
+ return `"prop:ivl=${start}"`;
+ }
+
+ const fromQuery = `"prop:ivl>=${start}"`;
+ const tillQuery = `"prop:ivl<=${end}"`;
+
+ return `${fromQuery} AND ${tillQuery}`;
+}
+
export function prepareIntervalData(
data: IntervalGraphData,
range: IntervalRange,
- i18n: I18n
+ i18n: I18n,
+ dispatch: any,
): [HistogramData | null, TableDatum[]] {
// get min/max
const allIntervals = data.intervals;
@@ -134,19 +146,11 @@ export function prepareIntervalData(
return `${interval} ${total}: \u200e${percent.toFixed(1)}%`;
}
- function makeQuery(data: HistogramData, binIdx: number): string {
- const bin = data.bins[binIdx];
+ function onClick(bin: Bin): void {
const start = bin.x0!;
const end = bin.x1! - 1;
-
- if (start === end) {
- return `"prop:ivl=${start}"`;
- }
-
- const fromQuery = `"prop:ivl>=${start}"`;
- const tillQuery = `"prop:ivl<=${end}"`;
-
- return `${fromQuery} AND ${tillQuery}`;
+ const query = makeQuery(start, end);
+ dispatch("search", { query });
}
const meanInterval = Math.round(mean(allIntervals) ?? 0);
@@ -163,7 +167,7 @@ export function prepareIntervalData(
bins,
total: totalInPeriod,
hoverText,
- makeQuery,
+ onClick,
colourScale,
showArea: true,
},
|