feat: translation flows, revision conflicts, delete scopes, article moves and a target site for new articles
This commit is contained in:
1 parent
339e646eb8
commit
45fbbc33b1
93 files changed
+7630
-294
No files matched your search
@@ -0,0 +1,149 @@
|
||||
import { watch, type Ref } from 'vue'
|
||||
import { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'
|
||||
import { locale, t } from '@/i18n'
|
||||
import { useLocalizedOverlay } from '@/i18n/presentation'
|
||||
import AddTranslationDialog, {
|
||||
type AddTranslationResult,
|
||||
} from '@/components/AddTranslationDialog.vue'
|
||||
import type { Article, CoverageEntry } from '@/composables/useArticles'
|
||||
import { ADD_TRANSLATION_DIALOG as DIALOG_NAME } from '@/lib/addTranslationLocation'
|
||||
import { holds } from '@/lib/editorCapabilities'
|
||||
import type { VersionRow } from '@/lib/editorVersions'
|
||||
import { languageName, type SiteLanguage } from '@/lib/siteLanguages'
|
||||
|
||||
interface TranslationOptions {
|
||||
article: Ref<Article | null>
|
||||
loaded: Ref<boolean>
|
||||
languages: () => SiteLanguage[]
|
||||
refetchLanguages: () => Promise<SiteLanguage[]>
|
||||
switchTo: (row: VersionRow, announcement?: string) => Promise<void>
|
||||
onGone: () => void
|
||||
}
|
||||
|
||||
function versionRowFor(id: number, lang: string): VersionRow {
|
||||
return {
|
||||
key: `version-${id}`,
|
||||
lang,
|
||||
name: languageName(lang, locale.value),
|
||||
code: lang.toUpperCase(),
|
||||
articleId: id,
|
||||
title: '',
|
||||
current: false,
|
||||
online: false,
|
||||
readOnly: false,
|
||||
languageDisabled: false,
|
||||
addTranslation: false,
|
||||
}
|
||||
}
|
||||
|
||||
function entryOf(created: Article, lang: string): CoverageEntry {
|
||||
return {
|
||||
id: created.id,
|
||||
lang,
|
||||
title: created.title,
|
||||
is_online: created.is_online,
|
||||
language_enabled: true,
|
||||
capabilities: created.capabilities,
|
||||
}
|
||||
}
|
||||
|
||||
export function useEditorTranslation(options: TranslationOptions) {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const overlay = useLocalizedOverlay()
|
||||
let instance: ReturnType<typeof overlay.create> | null = null
|
||||
|
||||
function strippedQuery(): LocationQueryRaw {
|
||||
const rest = { ...route.query }
|
||||
delete rest.dialog
|
||||
delete rest.lang
|
||||
return rest
|
||||
}
|
||||
|
||||
function stripParameters() {
|
||||
if (route.query.dialog !== undefined || route.query.lang !== undefined) {
|
||||
return router.replace({ query: strippedQuery() })
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
function open(lang?: string) {
|
||||
return router.push({
|
||||
query: { ...route.query, dialog: DIALOG_NAME, ...(lang ? { lang } : {}) },
|
||||
})
|
||||
}
|
||||
|
||||
async function settle(result: AddTranslationResult | undefined) {
|
||||
if (!result) {
|
||||
await stripParameters()
|
||||
return
|
||||
}
|
||||
if (result.kind === 'gone') {
|
||||
await stripParameters()
|
||||
options.onGone()
|
||||
return
|
||||
}
|
||||
await stripParameters()
|
||||
if (result.kind === 'open') {
|
||||
await options.switchTo(versionRowFor(result.id, result.lang))
|
||||
return
|
||||
}
|
||||
const current = options.article.value
|
||||
if (current) {
|
||||
options.article.value = {
|
||||
...current,
|
||||
translations: [
|
||||
...(current.translations ?? []),
|
||||
entryOf(result.article, result.lang),
|
||||
],
|
||||
}
|
||||
}
|
||||
const name = languageName(result.lang, locale.value)
|
||||
await options.switchTo(
|
||||
versionRowFor(result.article.id, result.lang),
|
||||
t('{0} draft created', [name]),
|
||||
)
|
||||
}
|
||||
|
||||
async function show(lang: string | undefined) {
|
||||
const created = overlay.create(AddTranslationDialog, {
|
||||
props: {
|
||||
get article() {
|
||||
return options.article.value!
|
||||
},
|
||||
get languages() {
|
||||
return options.languages()
|
||||
},
|
||||
initialLang: lang,
|
||||
refetchLanguages: options.refetchLanguages,
|
||||
},
|
||||
})
|
||||
instance = created
|
||||
const result = (await created.open()) as AddTranslationResult | undefined
|
||||
instance = null
|
||||
await settle(result)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [route.query.dialog, route.query.lang, options.loaded.value] as const,
|
||||
([dialog, lang, loaded]) => {
|
||||
if (!loaded) {
|
||||
return
|
||||
}
|
||||
if (dialog !== DIALOG_NAME) {
|
||||
instance?.close()
|
||||
return
|
||||
}
|
||||
if (!holds(options.article.value?.capabilities, 'create_translation')) {
|
||||
stripParameters()
|
||||
return
|
||||
}
|
||||
if (!instance) {
|
||||
show(typeof lang === 'string' ? lang : undefined)
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
return { open }
|
||||
}
|
||||
Reference in new issue
Block a user