anki/ts/deck-options/ConfigSelector.svelte

117 lines
3.5 KiB
Svelte
Raw Normal View History

<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
Move away from Bazel (#2202) (for upgrading users, please see the notes at the bottom) Bazel brought a lot of nice things to the table, such as rebuilds based on content changes instead of modification times, caching of build products, detection of incorrect build rules via a sandbox, and so on. Rewriting the build in Bazel was also an opportunity to improve on the Makefile-based build we had prior, which was pretty poor: most dependencies were external or not pinned, and the build graph was poorly defined and mostly serialized. It was not uncommon for fresh checkouts to fail due to floating dependencies, or for things to break when trying to switch to an older commit. For day-to-day development, I think Bazel served us reasonably well - we could generally switch between branches while being confident that builds would be correct and reasonably fast, and not require full rebuilds (except on Windows, where the lack of a sandbox and the TS rules would cause build breakages when TS files were renamed/removed). Bazel achieves that reliability by defining rules for each programming language that define how source files should be turned into outputs. For the rules to work with Bazel's sandboxing approach, they often have to reimplement or partially bypass the standard tools that each programming language provides. The Rust rules call Rust's compiler directly for example, instead of using Cargo, and the Python rules extract each PyPi package into a separate folder that gets added to sys.path. These separate language rules allow proper declaration of inputs and outputs, and offer some advantages such as caching of build products and fine-grained dependency installation. But they also bring some downsides: - The rules don't always support use-cases/platforms that the standard language tools do, meaning they need to be patched to be used. I've had to contribute a number of patches to the Rust, Python and JS rules to unblock various issues. - The dependencies we use with each language sometimes make assumptions that do not hold in Bazel, meaning they either need to be pinned or patched, or the language rules need to be adjusted to accommodate them. I was hopeful that after the initial setup work, things would be relatively smooth-sailing. Unfortunately, that has not proved to be the case. Things frequently broke when dependencies or the language rules were updated, and I began to get frustrated at the amount of Anki development time I was instead spending on build system upkeep. It's now about 2 years since switching to Bazel, and I think it's time to cut losses, and switch to something else that's a better fit. The new build system is based on a small build tool called Ninja, and some custom Rust code in build/. This means that to build Anki, Bazel is no longer required, but Ninja and Rust need to be installed on your system. Python and Node toolchains are automatically downloaded like in Bazel. This new build system should result in faster builds in some cases: - Because we're using cargo to build now, Rust builds are able to take advantage of pipelining and incremental debug builds, which we didn't have with Bazel. It's also easier to override the default linker on Linux/macOS, which can further improve speeds. - External Rust crates are now built with opt=1, which improves performance of debug builds. - Esbuild is now used to transpile TypeScript, instead of invoking the TypeScript compiler. This results in faster builds, by deferring typechecking to test/check time, and by allowing more work to happen in parallel. As an example of the differences, when testing with the mold linker on Linux, adding a new message to tags.proto (which triggers a recompile of the bulk of the Rust and TypeScript code) results in a compile that goes from about 22s on Bazel to about 7s in the new system. With the standard linker, it's about 9s. Some other changes of note: - Our Rust workspace now uses cargo-hakari to ensure all packages agree on available features, preventing unnecessary rebuilds. - pylib/anki is now a PEP420 implicit namespace, avoiding the need to merge source files and generated files into a single folder for running. By telling VSCode about the extra search path, code completion now works with generated files without needing to symlink them into the source folder. - qt/aqt can't use PEP420 as it's difficult to get rid of aqt/__init__.py. Instead, the generated files are now placed in a separate _aqt package that's added to the path. - ts/lib is now exposed as @tslib, so the source code and generated code can be provided under the same namespace without a merging step. - MyPy and PyLint are now invoked once for the entire codebase. - dprint will be used to format TypeScript/json files in the future instead of the slower prettier (currently turned off to avoid causing conflicts). It can automatically defer to prettier when formatting Svelte files. - svelte-check is now used for typechecking our Svelte code, which revealed a few typing issues that went undetected with the old system. - The Jest unit tests now work on Windows as well. If you're upgrading from Bazel, updated usage instructions are in docs/development.md and docs/build.md. A summary of the changes: - please remove node_modules and .bazel - install rustup (https://rustup.rs/) - install rsync if not already installed (on windows, use pacman - see docs/windows.md) - install Ninja (unzip from https://github.com/ninja-build/ninja/releases/tag/v1.11.1 and place on your path, or from your distro/homebrew if it's 1.10+) - update .vscode/settings.json from .vscode.dist
2022-11-27 06:24:20 +01:00
import * as tr from "@tslib/ftl";
import { noop } from "@tslib/functional";
2021-05-25 19:18:25 +02:00
import type Modal from "bootstrap/js/dist/modal";
import { createEventDispatcher, getContext } from "svelte";
2022-11-28 00:17:39 +01:00
import ButtonToolbar from "../components/ButtonToolbar.svelte";
import { modalsKey } from "../components/context-keys";
import Select from "../components/Select.svelte";
import StickyContainer from "../components/StickyContainer.svelte";
import type { ConfigListEntry, DeckOptionsState } from "./lib";
2021-05-18 18:55:22 +02:00
import SaveButton from "./SaveButton.svelte";
import TextInputModal from "./TextInputModal.svelte";
2021-04-25 10:40:02 +02:00
export let state: DeckOptionsState;
const configList = state.configList;
const dispatch = createEventDispatcher();
const dispatchPresetChange = () => dispatch("presetchange");
$: value = $configList.findIndex((entry) => entry.current);
$: label = configLabel($configList[value]);
function configLabel(entry: ConfigListEntry): string {
const count = tr.deckConfigUsedByDecks({ decks: entry.useCount });
return `${entry.name} (${count})`;
}
function blur(e: CustomEvent): void {
state.setCurrentIndex(e.detail.value);
dispatchPresetChange();
}
function onAddConfig(text: string): void {
const trimmed = text.trim();
if (trimmed.length) {
state.addConfig(trimmed);
dispatchPresetChange();
}
}
2021-05-26 05:20:24 +02:00
function onCloneConfig(text: string): void {
const trimmed = text.trim();
if (trimmed.length) {
state.cloneConfig(trimmed);
dispatchPresetChange();
2021-05-26 05:20:24 +02:00
}
}
function onRenameConfig(text: string): void {
state.setCurrentName(text);
}
2021-05-25 19:18:25 +02:00
const modals = getContext<Map<string, Modal>>(modalsKey);
2021-05-26 05:20:24 +02:00
let modalKey: string;
let modalStartingValue = "";
let modalTitle = "";
let modalSuccess: (text: string) => void = noop;
2021-05-25 19:18:25 +02:00
2021-05-26 05:20:24 +02:00
function promptToAdd() {
modalTitle = tr.deckConfigAddGroup();
2021-05-26 05:20:24 +02:00
modalSuccess = onAddConfig;
modalStartingValue = "";
modals.get(modalKey)!.show();
2021-05-25 19:18:25 +02:00
}
2021-05-26 05:20:24 +02:00
function promptToClone() {
modalTitle = tr.deckConfigCloneGroup();
2021-05-26 05:20:24 +02:00
modalSuccess = onCloneConfig;
modalStartingValue = state.getCurrentName();
modals.get(modalKey)!.show();
}
function promptToRename() {
modalTitle = tr.deckConfigRenameGroup();
2021-05-26 05:20:24 +02:00
modalSuccess = onRenameConfig;
modalStartingValue = state.getCurrentName();
modals.get(modalKey)!.show();
2021-05-25 19:18:25 +02:00
}
</script>
<TextInputModal
2021-05-26 05:20:24 +02:00
title={modalTitle}
prompt={tr.deckConfigNamePrompt()}
initialValue={modalStartingValue}
2021-05-26 05:20:24 +02:00
onOk={modalSuccess}
bind:modalKey
/>
<StickyContainer --gutter-block="0.5rem" --sticky-borders="0 0 1px" breakpoint="sm">
<ButtonToolbar class="justify-content-between flex-grow-1" wrap={false}>
Improve keyboard handling and accessibility for Select.svelte and refactor (#2811) * resolve TagAddButton a11y better comments to document tagindex reasoning * resolved a11y for TagsSelectedButton allow focus to TagsSelectedButton with Shift+Tab and Enter or Space to show popover * safely ignore a11y warning as container for interactables is not itself interactable * Update CONTRIBUTORS * quick fix syntax * quick fix syntax * quick fix syntax * quick fix syntax * resolved a11y in accordance with ARIA APG Disclure pattern * resolved a11y ideally should replace with with a11y-click-events-have-key-events is explicitly ignored as the alternative (adding ) seems more clunky * resolved SpinBox a11y cannot focus on these buttons, so no key event handling needed (keyboard editting already possible by just typing in the field) widget already properly follows ARIA APG Spinbutton pattern * cleanup * onEnterOrSpace() function implemented as discussed in #2787 and #2564 * I think this is the main keyboard handling of Select Still need to fix focus and handle roles and attributes * fixed the keyboard interaction focus is janky because you need to wait until after the listed options load and for some reason that needs a tiny delay on onMount I think this technically violates a11y, but it really doesn't since the delay is literally zero. But the code still needs it to happen. * Select and SelectOption reference the same focus function * SelectOption moved inside Select + started roles and a11y * quick syntax and such changes * finish handling roles and attributes * fixed keyboard handling and only visual focus * cleanup and slight refactoring * fixed syntax * what even is this? * bug fixes + revert key selection * fixed scrolling * better control scrolling and focus * Adjusted selection Up/Down Arrows: start selection on active option Enter/Space/Click: no initial selection, down arrow to first option, up arrow to last option * Only set selected the first time Select is opened, all subsequent times use the previous selected
2023-11-21 05:23:18 +01:00
<Select
class="flex-grow-1"
bind:value
{label}
list={$configList}
parser={(entry) => ({
content: configLabel(entry),
value: entry.idx,
})}
on:change={blur}
/>
Improved add-on extension API (#1626) * Add componentHook functionality * Register package NoteEditor * Rename OldEditorAdapter to NoteEditor * Expose instances in component-hook as well * Rename NoteTypeButtons to NotetypeButtons * Move PreviewButton initialization to BrowserEditor.svelte * Remove focusInRichText - Same thing can be done by inspecting activeInput * Satisfy formatter * Fix remaining rebase issues * Add .bazel to .prettierignore * Rename currentField and activeInput to focused{Field,Input} * Move identifier to lib and registration to sveltelib * Fix Dynamic component insertion * Simplify editingInputIsRichText * Give extra warning in svelte/svelte.ts - This was caused by doing a rename of a files, that only differed in case: NoteTypeButtons.svelte to NotetypeButtons.svelte - It was quite tough to figure out, and this console.log might make it easier if it ever happens again * Change signature of contextProperty * Add ts/typings for add-on definition files * Add Anki types in typings/common/index.d.ts * Export without .svelte suffix It conflicts with how Svelte types its packages * Fix left over .svelte import from editor.py * Rename NoteTypeButtons to unrelated to ensure case-only rename * Rename back to NotetypeButtons.svelte * Remove unused component-hook.ts, Fix typing in lifecycle-hooks * Merge runtime-require and register-package into one file + Give some preliminary types to require * Rename uiDidLoad to loaded * Fix eslint / svelte-check * Rename context imports to noteEditorContext * Fix import name mismatch - I wonder why these issues are not caught by svelte-check? * Rename two missed usages of uiDidLoad * Fix ButtonDropdown from having wrong border-radius * Uniformly rename libraries to packages - I don't have a strong opinion on whether to name them libraries or packages, I just think we should have a uniform name. - JS/TS only uses the terms "module" and "namespace", however `package` is a reserved keyword for future use, whereas `library` is not. * Refactor registration.ts into dynamic-slotting - This is part of an effort to refactor the dynamic slotting (extending buttons) functionality out of components like ButtonGroup. * Remove dynamically-slottable logic from ButtonToolbar * Use DynamicallySlottable in editor-toolbar * Fix no border radius on indentation button dropdown * Fix AddonButtons * Remove Item/ButtonGroupItem in deck-options, where it's not necessary * Remove unnecessary uses of Item and ButtonGroupItem * Fix remaining tests * Fix relative imports * Revert change return value of remapBinToSrcDir to ./bazel/out... * Remove typings directory * Adjust comments for dynamic-slottings
2022-02-03 05:52:11 +01:00
<SaveButton
{state}
on:add={promptToAdd}
on:clone={promptToClone}
on:rename={promptToRename}
on:remove={dispatchPresetChange}
Improved add-on extension API (#1626) * Add componentHook functionality * Register package NoteEditor * Rename OldEditorAdapter to NoteEditor * Expose instances in component-hook as well * Rename NoteTypeButtons to NotetypeButtons * Move PreviewButton initialization to BrowserEditor.svelte * Remove focusInRichText - Same thing can be done by inspecting activeInput * Satisfy formatter * Fix remaining rebase issues * Add .bazel to .prettierignore * Rename currentField and activeInput to focused{Field,Input} * Move identifier to lib and registration to sveltelib * Fix Dynamic component insertion * Simplify editingInputIsRichText * Give extra warning in svelte/svelte.ts - This was caused by doing a rename of a files, that only differed in case: NoteTypeButtons.svelte to NotetypeButtons.svelte - It was quite tough to figure out, and this console.log might make it easier if it ever happens again * Change signature of contextProperty * Add ts/typings for add-on definition files * Add Anki types in typings/common/index.d.ts * Export without .svelte suffix It conflicts with how Svelte types its packages * Fix left over .svelte import from editor.py * Rename NoteTypeButtons to unrelated to ensure case-only rename * Rename back to NotetypeButtons.svelte * Remove unused component-hook.ts, Fix typing in lifecycle-hooks * Merge runtime-require and register-package into one file + Give some preliminary types to require * Rename uiDidLoad to loaded * Fix eslint / svelte-check * Rename context imports to noteEditorContext * Fix import name mismatch - I wonder why these issues are not caught by svelte-check? * Rename two missed usages of uiDidLoad * Fix ButtonDropdown from having wrong border-radius * Uniformly rename libraries to packages - I don't have a strong opinion on whether to name them libraries or packages, I just think we should have a uniform name. - JS/TS only uses the terms "module" and "namespace", however `package` is a reserved keyword for future use, whereas `library` is not. * Refactor registration.ts into dynamic-slotting - This is part of an effort to refactor the dynamic slotting (extending buttons) functionality out of components like ButtonGroup. * Remove dynamically-slottable logic from ButtonToolbar * Use DynamicallySlottable in editor-toolbar * Fix no border radius on indentation button dropdown * Fix AddonButtons * Remove Item/ButtonGroupItem in deck-options, where it's not necessary * Remove unnecessary uses of Item and ButtonGroupItem * Fix remaining tests * Fix relative imports * Revert change return value of remapBinToSrcDir to ./bazel/out... * Remove typings directory * Adjust comments for dynamic-slottings
2022-02-03 05:52:11 +01:00
/>
</ButtonToolbar>
</StickyContainer>