From 712694c16d36c962a977c90f0d1c2eecaa5be98b Mon Sep 17 00:00:00 2001 From: Arild Matsson Date: Thu, 8 Feb 2024 13:06:24 +0100 Subject: [PATCH 01/41] Distinguish corpora from metadata --- src/api/api.types.ts | 4 ++- src/store/corpus.store.ts | 68 ++++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/api/api.types.ts b/src/api/api.types.ts index b8ae8d4..3135b3d 100644 --- a/src/api/api.types.ts +++ b/src/api/api.types.ts @@ -61,13 +61,15 @@ export type ResourceInfo = { /** Basic data about a resource */ export type ResourceData = { - type: "corpus"; + type: ResourceType; id: string; public_id: string; name: ByLang; source_files: FileMeta[]; }; +export type ResourceType = "corpus" | "metadata"; + /** Job status for a resource */ // There's more but we're not using everything. export type CorpusStatus = { diff --git a/src/store/corpus.store.ts b/src/store/corpus.store.ts index c7a63f7..909d712 100644 --- a/src/store/corpus.store.ts +++ b/src/store/corpus.store.ts @@ -3,53 +3,99 @@ import { defineStore } from "pinia"; import { useStorage } from "@vueuse/core"; import { setKeys } from "@/util"; import type { ByLang } from "@/util.types"; -import type { CorpusStatus, FileMeta, ResourceInfo } from "@/api/api.types"; +import type { + CorpusStatus, + FileMeta, + ResourceInfo, + ResourceType, +} from "@/api/api.types"; import type { ConfigOptions } from "@/api/corpusConfig"; -type Corpus = { +type Resource = { + type: ResourceType; name: ByLang; +}; + +type Corpus = Resource & { + type: "corpus"; sources: FileMeta[]; config: ConfigOptions; status: CorpusStatus; exports: FileMeta[]; }; +type Metadata = Resource; + +// A user-defined type guard to help inform TypeScript +// See https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards +const isCorpus = (resource: Partial): resource is Corpus => + resource.type == "corpus"; + export const useCorpusStore = defineStore("corpus", () => { // Connect state to browser's local storage. Change the number here to the // current date (YYMMDD) if the state shape is changed, to make the browser // forget the old state. The actual number doesn't really matter, as long as // it's a new one. const corporaRef = useStorage("mink@230102.corpora", {}); - const corpora: Record> = reactive(corporaRef.value); + const resources: Record> = reactive( + corporaRef.value, + ); - function setCorpusIds(corpusIds: string[]) { - setKeys(corpora, corpusIds, {}); + const corpora = computed>>(() => + filterResources("corpus"), + ); + const metadatas = computed>>(() => + filterResources("metadata"), + ); + + const filterResources = ( + type: ResourceType, + ): Record> => + Object.keys(resources).reduce( + (corpora, resourceId) => + resources[resourceId].type == type + ? { ...corpora, [resourceId]: resources[resourceId] } + : corpora, + {}, + ); + + function setCorpusIds(resourceIds: string[]) { + setKeys(resources, resourceIds, {}); } function setCorpora(infos: ResourceInfo[]) { // Drop old keys, assign empty records for each new id const ids = infos.map((info) => info.resource.id); - setKeys(corpora, ids, {}); + setKeys(resources, ids, {}); for (const infoNew of infos) { // Patch any existing record, otherwise create a new one. const info = - infoNew.resource.id in corpora ? corpora[infoNew.resource.id] : {}; + infoNew.resource.id in corpora.value + ? resources[infoNew.resource.id] + : {}; + info.type = infoNew.resource.type; info.name = infoNew.resource.name; - info.sources = infoNew.resource.source_files; - info.status = infoNew.job; - corpora[infoNew.resource.id] = info; + + if (isCorpus(info)) { + info.sources = infoNew.resource.source_files; + info.status = infoNew.job; + } + + resources[infoNew.resource.id] = info; } } function removeCorpus(corpusId: string) { - delete corpora[corpusId]; + delete resources[corpusId]; } const hasCorpora = computed(() => !!Object.keys(corpora).length); return { + resources, corpora, + metadatas, setCorpusIds, setCorpora, removeCorpus, From eda5d0e1e240ebe23691300efc051d93e3c09d09 Mon Sep 17 00:00:00 2001 From: Arild Matsson Date: Thu, 8 Feb 2024 13:06:36 +0100 Subject: [PATCH 02/41] Show metadatas --- src/corpora/LibraryView.vue | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/corpora/LibraryView.vue b/src/corpora/LibraryView.vue index f63fcdc..e2e10f0 100644 --- a/src/corpora/LibraryView.vue +++ b/src/corpora/LibraryView.vue @@ -1,4 +1,5 @@ diff --git a/src/corpus/CorpusDelete.vue b/src/corpus/CorpusDelete.vue index 8dd51f6..2b49314 100644 --- a/src/corpus/CorpusDelete.vue +++ b/src/corpus/CorpusDelete.vue @@ -6,16 +6,16 @@ import RouteButton from "@/components/RouteButton.vue"; import LayoutSection from "@/components/LayoutSection.vue"; import PendingContent from "@/spin/PendingContent.vue"; import useDeleteCorpus from "./deleteCorpus.composable"; -import { useCorpusStore } from "@/store/corpus.store"; +import { useResourceStore } from "@/store/resource.store"; const router = useRouter(); const corpusId = useCorpusIdParam(); const { deleteCorpus } = useDeleteCorpus(); -const corpusStore = useCorpusStore(); +const resourceStore = useResourceStore(); async function doDelete() { await deleteCorpus(corpusId); - if (!(corpusId in corpusStore.corpora)) { + if (!(corpusId in resourceStore.corpora)) { router.push("/corpus"); } } diff --git a/src/corpus/CorpusView.vue b/src/corpus/CorpusView.vue index 75b70f9..629449f 100644 --- a/src/corpus/CorpusView.vue +++ b/src/corpus/CorpusView.vue @@ -1,19 +1,19 @@ diff --git a/src/library/LibraryView.vue b/src/library/LibraryView.vue index 75ea83d..dbcc8d4 100644 --- a/src/library/LibraryView.vue +++ b/src/library/LibraryView.vue @@ -3,25 +3,25 @@ import useLocale from "@/i18n/locale.composable"; import PadButton from "@/components/PadButton.vue"; import LayoutSection from "@/components/LayoutSection.vue"; import PendingContent from "@/spin/PendingContent.vue"; -import useCorpora from "./corpora.composable"; +import useResources from "./resources.composable"; import CorpusButton from "./CorpusButton.vue"; import { useAuth } from "@/auth/auth.composable"; import SourceUpload from "@/corpus/sources/SourceUpload.vue"; import PageTitle from "@/components/PageTitle.vue"; import HelpBox from "@/components/HelpBox.vue"; -import { useCorpusStore } from "@/store/corpus.store"; +import { useResourceStore } from "@/store/resource.store"; import useSpin from "@/spin/spin.composable"; import useCreateCorpus from "@/corpus/createCorpus.composable"; import RouteButton from "@/components/RouteButton.vue"; -const corpusStore = useCorpusStore(); +const resourceStore = useResourceStore(); const { requireAuthentication, isAuthenticated } = useAuth(); -const { loadCorpora } = useCorpora(); +const { loadResources } = useResources(); const { createFromUpload } = useCreateCorpus(); const { spin } = useSpin(); const { th } = useLocale(); -requireAuthentication(loadCorpora); +requireAuthentication(loadResources); async function createCorpusFromFiles(files: FileList) { await spin(createFromUpload(files), null, "create"); @@ -34,7 +34,7 @@ async function createCorpusFromFiles(files: FileList) {

{{ - corpusStore.hasCorpora + resourceStore.hasCorpora ? $t("library.help.corpora") : $t("library.help.corpora.none") }} @@ -43,7 +43,7 @@ async function createCorpusFromFiles(files: FileList) { @@ -57,7 +57,7 @@ async function createCorpusFromFiles(files: FileList) {

-