diff --git a/.env b/.env index 52b071d..6f08e10 100644 --- a/.env +++ b/.env @@ -5,5 +5,6 @@ VITE_LOGOUT_URL=https://sp.spraakbanken.gu.se/Shibboleth.sso/Logout # VITE_JWT_URL=https://sp.spraakbanken.gu.se/auth/jwt VITE_KORP_URL=https://spraakbanken.gu.se/korp/ VITE_STRIX_URL=https://spraakbanken.gu.se/strix/ +VITE_NEWS_URL=https://raw.githubusercontent.com/spraakbanken/newsdesk/main/data/mink.yaml VITE_MATOMO_URL=https://spraakbanken.gu.se/stats/ # VITE_MATOMO_ID= # Do not report to the real backend when developing \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c19d66..0f9e398 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 22.x] steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4496a5f..619551c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,24 @@ As this project is a user-facing application, the places in the semantic version ## [Unreleased] +## [1.6.0] (2024-04-30) + +### Added + +- News shown in two places on home page: featured on top, others under the intro text + +### Changed + +- Restructured panels on corpus overview to better match backend concepts: + - New _Analysis_ panel with the run button from _Status_ and the downloads from _Results_ + - Renamed _Result_ to _Explore_ [#115](https://github.com/spraakbanken/mink-frontend/issues/115) +- Fetching news from the Newsdesk repo on page load, instead of a static file at build time +- The `on` prop of `PendingContent` now matches by start of string + +### Fixed + +- Clarify that data installed in tools is outdated after annotation re-run [#154](https://github.com/spraakbanken/mink-frontend/issues/154) + ## [1.5.0] (2024-04-23) ### Added @@ -183,7 +201,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.5.0...HEAD +[unreleased]: https://github.com/spraakbanken/mink-frontend/compare/v1.6.0...HEAD +[1.6.0]: https://github.com/spraakbanken/mink-frontend/compare/v1.5.0...v1.6.0 [1.5.0]: https://github.com/spraakbanken/mink-frontend/compare/v1.4.0...v1.5.0 [1.4.0]: https://github.com/spraakbanken/mink-frontend/compare/v1.3.0...v1.4.0 [1.3.0]: https://github.com/spraakbanken/mink-frontend/compare/v1.2.0...v1.3.0 diff --git a/env.d.ts b/env.d.ts index 780a8a7..20d664b 100644 --- a/env.d.ts +++ b/env.d.ts @@ -7,6 +7,7 @@ interface ImportMetaEnv { readonly VITE_JWT_URL?: string; readonly VITE_KORP_URL: string; readonly VITE_STRIX_URL: string; + readonly VITE_NEWS_URL: string; readonly VITE_MATOMO_URL: string; readonly VITE_MATOMO_ID?: number; } diff --git a/package.json b/package.json index 95fc05a..79e30f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mink-frontend", - "version": "1.5.0", + "version": "1.6.0", "license": "MIT", "scripts": { "dev": "vite", diff --git a/src/api/backend.composable.ts b/src/api/backend.composable.ts index efe4ced..c042bf8 100644 --- a/src/api/backend.composable.ts +++ b/src/api/backend.composable.ts @@ -14,10 +14,10 @@ export default function useMinkBackend() { spin(api.createMetadata(publicId), "create"); const deleteCorpus = (corpusId: string) => - spin(api.removeCorpus(corpusId), `corpus/${corpusId}`); + spin(api.removeCorpus(corpusId), `corpus/${corpusId}/delete`); const deleteMetadata = (resourceId: string) => - spin(api.removeMetadata(resourceId), `resource/${resourceId}`); + spin(api.removeMetadata(resourceId), `resource/${resourceId}/delete`); const loadConfig = (corpusId: string) => spin(api.downloadConfig(corpusId), `corpus/${corpusId}/config`); @@ -28,7 +28,7 @@ export default function useMinkBackend() { const downloadSource = (corpusId: string, filename: string, binary = false) => spin( api.downloadSources(corpusId, filename, binary), - `corpus/${corpusId}/sources/${filename}`, + `corpus/${corpusId}/sources/${filename}/raw`, ); const downloadPlaintext = (corpusId: string, filename: string) => @@ -44,11 +44,18 @@ export default function useMinkBackend() { ) => spin( api.uploadSources(corpusId, files, onProgress), - `corpus/${corpusId}/sources`, + `corpus/${corpusId}/sources/upload`, ); const deleteSource = (corpusId: string, filename: string) => - spin(api.removeSource(corpusId, filename), `corpus/${corpusId}/sources`); + spin( + api.removeSource(corpusId, filename), + `corpus/${corpusId}/sources/list`, + ); + + // Same as `resourceInfoOne` but with another spin token. + const listSources = (corpusId: string) => + spin(api.resourceInfoOne(corpusId), `corpus/${corpusId}/sources/list`); const uploadMetadata = (resourceId: string, yaml: string) => spin( @@ -64,31 +71,32 @@ export default function useMinkBackend() { const resourceInfoAll = () => spin(api.resourceInfoAll(), "corpora"); + // Same as `listSources` but with another spin token. const resourceInfoOne = (corpusId: string) => - spin(api.resourceInfoOne(corpusId), `corpus/${corpusId}/job`); + spin(api.resourceInfoOne(corpusId), `corpus/${corpusId}/info`); const runJob = (corpusId: string) => - spin(api.runSparv(corpusId), `corpus/${corpusId}/job`); + spin(api.runSparv(corpusId), `corpus/${corpusId}/job/sparv`); const installKorp = (corpusId: string) => - spin(api.installKorp(corpusId), `corpus/${corpusId}/job`); + spin(api.installKorp(corpusId), `corpus/${corpusId}/job/install/korp`); const installStrix = (corpusId: string) => - spin(api.installStrix(corpusId), `corpus/${corpusId}/job`); + spin(api.installStrix(corpusId), `corpus/${corpusId}/job/install/strix`); const abortJob = (corpusId: string) => - spin(api.abortJob(corpusId), `corpus/${corpusId}/job`); + spin(api.abortJob(corpusId), `corpus/${corpusId}/job/abort`); const loadExports = (corpusId: string) => - spin(api.listExports(corpusId), `corpus/${corpusId}/exports`); + spin(api.listExports(corpusId), `corpus/${corpusId}/exports/list`); const downloadExports = (corpusId: string) => - spin(api.downloadExports(corpusId), `corpus/${corpusId}/exports`); + spin(api.downloadExports(corpusId), `corpus/${corpusId}/exports/download`); const downloadExportFiles = (corpusId: string, filename: string) => spin( api.downloadExportFile(corpusId, filename), - `corpus/${corpusId}/exports`, + `corpus/${corpusId}/exports/download`, ); const checkAdminMode = () => spin(api.adminModeStatus(), "admin-mode"); @@ -109,6 +117,7 @@ export default function useMinkBackend() { downloadPlaintext, uploadSources, deleteSource, + listSources, uploadMetadata, downloadMetadata, resourceInfoAll, diff --git a/src/api/corpusConfig.ts b/src/api/corpusConfig.ts index 6d10aca..acf96d2 100644 --- a/src/api/corpusConfig.ts +++ b/src/api/corpusConfig.ts @@ -1,4 +1,4 @@ -const yaml = import("js-yaml").then((m) => m.default); +const Yaml = import("js-yaml").then((m) => m.default); import type { ByLang } from "@/util.types"; import type { @@ -150,7 +150,7 @@ export async function makeConfig(id: string, options: ConfigOptions) { ); } - return (await yaml).dump(config as SparvConfig); + return (await Yaml).dump(config as SparvConfig); } export function emptyConfig(): ConfigOptions { @@ -167,7 +167,7 @@ export function emptyConfig(): ConfigOptions { * May throw all kinds of errors, the sky is the limit. */ export async function parseConfig(configYaml: string): Promise { - const config = (await yaml).load(configYaml) as any; + const config = (await Yaml).load(configYaml) as any; if (!config) throw new TypeError(`Parsing config failed, returned "${config}"`); diff --git a/src/auth/auth.composable.ts b/src/auth/auth.composable.ts index 83b0cee..6765ee3 100644 --- a/src/auth/auth.composable.ts +++ b/src/auth/auth.composable.ts @@ -32,7 +32,7 @@ const payload = ref(); export function useAuth() { const router = useRouter(); const route = useRoute(); - const { spin, pending } = useSpin(); + const { spin, isPending } = useSpin(); const { alert } = useMessenger(); const { t } = useI18n(); @@ -43,7 +43,7 @@ export function useAuth() { ); const canUserWrite = computed(() => isAuthenticated.value); /** Indicates whether a jwt request is currently loading. */ - const isAuthenticating = computed(() => pending.value.includes("jwt")); + const isAuthenticating = computed(() => isPending("jwt")); /** If not authenticated, redirect to the login page. */ async function requireAuthentication(callback?: () => void) { diff --git a/src/components/LayoutBox.vue b/src/components/LayoutBox.vue index b399cc4..f16e938 100644 --- a/src/components/LayoutBox.vue +++ b/src/components/LayoutBox.vue @@ -6,7 +6,7 @@ defineProps<{ diff --git a/src/components/MaxHeight.vue b/src/components/MaxHeight.vue new file mode 100644 index 0000000..301505a --- /dev/null +++ b/src/components/MaxHeight.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/corpus/CorpusOverview.vue b/src/corpus/CorpusOverview.vue index 3ca3c28..db01f00 100644 --- a/src/corpus/CorpusOverview.vue +++ b/src/corpus/CorpusOverview.vue @@ -4,7 +4,8 @@ import { useCorpusState } from "@/corpus/corpusState.composable"; import ConfigPanel from "@/corpus/config/ConfigPanel.vue"; import SourcesPanel from "@/corpus/sources/SourcesPanel.vue"; import JobStatus from "@/corpus/job/JobStatus.vue"; -import ExportsPanel from "@/corpus/exports/ExportsPanel.vue"; +import AnalysisPanel from "@/corpus/analysis/AnalysisPanel.vue"; +import ExplorePanel from "@/corpus/explore/ExplorePanel.vue"; import CorpusStateHelp from "@/corpus/CorpusStateHelp.vue"; import RouteButton from "@/components/RouteButton.vue"; import LayoutBox from "@/components/LayoutBox.vue"; @@ -14,13 +15,13 @@ const { isNeedingConfig, isNeedingMeta } = useCorpusState(corpusId); diff --git a/src/corpus/analysis/AnalysisPanel.vue b/src/corpus/analysis/AnalysisPanel.vue new file mode 100644 index 0000000..45ded7e --- /dev/null +++ b/src/corpus/analysis/AnalysisPanel.vue @@ -0,0 +1,106 @@ + + + diff --git a/src/corpus/config/ConfigPanel.vue b/src/corpus/config/ConfigPanel.vue index 44ab056..d050c77 100644 --- a/src/corpus/config/ConfigPanel.vue +++ b/src/corpus/config/ConfigPanel.vue @@ -39,7 +39,7 @@ const { th } = useLocale(); -

