f3b6deefe9
Easier to import from, and allows us to declare the output of the build action without having to iterate over all the proto filenames. Have confirmed it doesn't break esbuild's tree shaking.
172 lines
5.8 KiB
Svelte
172 lines
5.8 KiB
Svelte
<!--
|
|
Copyright: Ankitects Pty Ltd and contributors
|
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
-->
|
|
<script lang="ts">
|
|
import type { DeckNameId } from "@tslib/anki/decks_pb";
|
|
import type { StringList } from "@tslib/anki/generic_pb";
|
|
import type {
|
|
CsvMetadata_Delimiter,
|
|
CsvMetadata_DupeResolution,
|
|
CsvMetadata_MappedNotetype,
|
|
CsvMetadata_MatchScope,
|
|
} from "@tslib/anki/import_export_pb";
|
|
import type { NotetypeNameId } from "@tslib/anki/notetypes_pb";
|
|
import { getCsvMetadata, importCsv } from "@tslib/backend";
|
|
import * as tr from "@tslib/ftl";
|
|
|
|
import Col from "../components/Col.svelte";
|
|
import Container from "../components/Container.svelte";
|
|
import Row from "../components/Row.svelte";
|
|
import Spacer from "../components/Spacer.svelte";
|
|
import DeckDupeCheckSwitch from "./DeckDupeCheckSwitch.svelte";
|
|
import DeckSelector from "./DeckSelector.svelte";
|
|
import DelimiterSelector from "./DelimiterSelector.svelte";
|
|
import DupeResolutionSelector from "./DupeResolutionSelector.svelte";
|
|
import FieldMapper from "./FieldMapper.svelte";
|
|
import Header from "./Header.svelte";
|
|
import HtmlSwitch from "./HtmlSwitch.svelte";
|
|
import {
|
|
buildDeckOneof,
|
|
buildNotetypeOneof,
|
|
getColumnOptions,
|
|
tryGetDeckId,
|
|
tryGetGlobalNotetype,
|
|
} from "./lib";
|
|
import NotetypeSelector from "./NotetypeSelector.svelte";
|
|
import Preview from "./Preview.svelte";
|
|
import StickyHeader from "./StickyHeader.svelte";
|
|
import Tags from "./Tags.svelte";
|
|
|
|
export let path: string;
|
|
export let notetypeNameIds: NotetypeNameId[];
|
|
export let deckNameIds: DeckNameId[];
|
|
export let dupeResolution: CsvMetadata_DupeResolution;
|
|
export let matchScope: CsvMetadata_MatchScope;
|
|
export let delimiter: CsvMetadata_Delimiter;
|
|
export let forceDelimiter: boolean;
|
|
export let forceIsHtml: boolean;
|
|
export let isHtml: boolean;
|
|
export let globalTags: string[];
|
|
export let updatedTags: string[];
|
|
export let columnLabels: string[];
|
|
export let tagsColumn: number;
|
|
export let guidColumn: number;
|
|
export let preview: StringList[];
|
|
// Protobuf oneofs. Exactly one of these pairs is expected to be set.
|
|
export let notetypeColumn: number | null;
|
|
export let globalNotetype: CsvMetadata_MappedNotetype | null;
|
|
export let deckId: bigint | null;
|
|
export let deckColumn: number | null;
|
|
|
|
let lastNotetypeId = globalNotetype?.id;
|
|
let lastDelimeter = delimiter;
|
|
|
|
$: columnOptions = getColumnOptions(
|
|
columnLabels,
|
|
preview[0].vals,
|
|
notetypeColumn,
|
|
deckColumn,
|
|
guidColumn,
|
|
);
|
|
$: getCsvMetadata({
|
|
path,
|
|
delimiter,
|
|
notetypeId: undefined,
|
|
deckId: undefined,
|
|
isHtml,
|
|
}).then((meta) => {
|
|
columnLabels = meta.columnLabels;
|
|
preview = meta.preview;
|
|
});
|
|
$: if (globalNotetype?.id !== lastNotetypeId || delimiter !== lastDelimeter) {
|
|
lastNotetypeId = globalNotetype?.id;
|
|
lastDelimeter = delimiter;
|
|
getCsvMetadata({
|
|
path,
|
|
delimiter,
|
|
notetypeId: globalNotetype?.id,
|
|
deckId: deckId ?? undefined,
|
|
}).then((meta) => {
|
|
globalNotetype = tryGetGlobalNotetype(meta);
|
|
deckId = tryGetDeckId(meta);
|
|
tagsColumn = meta.tagsColumn;
|
|
});
|
|
}
|
|
|
|
async function onImport(): Promise<void> {
|
|
await importCsv({
|
|
path,
|
|
metadata: {
|
|
dupeResolution,
|
|
matchScope,
|
|
delimiter,
|
|
forceDelimiter,
|
|
isHtml,
|
|
forceIsHtml,
|
|
globalTags,
|
|
updatedTags,
|
|
columnLabels,
|
|
tagsColumn,
|
|
guidColumn,
|
|
deck: buildDeckOneof(deckColumn, deckId),
|
|
notetype: buildNotetypeOneof(globalNotetype, notetypeColumn),
|
|
preview: [],
|
|
},
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<StickyHeader {path} {onImport} />
|
|
|
|
<Container class="csv-page">
|
|
<Row --cols={2}>
|
|
<Col --col-size={1} breakpoint="md">
|
|
<Container>
|
|
<Header heading={tr.importingFile()} />
|
|
<Spacer --height="1.5rem" />
|
|
<DelimiterSelector bind:delimiter disabled={forceDelimiter} />
|
|
<HtmlSwitch bind:isHtml disabled={forceIsHtml} />
|
|
<Preview {columnOptions} {preview} />
|
|
</Container>
|
|
</Col>
|
|
<Col --col-size={1} breakpoint="md">
|
|
<Container>
|
|
<Header heading={tr.importingImportOptions()} />
|
|
<Spacer --height="1.5rem" />
|
|
{#if globalNotetype}
|
|
<NotetypeSelector
|
|
{notetypeNameIds}
|
|
bind:notetypeId={globalNotetype.id}
|
|
/>
|
|
{/if}
|
|
{#if deckId}
|
|
<DeckSelector {deckNameIds} bind:deckId />
|
|
{/if}
|
|
<DupeResolutionSelector bind:dupeResolution />
|
|
<DeckDupeCheckSwitch bind:matchScope />
|
|
<Tags bind:globalTags bind:updatedTags />
|
|
</Container>
|
|
</Col>
|
|
<Col --col-size={1} breakpoint="md">
|
|
<Container>
|
|
<Header heading={tr.importingFieldMapping()} />
|
|
<Spacer --height="1.5rem" />
|
|
<FieldMapper {columnOptions} bind:globalNotetype bind:tagsColumn />
|
|
</Container>
|
|
</Col>
|
|
</Row>
|
|
</Container>
|
|
|
|
<style lang="scss">
|
|
:global(.csv-page) {
|
|
--gutter-inline: 0.25rem;
|
|
|
|
:global(.row) {
|
|
// rows have negative margins by default
|
|
--bs-gutter-x: 0;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
}
|
|
</style>
|