Skip to content

Commit

Permalink
feat: Editable config file in browser
Browse files Browse the repository at this point in the history
Fixes #178
  • Loading branch information
arildm committed Nov 28, 2024
1 parent c7d0ce4 commit bd8c77e
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ As this project is a user-facing application, the places in the semantic version
### Added

- Add geotagging to the NER option [#174](https://github.com/spraakbanken/mink-frontend/issues/174)
- Editable config file in browser [#178](https://github.com/spraakbanken/mink-frontend/issues/178)

### Fixed

Expand Down
33 changes: 17 additions & 16 deletions src/corpus/config/CorpusConfigCustom.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import type { AxiosError } from "axios";
import { PhWarning } from "@phosphor-icons/vue";
import { PhPencilSimple, PhWarning } from "@phosphor-icons/vue";
import useCorpusIdParam from "@/corpus/corpusIdParam.composable";
import useConfig from "@/corpus/config/config.composable";
import { useAuth } from "@/auth/auth.composable";
Expand All @@ -11,6 +11,8 @@ import type { MinkResponse } from "@/api/api.types";
import useMessenger from "@/message/messenger.composable";
import SyntaxHighlight from "@/components/SyntaxHighlight.vue";
import PendingContent from "@/spin/PendingContent.vue";
import RouteButton from "@/components/RouteButton.vue";
import CorpusConfigCustomHelp from "./CorpusConfigCustomHelp.vue";
const corpusId = useCorpusIdParam();
const { config, uploadConfigRaw } = useConfig(corpusId);
Expand All @@ -31,40 +33,39 @@ async function upload(files: File[]) {
</script>

<template>
<HelpBox>
<i18n-t scope="global" keypath="config.custom.help">
<template #sparv>
<a :href="$t('sparv.url')">Sparv</a>
</template>
<template #topic>
<a
href="https://spraakbanken.gu.se/sparv/#/user-manual/corpus-configuration"
>
Corpus Configuration
</a>
</template>
</i18n-t>
</HelpBox>
<CorpusConfigCustomHelp />

<div class="flex flex-wrap gap-4 items-start">
<LayoutBox class="w-96 grow" :title="$t('upload')">
<HelpBox important>
<PhWarning class="inline mb-1 mr-1" />
{{ $t("config.custom.upload.caution") }}
</HelpBox>

<HelpBox important>
<PhWarning class="inline mb-1 mr-1" />
{{ $t("config.custom.upload.overwrite") }}
</HelpBox>

<PendingContent :on="`corpus/${corpusId}/config`" blocking>
<FileUpload :file-handler="upload" accept=".yaml,.yml" />
<FileUpload :file-handler="upload" accept=".yaml,.yml" primary />
</PendingContent>
</LayoutBox>

<LayoutBox class="w-96 grow" :title="$t('show')">
<PendingContent :on="`corpus/${corpusId}/config`">
<SyntaxHighlight v-if="config" language="yaml" :code="config" />
</PendingContent>

<template #controls>
<RouteButton
:to="`/library/corpus/${corpusId}/config/custom/edit`"
class="button-primary"
>
<PhPencilSimple weight="bold" class="inline mb-1 mr-1" />
{{ $t("edit") }}
</RouteButton>
</template>
</LayoutBox>
</div>
</template>
97 changes: 97 additions & 0 deletions src/corpus/config/CorpusConfigCustomEdit.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<script setup lang="ts">
import Yaml from "js-yaml";
import { useAuth } from "@/auth/auth.composable";
import useConfig from "./config.composable";
import useCorpusIdParam from "../corpusIdParam.composable";
import { ref, watchEffect } from "vue";
import useMessenger from "@/message/messenger.composable";
import type { AxiosError } from "axios";
import type { MinkResponse } from "@/api/api.types";
import LayoutBox from "@/components/LayoutBox.vue";
import HelpBox from "@/components/HelpBox.vue";
import { PhFileX, PhWarning } from "@phosphor-icons/vue";
import PendingContent from "@/spin/PendingContent.vue";
import ActionButton from "@/components/ActionButton.vue";
import { getException } from "@/util";
import CorpusConfigCustomHelp from "./CorpusConfigCustomHelp.vue";
import RouteButton from "@/components/RouteButton.vue";
const corpusId = useCorpusIdParam();
const { requireAuthentication } = useAuth();
const { config, uploadConfigRaw } = useConfig(corpusId);
const { alertError } = useMessenger();
const input = ref(config.value || "");
const isValid = ref<boolean>();
requireAuthentication();
function validate() {
isValid.value = !getException(() => Yaml.load(input.value));
}
async function upload() {
if (input.value == config.value) return;
try {
await uploadConfigRaw(input.value);
} catch (error) {
alertError(error as AxiosError<MinkResponse>);
}
}
watchEffect(validate);
// Backend may modify input when saving, then make that visible
watchEffect(() => (input.value = config.value || ""));
</script>

<template>
<CorpusConfigCustomHelp />

<div class="flex">
<LayoutBox class="w-96 grow" :title="$t('edit')">
<template #controls>
<RouteButton
:to="`/library/corpus/${corpusId}/config/custom`"
:class="{ 'button-primary': input == config }"
>
{{ input == config ? $t("show") : $t("cancel") }}
</RouteButton>
</template>

<HelpBox important>
<PhWarning class="inline mb-1 mr-1" />
{{ $t("config.custom.upload.caution") }}
</HelpBox>
<HelpBox important>
<PhWarning class="inline mb-1 mr-1" />
{{ $t("config.custom.upload.overwrite") }}
</HelpBox>

<PendingContent :on="`corpus/${corpusId}/config`" blocking>
<div class="flex gap-2 items-baseline my-2">
<div class="flex-grow"></div>
<div v-if="!isValid" :title="$t('yaml.invalid')">
<PhFileX class="inline text-xl text-red-600" />
</div>
<ActionButton
@click="upload"
class="button-primary"
:disabled="input == config || !isValid"
:title="
input == config
? $t('save.no_changes')
: !isValid
? $t('yaml.invalid')
: undefined
"
>
{{ $t("save") }}
</ActionButton>
</div>

<textarea class="w-full h-96 font-mono text-sm" v-model="input" />
</PendingContent>
</LayoutBox>
</div>
</template>
20 changes: 20 additions & 0 deletions src/corpus/config/CorpusConfigCustomHelp.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
import HelpBox from "@/components/HelpBox.vue";
</script>

<template>
<HelpBox>
<i18n-t scope="global" keypath="config.custom.help">
<template #sparv>
<a :href="$t('sparv.url')">Sparv</a>
</template>
<template #topic>
<a
href="https://spraakbanken.gu.se/sparv/#/user-manual/corpus-configuration"
>
Corpus Configuration
</a>
</template>
</i18n-t>
</HelpBox>
</template>
5 changes: 4 additions & 1 deletion src/i18n/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ load: Load
not_loaded: Not loaded
file.archive: Archive
file.singles: Single files
save.no_changes: There are no changes to save
name: Name
metadata.name.help: You can use spaces and special characters.
identifier: Identifier
Expand All @@ -199,7 +200,7 @@ metadata.description.help: |
If you aim to share or publish the results, we recommend entering one or two sentences
to summarize the content or purpose to a potential user.
fileFormat: Source format
config.custom: Custom configuration
config.custom: Custom config
config.custom.help: Mink uses {sparv}, a modular and configurable pipeline for text analysis, to process your corpus. The standard configuration form only exposes a few of the available Sparv options. On this page, you can view and submit your own config file, written in the YAML format. Please refer to the Sparv documentation on {topic} for more information.
config.custom.upload.caution: Please note that submitting an invalid config file may cause unexpected behaviour.
config.custom.upload.overwrite: Saving the standard configuration form may overwrite your custom config.
Expand Down Expand Up @@ -245,6 +246,8 @@ accessdenied.contact: If you have questions, or you want to report a bug, please
notfound: Page not found
notfound.description: Something went wrong, and there is nothing to see at this address.
notfound.contact: If you have questions, or you want to report a bug, please contact sb-info{'@'}svenska.gu.se. Thank you!
yaml.valid: YAML is valid
yaml.invalid: YAML is invalid

# These correspond to the `return_code` param of backend responses
api.code.missing_auth_token: Missing authorization token
Expand Down
7 changes: 5 additions & 2 deletions src/i18n/locales/sv.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ load: Ladda in
not_loaded: Ej laddad
file.archive: Arkivfil
file.singles: Enskilda filer
save.no_changes: Det finns inga ändringar att spara
name: Namn
metadata.name.help: Det går bra att använda mellanslag och specialtecken.
identifier: Identifierare
Expand All @@ -200,10 +201,10 @@ metadata.description.help: |
Om du vill distribuera eller publicera resultatet rekommenderar vi en eller två meningar
som sammanfattar innehållet eller syftet för en potentiell användare.
fileFormat: Källformat
config.custom: Egen konfiguration
config.custom: Egen config
config.custom.help: Mink använder {sparv}, en modulär och konfigurerbar pipeline för textanalys, för att processa korpusen. Det vanliga formuläret visar endast en liten del av alla inställningar. På den här sidan kan du undersöka den faktiska configfilen och ladda upp en egen, i formatet YAML. Använd Sparvdokumentationens avsnitt {topic} för att tolka filens struktur.
config.custom.upload.caution: Notera att en ogiltig configfil kan leda till oväntat beteende.
config.custom.upload.overwrite: Om du sparar i det vanliga formuläret igen kan den egna konfigurationen skrivas över.
config.custom.upload.overwrite: Om du sparar i det vanliga formuläret igen kan den egna configen skrivas över.
config.format.help: Ange vilket filformat källtexterna har. Alla filer måste ha det valda formatet.
config.format.note.pdf: PDF-formatet är byggt främst för visuell presentation. Text som extraheras från PDF-filer kan ibland ge bristfälliga resultat. OCR-behandling av scannade dokument är (för närvarande) inget som Mink stödjer.
config.text_annotation: Textelement
Expand Down Expand Up @@ -247,6 +248,8 @@ accessdenied.contact: Om du har frågor eller vill rapportera en bugg, kontakta
notfound: Sidan kan inte hittas
notfound.description: Något har gått fel, och det finns ingenting att visa på den här adressen.
notfound.contact: Om du har frågor eller vill rapportera en bugg, kontakta gärna sb-info{'@'}svenska.gu.se. Tack!
yaml.valid: YAML-koden är giltig
yaml.invalid: YAML-koden är ogiltig

# These correspond to the `return_code` param of backend responses
api.code.missing_auth_token: Auktoriseringstoken saknas
Expand Down
7 changes: 7 additions & 0 deletions src/router/corpus.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const CorpusConfiguration = () =>
import("@/corpus/config/CorpusConfiguration.vue");
const CorpusConfigCustom = () =>
import("@/corpus/config/CorpusConfigCustom.vue");
const CorpusConfigCustomEdit = () =>
import("@/corpus/config/CorpusConfigCustomEdit.vue");
const CorpusResult = () => import("@/corpus/exports/CorpusResult.vue");
const CorpusDelete = () => import("@/corpus/CorpusDelete.vue");
const SourceView = () => import("@/corpus/sources/SourceView.vue");
Expand Down Expand Up @@ -42,6 +44,11 @@ const corpusRoutes: RouteRecordRaw[] = [
component: CorpusConfigCustom,
meta: { title: "config.custom" },
},
{
path: "config/custom/edit",
component: CorpusConfigCustomEdit,
meta: { title: "edit" },
},
{
path: "sources/:filename",
component: SourceView,
Expand Down
6 changes: 3 additions & 3 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ export default <Config>{
center: true,
padding: "2rem",
},
fontFamily: {
sans: ['"Source Sans 3 Variable"', "sans-serif"],
},
extend: {
colors: {
sborange: {
Expand All @@ -26,6 +23,9 @@ export default <Config>{
100: "#d7ebeb",
},
},
fontFamily: {
sans: ['"Source Sans 3 Variable"', "sans-serif"],
},
keyframes: {
pulse2: {
"0%": { opacity: ".8" },
Expand Down

0 comments on commit bd8c77e

Please sign in to comment.