{{ $t("settings") }}

+

{{ $t("analysis") }}

diff --git a/src/corpus/config/CorpusConfiguration.vue b/src/corpus/config/CorpusConfiguration.vue index a4573cf..b378c51 100644 --- a/src/corpus/config/CorpusConfiguration.vue +++ b/src/corpus/config/CorpusConfiguration.vue @@ -265,12 +265,3 @@ async function submit(fields: Form) { - - diff --git a/src/corpus/exports/ExportsPanel.vue b/src/corpus/explore/ExplorePanel.vue similarity index 52% rename from src/corpus/exports/ExportsPanel.vue rename to src/corpus/explore/ExplorePanel.vue index 4cb2e1d..45511ef 100644 --- a/src/corpus/exports/ExportsPanel.vue +++ b/src/corpus/explore/ExplorePanel.vue @@ -1,45 +1,40 @@ diff --git a/src/corpus/exports/ToolPanel.vue b/src/corpus/explore/ToolPanel.vue similarity index 83% rename from src/corpus/exports/ToolPanel.vue rename to src/corpus/explore/ToolPanel.vue index 112347b..5623410 100644 --- a/src/corpus/exports/ToolPanel.vue +++ b/src/corpus/explore/ToolPanel.vue @@ -17,11 +17,11 @@ defineEmits<{