Files
huly-platform/plugins/controlled-documents-resources/src/components/document/DocumentDiffViewer.svelte
T
2024-12-19 16:49:45 +07:00

148 lines
4.5 KiB
Svelte

<script lang="ts">
import { getContext, onDestroy } from 'svelte'
import { getClient } from '@hcengineering/presentation'
import { makeDocCollabId, type Doc } from '@hcengineering/core'
import { CollaborationIds } from '@hcengineering/text-editor'
import {
CollaborationDiffViewer,
Provider,
StringDiffViewer,
createTiptapCollaborationData
} from '@hcengineering/text-editor-resources'
import { Dropdown, Label, ListItem, Loading, Scroller, themeStore } from '@hcengineering/ui'
import documents, {
ControlledDocument,
ControlledDocumentSnapshot,
ControlledDocumentState,
Document,
DocumentState
} from '@hcengineering/controlled-documents'
import plugin from '../../plugin'
import {
$controlledDocument as controlledDocument,
$comparedDocument as compareTo,
$documentComparisonVersions as documentComparisonVersions,
comparisonRequested
} from '../../stores/editors/document'
import { getTranslatedControlledDocStates, getTranslatedDocumentStates } from '../../utils'
import DocumentTitle from './DocumentTitle.svelte'
const client = getClient()
const hierarchy = client.getHierarchy()
const ydoc: any = getContext(CollaborationIds.Doc)
let comparedYdoc: any | undefined = undefined
let comparedProvider: Provider | undefined = undefined
let loading = true
const handleSelect = (event: CustomEvent<ListItem>) => {
const version = $documentComparisonVersions.find((item) => item._id === event.detail._id)
if (version) {
comparisonRequested(version)
}
}
let translatedStates: Readonly<Record<DocumentState | ControlledDocumentState, string>> | null = null
function getTranslatedLabels (lang: string) {
Promise.all([getTranslatedDocumentStates(lang), getTranslatedControlledDocStates(lang)]).then(
([states, controlledStates]) => {
translatedStates = {
...states,
...controlledStates
}
}
)
}
function isDocument (document: Doc | null): document is Document {
if (document == null) {
return false
}
return hierarchy.isDerived(document._class, documents.class.Document)
}
const generateVersionName = (
document: ControlledDocument | ControlledDocumentSnapshot,
translatedStates: Readonly<Record<DocumentState | ControlledDocumentState, string>> | null
): string => {
let state: ControlledDocumentState | DocumentState | undefined = document.controlledState
if (state == null) {
state = document.state ?? DocumentState.Draft
}
if (isDocument(document)) {
return `v${document.major}.${document.minor} | ${translatedStates ? translatedStates[state] : ''}`
} else {
return `${document.name} | ${translatedStates ? translatedStates[state] : ''}`
}
}
$: getTranslatedLabels($themeStore.language)
$: versionItems = $documentComparisonVersions.map((version) => ({
_id: version._id,
label: generateVersionName(version, translatedStates)
}))
$: if ($compareTo) {
if (comparedProvider) {
comparedProvider.destroy()
}
loading = true
const compareToDoc = makeDocCollabId($compareTo, 'content')
const data = createTiptapCollaborationData(compareToDoc, $compareTo.content)
comparedYdoc = data.ydoc
comparedProvider = data.provider
void comparedProvider.loaded.then(() => (loading = false))
}
onDestroy(() => {
void comparedProvider?.destroy()
})
</script>
<div class="flex flex-gap-2 h-12 pl-7 items-center bottom-divider">
<Label label={plugin.string.Compare} />
<Dropdown
items={versionItems}
disabled
selected={versionItems.find((item) => item._id === $controlledDocument?._id)}
withSearch={false}
placeholder={documents.string.Version}
/>
<Label label={plugin.string.Against} />
<Dropdown
items={versionItems}
selected={versionItems.find((item) => item._id === $compareTo?._id)}
withSearch={false}
placeholder={documents.string.Version}
on:selected={handleSelect}
/>
</div>
{#if loading}
<Loading />
{:else}
<Scroller>
<div class="root">
<DocumentTitle>
<StringDiffViewer
value={$controlledDocument?.title ?? ''}
compareTo={(isDocument($compareTo) ? $compareTo : $controlledDocument)?.title ?? ''}
/>
</DocumentTitle>
<CollaborationDiffViewer field="content" comparedField="content" {ydoc} {comparedYdoc} />
<div class="bottomSpacing" />
</div>
</Scroller>
{/if}
<style lang="scss">
.root {
padding: 0 3.25rem;
}
.bottomSpacing {
padding-bottom: 30vh;
}
</style>