From b6150c79645ac6b7cc2935fb173d3063a3fd78f5 Mon Sep 17 00:00:00 2001 From: Arild Matsson Date: Wed, 15 Nov 2023 19:47:15 +0100 Subject: [PATCH 1/6] Set lang param of Korp/Strix urls --- CHANGELOG.md | 4 ++++ src/corpus/exports/Exports.vue | 6 ++++-- src/i18n/locale.composable.js | 8 +++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f16df0..88fe5d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ As this project is a user-facing application, the places in the semantic version ## [Unreleased] +### Fixed + +- Set `lang` param of Korp/Strix urls + ## [1.0.4] (2023-10-24) ### Fixed diff --git a/src/corpus/exports/Exports.vue b/src/corpus/exports/Exports.vue index f00deb8..7f4e252 100644 --- a/src/corpus/exports/Exports.vue +++ b/src/corpus/exports/Exports.vue @@ -16,7 +16,7 @@ :link-text="$t('exports.tools.help.korp.manual.text')" :can-install="canInstall" :is-installed="korpStatus.isDone" - :show-url="`${korpUrl}?mode=mink#?corpus=${corpusId}`" + :show-url="`${korpUrl}?mode=mink#?corpus=${corpusId}&lang=${locale3}`" @install="korpInstall()" /> @@ -25,7 +25,7 @@ :info="$t('exports.tools.help.strix')" :can-install="canInstall" :is-installed="strixStatus.isDone" - :show-url="`${strixUrl}?filters=corpus_id:${corpusId}&modeSelected=mink`" + :show-url="`${strixUrl}?modeSelected=mink&filters=corpus_id:${corpusId}&lang=${locale3}`" @install="strixInstall()" /> @@ -67,6 +67,7 @@ import { useCorpusState } from "@/corpus/corpusState.composable"; import useJob from "@/corpus/job/job.composable"; import PendingContent from "@/spin/PendingContent.vue"; import ToolPanel from "./ToolPanel.vue"; +import useLocale from "@/i18n/locale.composable"; const corpusId = useCorpusIdParam(); const { exports, loadExports, downloadResult, getDownloadFilename } = @@ -74,6 +75,7 @@ const { exports, loadExports, downloadResult, getDownloadFilename } = const { isDone } = useCorpusState(corpusId); const { installKorp, installStrix, sparvStatus, korpStatus, strixStatus } = useJob(corpusId); +const { locale3 } = useLocale(); const korpUrl = ensureTrailingSlash(import.meta.env.VITE_KORP_URL); const strixUrl = ensureTrailingSlash(import.meta.env.VITE_STRIX_URL); diff --git a/src/i18n/locale.composable.js b/src/i18n/locale.composable.js index 9b3e92e..477615c 100644 --- a/src/i18n/locale.composable.js +++ b/src/i18n/locale.composable.js @@ -1,4 +1,4 @@ -import { inject, watch } from "vue"; +import { computed, inject, watch } from "vue"; import { useI18n } from "vue-i18n"; import { useStorage } from "@vueuse/core"; import { filesize } from "filesize"; @@ -14,6 +14,11 @@ export default function useLocale() { document.querySelector("html")?.setAttribute("lang", locale.value); }; + // The ISO 639-3 code is used in many parts of the Språkbanken infrastructure. + const locale3 = computed( + () => console.log(locale.value) || (locale.value == "en" ? "eng" : "swe") + ); + // Sync from storage once, if present if (storedLocale.value) { locale.value = storedLocale.value; @@ -50,6 +55,7 @@ export default function useLocale() { return { locale, + locale3, th, filesize: myFilesize, }; From e87e1f2047567957affa1049c5f5e785d79e7d15 Mon Sep 17 00:00:00 2001 From: Arild Matsson Date: Wed, 15 Nov 2023 20:08:04 +0100 Subject: [PATCH 2/6] Remove stray console.log --- src/i18n/locale.composable.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/i18n/locale.composable.js b/src/i18n/locale.composable.js index 477615c..70d450e 100644 --- a/src/i18n/locale.composable.js +++ b/src/i18n/locale.composable.js @@ -15,9 +15,7 @@ export default function useLocale() { }; // The ISO 639-3 code is used in many parts of the Språkbanken infrastructure. - const locale3 = computed( - () => console.log(locale.value) || (locale.value == "en" ? "eng" : "swe") - ); + const locale3 = computed(() => (locale.value == "en" ? "eng" : "swe")); // Sync from storage once, if present if (storedLocale.value) { From 090a8c899ea87068a1b04d4ffbf655938f8c782f Mon Sep 17 00:00:00 2001 From: Arild Matsson Date: Fri, 17 Nov 2023 09:42:10 +0100 Subject: [PATCH 3/6] Set new corpus name to id --- CHANGELOG.md | 4 ++++ src/corpus/createCorpus.composable.js | 8 ++++++-- walrus | 0 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 walrus diff --git a/CHANGELOG.md b/CHANGELOG.md index 88fe5d6..95c385d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ As this project is a user-facing application, the places in the semantic version ## [Unreleased] +### Changed + +- A corpus created by upload (not through the creation form) now gets its name set to the id, instead of remaining empty + ### Fixed - Set `lang` param of Korp/Strix urls diff --git a/src/corpus/createCorpus.composable.js b/src/corpus/createCorpus.composable.js index e1d7f20..5970978 100644 --- a/src/corpus/createCorpus.composable.js +++ b/src/corpus/createCorpus.composable.js @@ -1,7 +1,6 @@ import { useRouter } from "vue-router"; import { useAuth } from "@/auth/auth.composable"; import useMinkBackend from "@/api/backend.composable"; -import { emptyConfig } from "@/api/corpusConfig"; import { useCorpusStore } from "@/store/corpus.store"; import useMessenger from "@/message/messenger.composable"; import useConfig from "./config/config.composable"; @@ -31,9 +30,14 @@ export default function useCreateCorpus() { const corpusId = await createCorpus().catch(alertError); if (!corpusId) return; + // Create a minimal config. + const config = { + name: { swe: corpusId, eng: corpusId }, + }; + const results = await Promise.allSettled([ uploadSources(files, corpusId), - uploadConfig(emptyConfig(), corpusId), + uploadConfig(config, corpusId), ]); const rejectedResults = results.filter( diff --git a/walrus b/walrus new file mode 100644 index 0000000..e69de29 From 3ea2beadf3ed69425d52a17b050113fffc924f70 Mon Sep 17 00:00:00 2001 From: Arild Matsson Date: Fri, 17 Nov 2023 11:00:51 +0100 Subject: [PATCH 4/6] Set format from file extension when creating corpus --- CHANGELOG.md | 1 + src/api/corpusConfig.js | 23 +++++++++++++++++------ src/corpus/corpusState.composable.js | 5 +++-- src/corpus/createCorpus.composable.js | 4 ++++ src/i18n/locales/en.yaml | 2 +- src/util.js | 10 ++++++++++ src/util.test.js | 17 +++++++++++++++++ 7 files changed, 53 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95c385d..fecce1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ As this project is a user-facing application, the places in the semantic version ### Changed +- A corpus created by upload now gets its format set to match the uploaded files - A corpus created by upload (not through the creation form) now gets its name set to the id, instead of remaining empty ### Fixed diff --git a/src/api/corpusConfig.js b/src/api/corpusConfig.js index a9f7164..4186e63 100644 --- a/src/api/corpusConfig.js +++ b/src/api/corpusConfig.js @@ -68,13 +68,13 @@ export async function makeConfig(id, options) { ], }; - if (format === "xml") { - if (!textAnnotation) { - throw new TypeError("Text annotation setting is required for XML"); + if (format == "xml") { + // The text annotation setting is required if XML, but it may be set later + if (textAnnotation) { + config.import.text_annotation = textAnnotation; + config.export.source_annotations = [`${textAnnotation} as text`, "..."]; } - config.import.text_annotation = textAnnotation; - config.export.source_annotations = [`${textAnnotation} as text`, "..."]; - } else if (format === "pdf") { + } else if (format == "pdf") { config.export.source_annotations = ["text", "page:number"]; } @@ -141,3 +141,14 @@ export async function parseConfig(configYaml) { ).params.value, }; } + +/** Check if the config looks ready to run. May throw anything. */ +export function validateConfig(config) { + if (!config.format) { + throw new TypeError("Format missing"); + } + + if (config.format == "xml" && !config.textAnnotation) { + throw new TypeError("Text annotation setting is required for XML"); + } +} diff --git a/src/corpus/corpusState.composable.js b/src/corpus/corpusState.composable.js index 7a9229a..c3c8e5b 100644 --- a/src/corpus/corpusState.composable.js +++ b/src/corpus/corpusState.composable.js @@ -1,9 +1,10 @@ import { computed } from "vue"; import { useI18n } from "vue-i18n"; -import { FORMATS_EXT } from "@/api/corpusConfig"; +import { validateConfig } from "@/api/corpusConfig"; import useConfig from "./config/config.composable"; import useJob from "./job/job.composable"; import useSources from "./sources/sources.composable"; +import { getException } from "@/util"; /** The "corpus state" is related to the job status, but is more about predicting what action the user needs to take. */ export function useCorpusState(corpusId) { @@ -38,7 +39,7 @@ export function useCorpusState(corpusId) { }); const isConfigValid = computed( - () => config.value && FORMATS_EXT.includes(config.value.format) + () => !getException(() => validateConfig(config.value)) ); const hasMetadata = computed( diff --git a/src/corpus/createCorpus.composable.js b/src/corpus/createCorpus.composable.js index 5970978..e02b0bf 100644 --- a/src/corpus/createCorpus.composable.js +++ b/src/corpus/createCorpus.composable.js @@ -30,9 +30,13 @@ export default function useCreateCorpus() { const corpusId = await createCorpus().catch(alertError); if (!corpusId) return; + // Get file extension of first file, assuming all are using the same extension. + const format = files[0]?.name.split(".").pop(); + // Create a minimal config. const config = { name: { swe: corpusId, eng: corpusId }, + format, }; const results = await Promise.allSettled([ diff --git a/src/i18n/locales/en.yaml b/src/i18n/locales/en.yaml index c806e13..202bd55 100644 --- a/src/i18n/locales/en.yaml +++ b/src/i18n/locales/en.yaml @@ -270,7 +270,7 @@ api.code.failed_uploading_sources: Failed to upload source files api.code.failed_uploading_sources_file_size: Some files could not be uploaded, because they exceed the maximum file size of {max_file_size} MB api.code.failed_uploading_sources_invalid_file_extension: 'File "{file}" could not be uploaded, because it has an invalid filename extension. Please use any of the supported file formats: xml, txt, odt, docx, pdf.' api.code.failed_uploading_sources_invalid_xml: File "{file}" could not be uploaded, because it contains invalid XML -api.code.failed_uploading_sources_incompatible_file_extension: File "{file}" could not be uploaded, because it has an different filename extension. Please check that the file format of this corpus is configured to agree with your source files. +api.code.failed_uploading_sources_incompatible_file_extension: File "{file}" could not be uploaded, because it has a different filename extension. Please check that the file format of this corpus is configured to agree with your source files. api.code.uploaded_sources: The source files were successfully added api.code.data_too_large: Request data too large (max {max_content_length} MB per upload) api.code.listing_sources: Listing current source files for the corpus "{corpus_id}" diff --git a/src/util.js b/src/util.js index 10aa020..ebf99be 100644 --- a/src/util.js +++ b/src/util.js @@ -67,3 +67,13 @@ export function setKeys(obj, keys, defaultValue = null) { /** Create a random string of around 11 chars in the [0-9a-z] range. */ export const randomString = () => Math.random().toString(36).slice(2); + +/** Execute callback, catch and return any exception, otherwise return undefined. */ +export const getException = (f) => { + try { + f(); + } catch (e) { + return e; + } + return undefined; +}; diff --git a/src/util.test.js b/src/util.test.js index 027a6bc..39ddd39 100644 --- a/src/util.test.js +++ b/src/util.test.js @@ -3,6 +3,7 @@ import { ensureExtension, formatDate, formatSeconds, + getException, pathJoin, randomString, setKeys, @@ -64,3 +65,19 @@ describe("randomString", () => { expect(fails).toEqual([]); }); }); + +describe("getException", () => { + test("translate success to undefined", () => { + const f = () => "foobar"; + const exception = getException(f); + expect(exception).toBeUndefined(); + }); + test("reflect exception", () => { + const f = () => { + throw new EvalError("Leverpastej"); + }; + const exception = getException(f); + expect(exception.name).toBe("EvalError"); + expect(exception.message).toBe("Leverpastej"); + }); +}); From 20d93ed88f88bdeac443e99054a6c47952549afa Mon Sep 17 00:00:00 2001 From: Arild Matsson Date: Fri, 17 Nov 2023 11:26:11 +0100 Subject: [PATCH 5/6] Set format from source files with new extension --- CHANGELOG.md | 3 +-- src/corpus/createCorpus.composable.js | 3 ++- src/corpus/sources/SourceUpload.vue | 15 +++++++++++++-- src/corpus/sources/sources.composable.js | 3 ++- src/util.js | 3 +++ src/util.test.js | 19 +++++++++++++++++++ 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fecce1a..c005aa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,7 @@ As this project is a user-facing application, the places in the semantic version ### Changed -- A corpus created by upload now gets its format set to match the uploaded files -- A corpus created by upload (not through the creation form) now gets its name set to the id, instead of remaining empty +- Improved sync between source files and settings: set format from files, set name to corpus id ### Fixed diff --git a/src/corpus/createCorpus.composable.js b/src/corpus/createCorpus.composable.js index e02b0bf..14700d1 100644 --- a/src/corpus/createCorpus.composable.js +++ b/src/corpus/createCorpus.composable.js @@ -6,6 +6,7 @@ import useMessenger from "@/message/messenger.composable"; import useConfig from "./config/config.composable"; import useSources from "./sources/sources.composable"; import useCorpus from "./corpus.composable"; +import { getFilenameExtension } from "@/util"; export default function useCreateCorpus() { const corpusStore = useCorpusStore(); @@ -31,7 +32,7 @@ export default function useCreateCorpus() { if (!corpusId) return; // Get file extension of first file, assuming all are using the same extension. - const format = files[0]?.name.split(".").pop(); + const format = getFilenameExtension(files[0]?.name); // Create a minimal config. const config = { diff --git a/src/corpus/sources/SourceUpload.vue b/src/corpus/sources/SourceUpload.vue index ff92c73..0f094a8 100644 --- a/src/corpus/sources/SourceUpload.vue +++ b/src/corpus/sources/SourceUpload.vue @@ -49,11 +49,13 @@