mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Merge pull request #934 from hgiesel/graphprefs
Add GraphsPreferences API to graphs for setting persistent preferences
This commit is contained in:
commit
2a875ffc55
15 changed files with 231 additions and 57 deletions
|
@ -34,7 +34,7 @@ LABEL_REPEATED = 3
|
|||
|
||||
# messages we don't want to unroll in codegen
|
||||
SKIP_UNROLL_INPUT = {"TranslateString"}
|
||||
SKIP_DECODE = {"Graphs"}
|
||||
SKIP_DECODE = {"Graphs", "GetGraphPreferences"}
|
||||
|
||||
|
||||
def python_type(field):
|
||||
|
|
|
@ -18,6 +18,7 @@ import flask_cors # type: ignore
|
|||
from flask import Response, request
|
||||
from waitress.server import create_server
|
||||
|
||||
import anki.backend_pb2 as pb
|
||||
import aqt
|
||||
from anki import hooks
|
||||
from anki.rsbackend import from_json_bytes
|
||||
|
@ -255,17 +256,29 @@ def graph_data() -> bytes:
|
|||
return aqt.mw.col.backend.graphs(search=args["search"], days=args["days"])
|
||||
|
||||
|
||||
def graph_preferences() -> bytes:
|
||||
return aqt.mw.col.backend.get_graph_preferences()
|
||||
|
||||
|
||||
def set_graph_preferences() -> None:
|
||||
input = pb.GraphPreferences()
|
||||
input.ParseFromString(request.data)
|
||||
aqt.mw.col.backend.set_graph_preferences(input=input)
|
||||
|
||||
|
||||
def congrats_info() -> bytes:
|
||||
info = aqt.mw.col.backend.congrats_info()
|
||||
return info.SerializeToString()
|
||||
|
||||
|
||||
post_handlers = dict(
|
||||
graphData=graph_data,
|
||||
post_handlers = {
|
||||
"graphData": graph_data,
|
||||
"graphPreferences": graph_preferences,
|
||||
"setGraphPreferences": set_graph_preferences,
|
||||
# pylint: disable=unnecessary-lambda
|
||||
i18nResources=lambda: aqt.mw.col.backend.i18n_resources(),
|
||||
congratsInfo=congrats_info,
|
||||
)
|
||||
"i18nResources": lambda: aqt.mw.col.backend.i18n_resources(),
|
||||
"congratsInfo": congrats_info,
|
||||
}
|
||||
|
||||
|
||||
def handle_post(path: str) -> Response:
|
||||
|
@ -274,12 +287,15 @@ def handle_post(path: str) -> Response:
|
|||
return flask.make_response("Collection not open", HTTPStatus.NOT_FOUND)
|
||||
|
||||
if path in post_handlers:
|
||||
data = post_handlers[path]()
|
||||
response = flask.make_response(data)
|
||||
response.headers["Content-Type"] = "application/binary"
|
||||
return response
|
||||
if data := post_handlers[path]():
|
||||
response = flask.make_response(data)
|
||||
response.headers["Content-Type"] = "application/binary"
|
||||
else:
|
||||
response = flask.make_response("", HTTPStatus.NO_CONTENT)
|
||||
else:
|
||||
return flask.make_response(
|
||||
response = flask.make_response(
|
||||
f"Unhandled post to {path}",
|
||||
HTTPStatus.FORBIDDEN,
|
||||
)
|
||||
|
||||
return response
|
||||
|
|
|
@ -116,6 +116,8 @@ service BackendService {
|
|||
|
||||
rpc CardStats(CardID) returns (String);
|
||||
rpc Graphs(GraphsIn) returns (GraphsOut);
|
||||
rpc GetGraphPreferences(Empty) returns (GraphPreferences);
|
||||
rpc SetGraphPreferences(GraphPreferences) returns (Empty);
|
||||
|
||||
// media
|
||||
|
||||
|
@ -1082,12 +1084,6 @@ message GraphsIn {
|
|||
}
|
||||
|
||||
message GraphsOut {
|
||||
enum Weekday {
|
||||
SUNDAY = 0;
|
||||
MONDAY = 1;
|
||||
FRIDAY = 5;
|
||||
SATURDAY = 6;
|
||||
}
|
||||
repeated Card cards = 1;
|
||||
repeated RevlogEntry revlog = 2;
|
||||
uint32 days_elapsed = 3;
|
||||
|
@ -1096,7 +1092,17 @@ message GraphsOut {
|
|||
uint32 scheduler_version = 5;
|
||||
/// Seconds to add to UTC timestamps to get local time.
|
||||
int32 local_offset_secs = 7;
|
||||
Weekday first_weekday = 8;
|
||||
}
|
||||
|
||||
message GraphPreferences {
|
||||
enum Weekday {
|
||||
SUNDAY = 0;
|
||||
MONDAY = 1;
|
||||
FRIDAY = 5;
|
||||
SATURDAY = 6;
|
||||
}
|
||||
Weekday calendar_first_day_of_week = 1;
|
||||
bool card_counts_separate_inactive = 2;
|
||||
}
|
||||
|
||||
message RevlogEntry {
|
||||
|
|
|
@ -676,6 +676,15 @@ impl BackendService for Backend {
|
|||
self.with_col(|col| col.graph_data_for_search(&input.search, input.days))
|
||||
}
|
||||
|
||||
fn get_graph_preferences(&self, _input: pb::Empty) -> BackendResult<pb::GraphPreferences> {
|
||||
self.with_col(|col| col.get_graph_preferences())
|
||||
}
|
||||
|
||||
fn set_graph_preferences(&self, input: pb::GraphPreferences) -> BackendResult<Empty> {
|
||||
self.with_col(|col| col.set_graph_preferences(input))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
// decks
|
||||
//-----------------------------------------------
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@ pub(crate) enum ConfigKey {
|
|||
ShowRemainingDueCountsInStudy,
|
||||
ShowIntervalsAboveAnswerButtons,
|
||||
NewReviewMix,
|
||||
FirstWeekday,
|
||||
FirstDayOfWeek,
|
||||
CardCountsSeparateInactive,
|
||||
AnswerTimeLimitSecs,
|
||||
ShowDayLearningCardsFirst,
|
||||
LastUnburiedDay,
|
||||
|
@ -76,7 +77,8 @@ impl From<ConfigKey> for &'static str {
|
|||
ConfigKey::ShowRemainingDueCountsInStudy => "dueCounts",
|
||||
ConfigKey::ShowIntervalsAboveAnswerButtons => "estTimes",
|
||||
ConfigKey::NewReviewMix => "newSpread",
|
||||
ConfigKey::FirstWeekday => "firstWeekday",
|
||||
ConfigKey::FirstDayOfWeek => "firstDayOfWeek",
|
||||
ConfigKey::CardCountsSeparateInactive => "cardCountsSeparateInactive",
|
||||
ConfigKey::AnswerTimeLimitSecs => "timeLim",
|
||||
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
||||
ConfigKey::LastUnburiedDay => "lastUnburied",
|
||||
|
@ -229,11 +231,24 @@ impl Collection {
|
|||
self.set_config(ConfigKey::NewReviewMix, &(mix as u8))
|
||||
}
|
||||
|
||||
pub(crate) fn get_first_weekday(&self) -> Weekday {
|
||||
self.get_config_optional(ConfigKey::FirstWeekday)
|
||||
pub(crate) fn get_first_day_of_week(&self) -> Weekday {
|
||||
self.get_config_optional(ConfigKey::FirstDayOfWeek)
|
||||
.unwrap_or(Weekday::Sunday)
|
||||
}
|
||||
|
||||
pub(crate) fn set_first_day_of_week(&self, weekday: Weekday) -> Result<()> {
|
||||
self.set_config(ConfigKey::FirstDayOfWeek, &weekday)
|
||||
}
|
||||
|
||||
pub(crate) fn get_card_counts_separate_inactive(&self) -> bool {
|
||||
self.get_config_optional(ConfigKey::CardCountsSeparateInactive)
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
pub(crate) fn set_card_counts_separate_inactive(&self, separate: bool) -> Result<()> {
|
||||
self.set_config(ConfigKey::CardCountsSeparateInactive, &separate)
|
||||
}
|
||||
|
||||
pub(crate) fn get_show_due_counts(&self) -> bool {
|
||||
self.get_config_optional(ConfigKey::ShowRemainingDueCountsInStudy)
|
||||
.unwrap_or(true)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::{backend_proto as pb, prelude::*, revlog::RevlogEntry, search::SortMode};
|
||||
use crate::{
|
||||
backend_proto as pb, config::Weekday, prelude::*, revlog::RevlogEntry, search::SortMode,
|
||||
};
|
||||
|
||||
impl Collection {
|
||||
pub(crate) fn graph_data_for_search(
|
||||
|
@ -42,9 +44,26 @@ 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,
|
||||
first_weekday: self.get_first_weekday() as i32,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_graph_preferences(&self) -> Result<pb::GraphPreferences> {
|
||||
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(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn set_graph_preferences(&self, prefs: pb::GraphPreferences) -> Result<()> {
|
||||
self.set_first_day_of_week(match prefs.calendar_first_day_of_week {
|
||||
1 => Weekday::Monday,
|
||||
5 => Weekday::Friday,
|
||||
6 => Weekday::Saturday,
|
||||
_ => Weekday::Sunday,
|
||||
})?;
|
||||
self.set_card_counts_separate_inactive(prefs.card_counts_separate_inactive)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RevlogEntry> for pb::RevlogEntry {
|
||||
|
|
|
@ -71,6 +71,7 @@ ts_library(
|
|||
"@npm//d3-transition",
|
||||
"@npm//lodash.debounce",
|
||||
"@npm//lodash.throttle",
|
||||
"@npm//svelte",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -3,15 +3,18 @@
|
|||
import AxisTicks from "./AxisTicks.svelte";
|
||||
import { defaultGraphBounds, RevlogRange } from "./graph-helpers";
|
||||
import { gatherData, renderCalendar } from "./calendar";
|
||||
import type { PreferenceStore } from "./preferences";
|
||||
import type { GraphData } from "./calendar";
|
||||
import type pb from "anki/backend_proto";
|
||||
import type { I18n } from "anki/i18n";
|
||||
|
||||
export let sourceData: pb.BackendProto.GraphsOut | null = null;
|
||||
export let preferences: PreferenceStore | null = null;
|
||||
export let revlogRange: RevlogRange;
|
||||
export let i18n: I18n;
|
||||
export let nightMode: boolean;
|
||||
|
||||
let { calendarFirstDayOfWeek } = preferences;
|
||||
let graphData: GraphData | null = null;
|
||||
|
||||
let bounds = defaultGraphBounds();
|
||||
|
@ -25,7 +28,7 @@
|
|||
let targetYear = maxYear;
|
||||
|
||||
$: if (sourceData) {
|
||||
graphData = gatherData(sourceData);
|
||||
graphData = gatherData(sourceData, $calendarFirstDayOfWeek);
|
||||
}
|
||||
|
||||
$: {
|
||||
|
@ -49,7 +52,8 @@
|
|||
targetYear,
|
||||
i18n,
|
||||
nightMode,
|
||||
revlogRange
|
||||
revlogRange,
|
||||
calendarFirstDayOfWeek.set
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
import { defaultGraphBounds } from "./graph-helpers";
|
||||
import { gatherData, renderCards } from "./card-counts";
|
||||
import type { GraphData, TableDatum } from "./card-counts";
|
||||
import type { PreferenceStore } from "./preferences";
|
||||
import type pb from "anki/backend_proto";
|
||||
import type { I18n } from "anki/i18n";
|
||||
import SeparateInactiveCheckbox from "./SeparateInactiveCheckbox.svelte";
|
||||
|
||||
export let sourceData: pb.BackendProto.GraphsOut;
|
||||
export let i18n: I18n;
|
||||
export let preferences: PreferenceStore;
|
||||
|
||||
let separateInactive = true;
|
||||
let { cardCountsSeparateInactive } = preferences;
|
||||
let svg = null as HTMLElement | SVGElement | null;
|
||||
|
||||
let bounds = defaultGraphBounds();
|
||||
|
@ -20,10 +21,11 @@
|
|||
let tableData = (null as unknown) as TableDatum[];
|
||||
|
||||
$: {
|
||||
graphData = gatherData(sourceData, separateInactive, i18n);
|
||||
graphData = gatherData(sourceData, $cardCountsSeparateInactive, i18n);
|
||||
tableData = renderCards(svg as any, bounds, graphData);
|
||||
}
|
||||
|
||||
const label = i18n.tr(i18n.TR.STATISTICS_COUNTS_SEPARATE_SUSPENDED_BURIED_CARDS);
|
||||
const total = i18n.tr(i18n.TR.STATISTICS_COUNTS_TOTAL_CARDS);
|
||||
</script>
|
||||
|
||||
|
@ -56,7 +58,10 @@
|
|||
<h1>{graphData.title}</h1>
|
||||
|
||||
<div class="range-box-inner">
|
||||
<SeparateInactiveCheckbox bind:separateInactive {i18n} />
|
||||
<label>
|
||||
<input type="checkbox" bind:checked={$cardCountsSeparateInactive} />
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="counts-outer">
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
<script lang="typescript">
|
||||
import type { SvelteComponent } from "svelte/internal";
|
||||
import type { I18n } from "anki/i18n";
|
||||
import type { PreferenceStore } from "./preferences";
|
||||
import type pb from "anki/backend_proto";
|
||||
import { getGraphData, RevlogRange } from "./graph-helpers";
|
||||
import { getPreferences } from "./preferences";
|
||||
|
||||
export let i18n: I18n;
|
||||
export let nightMode: boolean;
|
||||
|
@ -17,12 +19,18 @@
|
|||
|
||||
let active = false;
|
||||
let sourceData: pb.BackendProto.GraphsOut | null = null;
|
||||
let preferences: PreferenceStore | null = null;
|
||||
let revlogRange: RevlogRange;
|
||||
|
||||
const preferencesPromise = getPreferences();
|
||||
|
||||
const refreshWith = async (search: string, days: number) => {
|
||||
active = true;
|
||||
try {
|
||||
sourceData = await getGraphData(search, days);
|
||||
[sourceData, preferences] = await Promise.all([
|
||||
getGraphData(search, days),
|
||||
preferencesPromise,
|
||||
]);
|
||||
revlogRange = days > 365 || days === 0 ? RevlogRange.All : RevlogRange.Year;
|
||||
} catch (e) {
|
||||
sourceData = null;
|
||||
|
@ -54,6 +62,7 @@
|
|||
<svelte:component
|
||||
this={graph}
|
||||
{sourceData}
|
||||
{preferences}
|
||||
{revlogRange}
|
||||
{i18n}
|
||||
{nightMode} />
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<script lang="typescript">
|
||||
import type { I18n } from "anki/i18n";
|
||||
|
||||
export let i18n: I18n;
|
||||
export let separateInactive: boolean = true;
|
||||
|
||||
const label = i18n.tr(i18n.TR.STATISTICS_COUNTS_SEPARATE_SUSPENDED_BURIED_CARDS);
|
||||
</script>
|
||||
|
||||
<label> <input type="checkbox" bind:checked={separateInactive} /> {label} </label>
|
|
@ -6,7 +6,7 @@
|
|||
@typescript-eslint/no-explicit-any: "off",
|
||||
*/
|
||||
|
||||
import type pb from "anki/backend_proto";
|
||||
import pb from "anki/backend_proto";
|
||||
import { interpolateBlues } from "d3-scale-chromatic";
|
||||
import "d3-transition";
|
||||
import { select, mouse } from "d3-selection";
|
||||
|
@ -41,7 +41,13 @@ interface DayDatum {
|
|||
date: Date;
|
||||
}
|
||||
|
||||
export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
|
||||
type WeekdayType = pb.BackendProto.GraphPreferences.Weekday;
|
||||
const Weekday = pb.BackendProto.GraphPreferences.Weekday; /* enum */
|
||||
|
||||
export function gatherData(
|
||||
data: pb.BackendProto.GraphsOut,
|
||||
firstDayOfWeek: WeekdayType
|
||||
): GraphData {
|
||||
const reviewCount = new Map<number, number>();
|
||||
|
||||
for (const review of data.revlog as pb.BackendProto.RevlogEntry[]) {
|
||||
|
@ -56,17 +62,17 @@ export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
|
|||
}
|
||||
|
||||
const timeFunction =
|
||||
data.firstWeekday === 1
|
||||
firstDayOfWeek === Weekday.MONDAY
|
||||
? timeMonday
|
||||
: data.firstWeekday === 5
|
||||
: firstDayOfWeek === Weekday.FRIDAY
|
||||
? timeFriday
|
||||
: data.firstWeekday === 6
|
||||
: firstDayOfWeek === Weekday.SATURDAY
|
||||
? timeSaturday
|
||||
: timeSunday;
|
||||
|
||||
const weekdayLabels: number[] = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
weekdayLabels.push((data.firstWeekday + i) % 7);
|
||||
weekdayLabels.push((firstDayOfWeek + i) % 7);
|
||||
}
|
||||
|
||||
return { reviewCount, timeFunction, weekdayLabels };
|
||||
|
@ -79,7 +85,8 @@ export function renderCalendar(
|
|||
targetYear: number,
|
||||
i18n: I18n,
|
||||
nightMode: boolean,
|
||||
revlogRange: RevlogRange
|
||||
revlogRange: RevlogRange,
|
||||
setFirstDayOfWeek: (d: number) => void
|
||||
): void {
|
||||
const svg = select(svgElem);
|
||||
const now = new Date();
|
||||
|
@ -170,11 +177,19 @@ export function renderCalendar(
|
|||
.attr("height", height - 2)
|
||||
.attr("x", x(1)! - 3)
|
||||
.attr("y", (_d, index) => bounds.marginTop + index * height)
|
||||
.attr("fill", nightMode ? "#ddd" : "black")
|
||||
.attr("dominant-baseline", "hanging")
|
||||
.attr("text-anchor", "end")
|
||||
.attr("font-size", "small")
|
||||
.attr("font-family", "monospace")
|
||||
.style("user-select", "none");
|
||||
.style("user-select", "none")
|
||||
.on("click", null)
|
||||
.filter((d: number) =>
|
||||
[Weekday.SUNDAY, Weekday.MONDAY, Weekday.FRIDAY, Weekday.SATURDAY].includes(
|
||||
d
|
||||
)
|
||||
)
|
||||
.on("click", setFirstDayOfWeek);
|
||||
|
||||
svg.select("g.days")
|
||||
.selectAll("rect")
|
||||
|
@ -192,11 +207,5 @@ export function renderCalendar(
|
|||
.on("mouseout", hideTooltip)
|
||||
.transition()
|
||||
.duration(800)
|
||||
.attr("fill", (d) => {
|
||||
if (d.count === 0) {
|
||||
return emptyColour;
|
||||
} else {
|
||||
return blues(d.count)!;
|
||||
}
|
||||
});
|
||||
.attr("fill", (d) => (d.count === 0 ? emptyColour : blues(d.count)!));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import pb from "anki/backend_proto";
|
||||
import type { Selection } from "d3-selection";
|
||||
import type { PreferencePayload } from "./preferences";
|
||||
import { postRequest } from "anki/postrequest";
|
||||
|
||||
export async function getGraphData(
|
||||
|
@ -19,6 +20,21 @@ export async function getGraphData(
|
|||
);
|
||||
}
|
||||
|
||||
export async function getGraphPreferences(): Promise<pb.BackendProto.GraphPreferences> {
|
||||
return pb.BackendProto.GraphPreferences.decode(
|
||||
await postRequest("/_anki/graphPreferences", JSON.stringify({}))
|
||||
);
|
||||
}
|
||||
|
||||
export async function setGraphPreferences(prefs: PreferencePayload): Promise<void> {
|
||||
return (async (): Promise<void> => {
|
||||
await postRequest(
|
||||
"/_anki/setGraphPreferences",
|
||||
pb.BackendProto.GraphPreferences.encode(prefs).finish()
|
||||
);
|
||||
})();
|
||||
}
|
||||
|
||||
// amount of data to fetch from backend
|
||||
export enum RevlogRange {
|
||||
Year = 1,
|
||||
|
|
75
ts/graphs/preferences.ts
Normal file
75
ts/graphs/preferences.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import pb from "anki/backend_proto";
|
||||
import { getGraphPreferences, setGraphPreferences } from "./graph-helpers";
|
||||
import { Writable, writable, get } from "svelte/store";
|
||||
|
||||
export interface CustomStore<T> extends Writable<T> {
|
||||
subscribe: (getter: (value: T) => void) => () => void;
|
||||
set: (value: T) => void;
|
||||
}
|
||||
|
||||
export type PreferenceStore = {
|
||||
[K in keyof Omit<pb.BackendProto.GraphPreferences, "toJSON">]: CustomStore<
|
||||
pb.BackendProto.GraphPreferences[K]
|
||||
>;
|
||||
};
|
||||
|
||||
export type PreferencePayload = {
|
||||
[K in keyof Omit<
|
||||
pb.BackendProto.GraphPreferences,
|
||||
"toJSON"
|
||||
>]: pb.BackendProto.GraphPreferences[K];
|
||||
};
|
||||
|
||||
function createPreference<T>(
|
||||
initialValue: T,
|
||||
savePreferences: () => void
|
||||
): CustomStore<T> {
|
||||
const { subscribe, set, update } = writable(initialValue);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set: (value: T): void => {
|
||||
set(value);
|
||||
savePreferences();
|
||||
},
|
||||
update: (updater: (value: T) => T): void => {
|
||||
update(updater);
|
||||
savePreferences();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function preparePreferences(
|
||||
GraphPreferences: pb.BackendProto.GraphPreferences
|
||||
): PreferenceStore {
|
||||
const preferences: Partial<PreferenceStore> = {};
|
||||
|
||||
function constructPreferences(): PreferencePayload {
|
||||
const payload: Partial<PreferencePayload> = {};
|
||||
|
||||
for (const key in preferences as PreferenceStore) {
|
||||
payload[key] = get(preferences[key]);
|
||||
}
|
||||
|
||||
return payload as PreferencePayload;
|
||||
}
|
||||
|
||||
function savePreferences(): void {
|
||||
setGraphPreferences(constructPreferences());
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(
|
||||
pb.BackendProto.GraphPreferences.toObject(GraphPreferences, {
|
||||
defaults: true,
|
||||
})
|
||||
)) {
|
||||
preferences[key] = createPreference(value, savePreferences);
|
||||
}
|
||||
|
||||
return preferences as PreferenceStore;
|
||||
}
|
||||
|
||||
export async function getPreferences(): Promise<PreferenceStore> {
|
||||
const initialPreferences = await getGraphPreferences();
|
||||
return preparePreferences(initialPreferences);
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "es6",
|
||||
"lib": ["es2016", "es2019.array", "dom", "dom.iterable"],
|
||||
"lib": ["es2017", "es2019.array", "dom", "dom.iterable"],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"anki/*": ["../bazel-bin/ts/lib/*"]
|
||||
|
|
Loading…
Reference in a new issue