Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
arildm committed Jan 2, 2024
2 parents a15b865 + ca27d3d commit adc5b79
Show file tree
Hide file tree
Showing 19 changed files with 118 additions and 82 deletions.
20 changes: 19 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ As this project is a user-facing application, the places in the semantic version

## [Unreleased]

## [1.1.0] (2024-01-02)

### Added

- Link to manual about exports files

### Changed

- Rename "Dashboard" to "Library"
- Use new `resource-info` route, drop `check-status` and `list-sources`
- The local storage key is now tagged with a datestamp, and should be changed when the data shape of the state changes

### Fixed

- Allow clicking most elements behind a loading spinner
- Home page width on small screen

## [1.0.5] (2023-11-28)

### Changed
Expand Down Expand Up @@ -82,7 +99,8 @@ The frontend is now open to the general public! This version allows users to:

Code changes up until this point are not documented other than in the git commit log.

[unreleased]: https://github.com/spraakbanken/mink-frontend/compare/v1.0.5...HEAD
[unreleased]: https://github.com/spraakbanken/mink-frontend/compare/v1.1.0...HEAD
[1.1.0]: https://github.com/spraakbanken/mink-frontend/compare/v1.0.5...v1.1.0
[1.0.5]: https://github.com/spraakbanken/mink-frontend/compare/v1.0.4...v1.0.5
[1.0.4]: https://github.com/spraakbanken/mink-frontend/compare/v1.0.3...v1.0.4
[1.0.3]: https://github.com/spraakbanken/mink-frontend/compare/v1.0.2...v1.0.3
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mink-frontend",
"version": "1.0.5",
"version": "1.1.0",
"license": "MIT",
"scripts": {
"dev": "vite",
Expand Down
21 changes: 3 additions & 18 deletions src/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,6 @@ class MinkApi {
return response.data;
}

async listSources(corpusId) {
const response = await this.axios.get("list-sources", {
params: { corpus_id: corpusId },
});
return response.data.contents;
}

async downloadSourceFile(corpusId, filename, binary = false) {
const response = await this.axios.get("download-sources", {
params: { corpus_id: corpusId, file: filename, zip: false },
Expand Down Expand Up @@ -102,22 +95,14 @@ class MinkApi {
return response.data;
}

/**
* @returns {job_status, message, status} job_status can be: none, syncing_corpus,
* waiting, annotating, done_annotating, syncing_results, done, error, aborted.
*/
async checkStatus(corpusId) {
const response = await this.axios.get("check-status", {
/** @see https://ws.spraakbanken.gu.se/ws/mink/api-doc#tag/Process-Corpus/operation/resourceinfo */
async resourceInfo(corpusId) {
const response = await this.axios.get("resource-info", {
params: { corpus_id: corpusId },
});
return response.data;
}

async checkStatusAll() {
const response = await this.axios.get("check-status");
return response.data.jobs;
}

async runSparv(corpusId) {
const response = await this.axios
.put("run-sparv", null, { params: { corpus_id: corpusId } })
Expand Down
24 changes: 8 additions & 16 deletions src/api/backend.composable.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@ export default function useMinkBackend() {
`corpus/${corpusId}/config`
);

const loadSources = (corpusId) =>
spin(
api.listSources(corpusId),
t("source.list.loading"),
`corpus/${corpusId}/sources`
);

const downloadSource = (corpusId, filename, binary) =>
spin(
api.downloadSourceFile(corpusId, filename, binary),
Expand Down Expand Up @@ -73,12 +66,13 @@ export default function useMinkBackend() {
`corpus/${corpusId}/sources`
);

const loadJob = (corpusId) =>
spin(api.checkStatus(corpusId), t("job.loading"), `corpus/${corpusId}/job`);

/** Load job status data for those corpora that have any job info. */
const loadJobs = () =>
spin(api.checkStatusAll(), t("job.loading"), `corpora`);
/** @see https://ws.spraakbanken.gu.se/ws/mink/api-doc#tag/Process-Corpus/operation/resourceinfo */
const resourceInfo = (corpusId) =>
spin(
api.resourceInfo(corpusId),
t("resource.loading"),
`corpus/${corpusId}/job`
);

const runJob = (corpusId) =>
spin(api.runSparv(corpusId), t("job.starting"), `corpus/${corpusId}/job`);
Expand Down Expand Up @@ -134,13 +128,11 @@ export default function useMinkBackend() {
deleteCorpus,
loadConfig,
saveConfig,
loadSources,
downloadSource,
downloadPlaintext,
uploadSources,
deleteSource,
loadJob,
loadJobs,
resourceInfo,
runJob,
installKorp,
installStrix,
Expand Down
8 changes: 5 additions & 3 deletions src/corpora/Dashboard.vue → src/corpora/Library.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<template>
<PageTitle>{{ $t("library") }}</PageTitle>
<Section v-if="isAuthenticated" :title="$t('corpuses')">
<HelpBox>
<p>
{{
corpusStore.hasCorpora
? $t("dashboard.help.corpora")
: $t("dashboard.help.corpora.none")
? $t("library.help.corpora")
: $t("library.help.corpora.none")
}}
</p>
</HelpBox>
Expand All @@ -24,7 +25,7 @@
</PendingContent>
</Section>
<Section v-if="isAuthenticated" :title="$t('new_corpus')">
<PendingContent on="create">
<PendingContent on="create" blocking>
<SourceUpload
:file-handler="createCorpusFromFiles"
:variant="corpusStore.hasCorpora ? null : 'primary'"
Expand All @@ -40,6 +41,7 @@ import PendingContent from "@/spin/PendingContent.vue";
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 useCorpora from "@/corpora/corpora.composable";
import { useCorpusStore } from "@/store/corpus.store";
Expand Down
2 changes: 1 addition & 1 deletion src/corpus/CorpusDelete.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ async function doDelete() {
</script>

<template>
<PendingContent :on="`corpus/${corpusId}`">
<PendingContent :on="`corpus/${corpusId}`" blocking>
<Section :title="$t('corpus.delete')">
<p class="my-2">{{ $t("corpus.delete.ask") }}</p>

Expand Down
2 changes: 1 addition & 1 deletion src/corpus/config/CorpusConfiguration.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
</Section>
</FormKit>
<div class="flex justify-center">
<PendingContent :on="`corpus/${corpusId}/config`">
<PendingContent :on="`corpus/${corpusId}`">
<router-link :to="`/corpus/${corpusId}/delete`">
<ActionButton variant="danger">
<icon :icon="['far', 'trash-can']" class="mr-1" />
Expand Down
20 changes: 14 additions & 6 deletions src/corpus/corpus.composable.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import useMessenger from "@/message/messenger.composable";
import useCorpora from "@/corpora/corpora.composable";
import useConfig from "./config/config.composable";
import useExports from "./exports/exports.composable";
import useSources from "./sources/sources.composable";
import useJob from "./job/job.composable";

/** Let data be refreshed initially, but skip subsequent load calls. */
const isCorpusFresh = {};
Expand All @@ -19,23 +17,33 @@ export default function useCorpus(corpusId) {
const { alertError } = useMessenger();
const { loadConfig } = useConfig(corpusId);
const { loadExports } = useExports(corpusId);
const { loadJob } = useJob(corpusId);
const { loadSources } = useSources(corpusId);

async function loadCorpus(force = false) {
// Make sure the corpus has an entry in the store.
await loadCorpora();
if (isCorpusFresh[corpusId] && !force) {
return;
}

// Load all essential info about the corpus.
await Promise.all([
loadConfig(), //
loadExports(),
loadJob(),
loadSources(),
loadResourceInfo(),
]);

// Remember to skip loading next time.
isCorpusFresh[corpusId] = true;
}

/** Load job status and source files in the same request. */
async function loadResourceInfo() {
const info = await mink.resourceInfo(corpusId).catch(alertError);
corpusStore.corpora[corpusId].name = info.resource.name;
corpusStore.corpora[corpusId].sources = info.resource.source_files;
corpusStore.corpora[corpusId].status = info.job;
}

async function deleteCorpus(corpusId_ = corpusId) {
// Delete corpus in the backend.
await mink.deleteCorpus(corpusId_).catch(alertError);
Expand Down
7 changes: 7 additions & 0 deletions src/corpus/exports/CorpusResult.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
<Section :title="$t('result')">
<HelpBox>
<p>{{ $t("exports.help") }}</p>
<aside>
<a
href="https://spraakbanken.gu.se/en/tools/mink/manual#download-results"
>
{{ $t("exports.help.more.label") }}
</a>
</aside>
</HelpBox>

<div class="my-4">
Expand Down
24 changes: 14 additions & 10 deletions src/corpus/job/job.composable.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,26 @@ export default function useJob(corpusId) {
const { alertError } = useMessenger();

async function loadJob() {
corpus.value.status = await mink
.loadJob(corpusId)
const info = await mink
.resourceInfo(corpusId)
.catch(() => ({}))
.catch(alertError);
corpus.value.status = info.job;
}

async function runJob() {
corpus.value.status = await mink.runJob(corpusId).catch(alertError);
const info = await mink.runJob(corpusId).catch(alertError);
corpus.value.status = info.job;
}

async function installKorp() {
corpus.value.status = await mink.installKorp(corpusId).catch(alertError);
const info = await mink.installKorp(corpusId).catch(alertError);
corpus.value.status = info.job;
}

async function installStrix() {
corpus.value.status = await mink.installStrix(corpusId).catch(alertError);
const info = await mink.installStrix(corpusId).catch(alertError);
corpus.value.status = info.job;
}

async function abortJob() {
Expand All @@ -79,22 +83,22 @@ export default function useJob(corpusId) {

const jobStatus = computed(() => corpus.value?.status);
const sparvStatus = computed(
() => new JobStatus(jobStatus.value?.job_status?.sparv)
() => new JobStatus(jobStatus.value?.status?.sparv)
);
const korpStatus = computed(
() => new JobStatus(jobStatus.value?.job_status?.korp)
() => new JobStatus(jobStatus.value?.status?.korp)
);
const strixStatus = computed(
() => new JobStatus(jobStatus.value?.job_status?.strix)
() => new JobStatus(jobStatus.value?.status?.strix)
);
const currentStatus = computed(() => {
const process = jobStatus.value.current_process;
return new JobStatus(jobStatus.value?.job_status?.[process]);
return new JobStatus(jobStatus.value?.status?.[process]);
});

// "Running" if any job is waiting/running.
const isJobRunning = computed(() => {
const statuses = jobStatus.value?.job_status;
const statuses = jobStatus.value?.status;
if (!statuses) return false;
return Object.keys(statuses).some(
(process) => new JobStatus(statuses[process]).isRunning
Expand Down
4 changes: 2 additions & 2 deletions src/corpus/sources/sources.composable.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export default function useSources(corpusId) {
const sources = computed(() => corpusStore.corpora[corpusId]?.sources || []);

async function loadSources(corpusId_ = corpusId) {
const sourcesFetched = await mink.loadSources(corpusId_).catch(alertError);
corpusStore.corpora[corpusId_].sources = sourcesFetched;
const info = await mink.resourceInfo(corpusId_).catch(alertError);
corpusStore.corpora[corpusId_].sources = info.resource.source_files;
}

async function downloadSource(source, binary) {
Expand Down
8 changes: 4 additions & 4 deletions src/home/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const logoutUrl = getLogoutUrl();
<div
class="flex-1 flex flex-col md:flex-row 2xl:flex-col items-center gap-6"
>
<HomeIllustration class="w-96 md:w-1/2 2xl:w-4/5">
<HomeIllustration class="md:w-1/2 2xl:w-4/5">
<img src="@/assets/sparv-screen.png" />
</HomeIllustration>

Expand All @@ -106,7 +106,7 @@ const logoutUrl = getLogoutUrl();
<div
class="flex-1 flex flex-col md:flex-row-reverse 2xl:flex-col items-center gap-6"
>
<HomeIllustration class="w-96 md:w-1/2 2xl:w-4/5">
<HomeIllustration class="md:w-1/2 2xl:w-4/5">
<img src="@/assets/texts.png" />
</HomeIllustration>

Expand All @@ -125,7 +125,7 @@ const logoutUrl = getLogoutUrl();
<div
class="flex-1 flex flex-col md:flex-row 2xl:flex-col items-center gap-6"
>
<HomeIllustration class="w-96 md:w-1/2 2xl:w-4/5">
<HomeIllustration class="md:w-1/2 2xl:w-4/5">
<img src="@/assets/korp-screen.png" />
</HomeIllustration>

Expand Down Expand Up @@ -154,7 +154,7 @@ const logoutUrl = getLogoutUrl();
<div
class="flex-1 flex flex-col md:flex-row-reverse 2xl:flex-col items-center gap-6"
>
<HomeIllustration class="w-96 md:w-1/2 2xl:w-5/6">
<HomeIllustration class="md:w-1/2 2xl:w-5/6">
<img src="@/assets/share.png" />
</HomeIllustration>

Expand Down
9 changes: 5 additions & 4 deletions src/i18n/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,17 @@ home.otherdata.body: Make sure to first get acquainted with any existing languag
home.otherdata.sbdata.title: "Språkbanken Text: Language resources"
welcome: Welcome, {name}!
mydata: My data
dashboard: Dashboard
dashboard.help.corpora: These are the corpora that you have created. Only you can see them. Click them to view more details.
dashboard.help.corpora.none: Mink provides automatic linguistic analysis for your data. Start by creating a corpus; use the "@:{'new_corpus'}" button or drop text files into the upload field below.
library: Library
library.help.corpora: These are the corpora that you have created. Only you can see them. Click them to view more details.
library.help.corpora.none: Mink provides automatic linguistic analysis for your data. Start by creating a corpus; use the "@:{'new_corpus'}" button or drop text files into the upload field below.
corpus.create.help: The corpus will be accessibly by you only. You can always change these values later.
corpus.creating: Creating corpus
corpus.configuring: Configuring corpus
corpus.delete: Delete corpus
corpus.delete.ask: Are you sure you want to delete this corpus?
corpus.deleting: Deleting corpus
corpus.list.loading: Listing corpora
resource.loading: Loading dataset
corpus.state.unknown: Unknown
corpus.state.empty: No files
corpus.state.needing_config: Configuration needed
Expand Down Expand Up @@ -56,7 +57,6 @@ job.run: Run annotation
job.rerun: Re-run annotation
job.abort: Abort
job.aborting: Aborting annotation job
job.loading: Checking annotation status
job.starting: Queueing annotation job
job.installing: Installing to Korp
job.status: Status
Expand Down Expand Up @@ -95,6 +95,7 @@ exports.tools.view: View
exports.download.help: Results can be downloaded as machine-readable files for processing in scripts or other specialized software.
exports.downloading: Downloading results
exports.help: The annotation process yields export files for each input file. You can download each single export file or all of them in a bundle. The exact structure of the files depends on the input files as well as the configuration. They are stored on the server indefinitely, but re-running the annotation will replace them with new ones.
exports.help.more.label: Read more about export files in the user manual
user.settings: Settings
user.settings.admin_mode: Enable administration mode
user.admin_mode.warning: Administration mode is enabled. Please be careful!
Expand Down
Loading

0 comments on commit adc5b79

Please sign in to comment.