Allow to export documents without children (#10909)

* Allow to export documents without children

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix tests

Signed-off-by: Artem Savchenko <armisav@gmail.com>

---------

Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Artyom Savchenko
2026-07-06 11:29:21 +05:00
committed by GitHub
parent d2e92134cc
commit 184b4ec08f
23 changed files with 268 additions and 36 deletions
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Pouze platné dokumenty",
"ExportFilterSkipArchivedObsolete": "Vše kromě archivovaných a zastaralých",
"ExportFilterAll": "Všechny dokumenty",
"ExportChildDocuments": "Exportovat podřízené dokumenty",
"ExportChildDocumentsDescription": "Také exportovat dokumenty připojené k vybraným",
"ExportResultRecordTitle": "Export dokumentů z pracovního prostoru {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Nur wirksame Dokumente exportieren",
"ExportFilterSkipArchivedObsolete": "Alle Dokumente außer archivierten und veralteten",
"ExportFilterAll": "Alle Dokumente",
"ExportChildDocuments": "Untergeordnete Dokumente exportieren",
"ExportChildDocumentsDescription": "Auch Dokumente exportieren, die an die ausgewählten angehängt sind",
"ExportResultRecordTitle": "Export von Dokumenten aus dem Arbeitsbereich {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Export only effective documents",
"ExportFilterSkipArchivedObsolete": "All documents except archived and obsolete",
"ExportFilterAll": "All documents",
"ExportChildDocuments": "Export child documents",
"ExportChildDocumentsDescription": "Also export documents attached to the selected ones",
"ExportResultRecordTitle": "Export of documents from {workspace} workspace ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Solo documentos efectivos",
"ExportFilterSkipArchivedObsolete": "Todos excepto archivados y obsoletos",
"ExportFilterAll": "Todos los documentos",
"ExportChildDocuments": "Exportar documentos secundarios",
"ExportChildDocumentsDescription": "Exportar también los documentos adjuntos a los seleccionados",
"ExportResultRecordTitle": "Exportación de documentos del espacio de trabajo {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Seulement les documents effectifs",
"ExportFilterSkipArchivedObsolete": "Tous sauf archivés et obsolètes",
"ExportFilterAll": "Tous les documents",
"ExportChildDocuments": "Exporter les documents enfants",
"ExportChildDocumentsDescription": "Exporter aussi les documents rattachés aux éléments sélectionnés",
"ExportResultRecordTitle": "Export de documents depuis l'espace de travail {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Solo documenti effettivi",
"ExportFilterSkipArchivedObsolete": "Tutti tranne archiviati e obsoleti",
"ExportFilterAll": "Tutti i documenti",
"ExportChildDocuments": "Esporta documenti figlio",
"ExportChildDocumentsDescription": "Esporta anche i documenti collegati a quelli selezionati",
"ExportResultRecordTitle": "Esportazione di documenti dallo spazio di lavoro {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "有効なドキュメントのみ",
"ExportFilterSkipArchivedObsolete": "アーカイブ・廃止を除くすべて",
"ExportFilterAll": "すべてのドキュメント",
"ExportChildDocuments": "子ドキュメントをエクスポート",
"ExportChildDocumentsDescription": "選択したドキュメントに添付されたドキュメントもエクスポートします",
"ExportResultRecordTitle": "ワークスペース {workspace} からのドキュメントのエクスポート ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "유효한 문서만",
"ExportFilterSkipArchivedObsolete": "보관/폐기 제외 전체",
"ExportFilterAll": "모든 문서",
"ExportChildDocuments": "하위 문서 내보내기",
"ExportChildDocumentsDescription": "선택한 문서에 첨부된 문서도 함께 내보냅니다",
"ExportResultRecordTitle": "{workspace} 워크스페이스 문서 내보내기 ({date})"
}
}
+2
View File
@@ -54,6 +54,8 @@
"ExportFilterEffectiveOnly": "Apenas documentos efetivos",
"ExportFilterSkipArchivedObsolete": "Todos exceto arquivados e obsoletos",
"ExportFilterAll": "Todos os documentos",
"ExportChildDocuments": "Exportar documentos filhos",
"ExportChildDocumentsDescription": "Exportar também os documentos anexados aos selecionados",
"ExportResultRecordTitle": "Exportação de documentos do espaço de trabalho {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Apenas documentos efetivos",
"ExportFilterSkipArchivedObsolete": "Todos exceto arquivados e obsoletos",
"ExportFilterAll": "Todos os documentos",
"ExportChildDocuments": "Exportar documentos filhos",
"ExportChildDocumentsDescription": "Exportar também os documentos anexados aos selecionados",
"ExportResultRecordTitle": "Exportação de documentos do espaço de trabalho {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Только действующие документы",
"ExportFilterSkipArchivedObsolete": "Все кроме архивных и устаревших",
"ExportFilterAll": "Все документы",
"ExportChildDocuments": "Экспортировать дочерние документы",
"ExportChildDocumentsDescription": "Также экспортировать документы, прикреплённые к выбранным",
"ExportResultRecordTitle": "Экспорт документов из пространства {workspace} ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "Yalnızca geçerli belgeler",
"ExportFilterSkipArchivedObsolete": "Arşivlenmiş ve geçersiz hariç tümü",
"ExportFilterAll": "Tüm belgeler",
"ExportChildDocuments": "Alt belgeleri dışa aktar",
"ExportChildDocumentsDescription": "Seçili belgelere ekli belgeleri de dışa aktar",
"ExportResultRecordTitle": "{workspace} çalışma alanından belge dışa aktarma ({date})"
}
}
+2
View File
@@ -53,6 +53,8 @@
"ExportFilterEffectiveOnly": "仅有效文档",
"ExportFilterSkipArchivedObsolete": "除已归档和已过时外的全部",
"ExportFilterAll": "全部文档",
"ExportChildDocuments": "导出子文档",
"ExportChildDocumentsDescription": "同时导出附加到所选文档上的文档",
"ExportResultRecordTitle": "从工作区 {workspace} 导出文档 ({date})"
}
}
@@ -25,7 +25,7 @@
type Class
} from '@hcengineering/core'
import { Card, getClient, getCurrentWorkspaceUuid } from '@hcengineering/presentation'
import { DropdownLabels, DropdownLabelsIntl, Label } from '@hcengineering/ui'
import { DropdownLabels, DropdownLabelsIntl, Label, ToggleWithLabel } from '@hcengineering/ui'
import { getResource } from '@hcengineering/platform'
import login from '@hcengineering/login'
import { shouldSkipDocument, isEffectiveDocument } from '@hcengineering/export'
@@ -52,6 +52,11 @@
type ExportFilterMode = 'effectiveOnly' | 'skipArchivedObsolete' | 'all'
let exportFilterMode: ExportFilterMode = 'effectiveOnly'
// Whether to recursively export child (collection) documents of the selected docs.
// Hidden and forced to true when exporting an entire space — the space already
// enumerates every document inside it.
let includeChildren: boolean = false
const exportFilterItems = [
{ id: 'effectiveOnly' as const, label: plugin.string.ExportFilterEffectiveOnly },
{ id: 'skipArchivedObsolete' as const, label: plugin.string.ExportFilterSkipArchivedObsolete },
@@ -142,6 +147,10 @@
const effectiveDocs = projectDocExport === true ? await getExportDocuments() : filteredSelectedDocs
// When exporting an entire space, child documents are picked up by the
// space-wide traversal — force the flag on regardless of UI state.
const effectiveIncludeChildren = spaceExport === true ? true : includeChildren
void exportToWorkspace(
_class,
exportQuery,
@@ -149,7 +158,8 @@
targetWorkspace,
undefined,
exportFilterMode === 'skipArchivedObsolete',
exportFilterMode === 'effectiveOnly'
exportFilterMode === 'effectiveOnly',
effectiveIncludeChildren
)
loading = false
dispatch('close', true)
@@ -191,5 +201,14 @@
<Label label={plugin.string.ExportFilterMode} />
</span>
<DropdownLabelsIntl items={exportFilterItems} bind:selected={exportFilterMode} kind="regular" size="large" />
{#if spaceExport !== true}
<div class="pl-2 py-4">
<ToggleWithLabel
label={plugin.string.ExportChildDocuments}
description={plugin.string.ExportChildDocumentsDescription}
bind:on={includeChildren}
/>
</div>
{/if}
</div>
</Card>
+4 -2
View File
@@ -26,7 +26,8 @@ export async function exportToWorkspace (
targetWorkspace: string | undefined,
relations?: RelationDefinition[] | undefined,
skipDeletedObsolete?: boolean,
exportOnlyEffective?: boolean
exportOnlyEffective?: boolean,
includeChildren?: boolean
): Promise<void> {
const lang = getCurrentLanguage()
@@ -73,7 +74,8 @@ export async function exportToWorkspace (
_class,
fieldMappers,
skipDeletedObsolete,
exportOnlyEffective
exportOnlyEffective,
includeChildren
}
if (relations != null) {
body.relations = relations
+3 -1
View File
@@ -56,6 +56,8 @@ export default mergeIds(exportId, exportPlugin, {
ExportFilterMode: '' as IntlString,
ExportFilterEffectiveOnly: '' as IntlString,
ExportFilterSkipArchivedObsolete: '' as IntlString,
ExportFilterAll: '' as IntlString
ExportFilterAll: '' as IntlString,
ExportChildDocuments: '' as IntlString,
ExportChildDocumentsDescription: '' as IntlString
}
})
@@ -127,7 +127,8 @@ describe('RelationExporter sourceClass', () => {
hierarchy,
lowLevel,
expect.any(Map),
relations
relations,
false
)
})
@@ -178,7 +179,8 @@ describe('RelationExporter sourceClass', () => {
hierarchy,
lowLevel,
expect.any(Map),
relations
relations,
false
)
})
@@ -219,7 +221,8 @@ describe('RelationExporter sourceClass', () => {
hierarchy,
lowLevel,
expect.any(Map),
relations
relations,
false
)
})
@@ -541,6 +541,149 @@ describe('CrossWorkspaceExporter', () => {
expect(attachedToArg).not.toBe(SOURCE_DOC_1)
}
})
it('should NOT export child collection documents when includeChildren is false', async () => {
const sourceSpace = createMockSpace(SOURCE_SPACE_ID, 'Test Space')
const parentDoc = createMockDoc(SOURCE_DOC_1, mockDocClass, SOURCE_SPACE_ID)
const attachedDoc = createMockAttachedDoc(
SOURCE_ATTACHED_1,
mockAttachedDocClass,
SOURCE_SPACE_ID,
SOURCE_DOC_1,
mockDocClass,
'children',
{ title: 'Attached Doc' }
)
const hierarchy = createMockHierarchy({
domains: new Map([
[mockDocClass, 'test_domain'],
[mockAttachedDocClass, 'test_domain'],
[core.class.Space, 'space_domain']
]),
isDerived: new Map([[mockAttachedDocClass, true]]),
attributes: new Map([
[
mockDocClass,
new Map([['children', { type: { _class: core.class.Collection, of: mockAttachedDocClass } }]])
],
[
mockAttachedDocClass,
new Map([
['attachedTo', { type: { _class: core.class.RefTo } }],
['attachedToClass', { type: { _class: 'core:class:TypeString' as Ref<Class<Doc>> } }],
['collection', { type: { _class: 'core:class:TypeString' as Ref<Class<Doc>> } }]
])
]
])
})
const lowLevelStorage = createMockLowLevelStorage(
new Map([
['test_domain', [parentDoc, attachedDoc]],
['space_domain', [sourceSpace]]
])
)
const targetClient = createMockTxOperations([], [], hierarchy)
const pipelineFactory = createMockPipelineFactory(hierarchy, lowLevelStorage)
const exporter = new CrossWorkspaceExporter(
mockContext,
pipelineFactory,
targetClient,
mockStorage,
undefined,
createWorkspaceIds('source-ws'),
createWorkspaceIds('target-ws')
)
// Query the parent class only — and explicitly opt OUT of child export.
const result = await exporter.export({
sourceWorkspace: createWorkspaceIds('source-ws'),
targetWorkspace: createWorkspaceIds('target-ws'),
sourceQuery: { _id: SOURCE_DOC_1 } as any,
_class: mockDocClass,
includeChildren: false
})
expect(result.success).toBe(true)
// The parent doc must be created via createDoc, but the attached collection
// item must NOT go through addCollection because includeChildren is false.
// eslint-disable-next-line @typescript-eslint/unbound-method
expect((targetClient.addCollection as jest.Mock).mock.calls.length).toBe(0)
})
it('should export child collection documents when includeChildren is true', async () => {
const sourceSpace = createMockSpace(SOURCE_SPACE_ID, 'Test Space')
const parentDoc = createMockDoc(SOURCE_DOC_1, mockDocClass, SOURCE_SPACE_ID)
const attachedDoc = createMockAttachedDoc(
SOURCE_ATTACHED_1,
mockAttachedDocClass,
SOURCE_SPACE_ID,
SOURCE_DOC_1,
mockDocClass,
'children',
{ title: 'Attached Doc' }
)
const hierarchy = createMockHierarchy({
domains: new Map([
[mockDocClass, 'test_domain'],
[mockAttachedDocClass, 'test_domain'],
[core.class.Space, 'space_domain']
]),
isDerived: new Map([[mockAttachedDocClass, true]]),
attributes: new Map([
[
mockDocClass,
new Map([['children', { type: { _class: core.class.Collection, of: mockAttachedDocClass } }]])
],
[
mockAttachedDocClass,
new Map([
['attachedTo', { type: { _class: core.class.RefTo } }],
['attachedToClass', { type: { _class: 'core:class:TypeString' as Ref<Class<Doc>> } }],
['collection', { type: { _class: 'core:class:TypeString' as Ref<Class<Doc>> } }]
])
]
])
})
const lowLevelStorage = createMockLowLevelStorage(
new Map([
['test_domain', [parentDoc, attachedDoc]],
['space_domain', [sourceSpace]]
])
)
const targetClient = createMockTxOperations([], [], hierarchy)
const pipelineFactory = createMockPipelineFactory(hierarchy, lowLevelStorage)
const exporter = new CrossWorkspaceExporter(
mockContext,
pipelineFactory,
targetClient,
mockStorage,
undefined,
createWorkspaceIds('source-ws'),
createWorkspaceIds('target-ws')
)
// Query the parent class only — and opt IN to recursive child export.
const result = await exporter.export({
sourceWorkspace: createWorkspaceIds('source-ws'),
targetWorkspace: createWorkspaceIds('target-ws'),
sourceQuery: { _id: SOURCE_DOC_1 } as any,
_class: mockDocClass,
includeChildren: true
})
expect(result.success).toBe(true)
// With the flag on, the attached collection item must be created via addCollection.
// eslint-disable-next-line @typescript-eslint/unbound-method
expect((targetClient.addCollection as jest.Mock).mock.calls.length).toBeGreaterThan(0)
})
})
describe('Forward Relations', () => {
+4 -1
View File
@@ -414,7 +414,8 @@ export function createServer (
relations: rawRelations,
fieldMappers,
skipDeletedObsolete,
exportOnlyEffective
exportOnlyEffective,
includeChildren
}: {
targetWorkspace: WorkspaceUuid
_class: Ref<Class<Doc>>
@@ -427,6 +428,7 @@ export function createServer (
fieldMappers?: Record<string, Record<string, any>>
skipDeletedObsolete?: boolean
exportOnlyEffective?: boolean
includeChildren?: boolean
} = req.body
// Validate required parameters
@@ -543,6 +545,7 @@ export function createServer (
fieldMappers,
skipDeletedObsolete: skipDeletedObsolete ?? true,
exportOnlyEffective: exportOnlyEffective ?? false,
includeChildren: includeChildren ?? false,
customHandlers: [createProductVersionHandler()]
}
@@ -75,7 +75,8 @@ export class DocumentExporter {
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage,
existingDocsMap: Map<Ref<Doc>, Doc>,
relations: RelationDefinition[]
relations: RelationDefinition[],
includeChildren: boolean = false
): Promise<boolean> {
if (this.state.processingDocs.has(doc._id)) {
return false
@@ -127,7 +128,8 @@ export class DocumentExporter {
conflictStrategy,
includeAttachments,
sourceHierarchy,
sourceLowLevel
sourceLowLevel,
includeChildren
)
// Create the document
@@ -145,7 +147,8 @@ export class DocumentExporter {
conflictStrategy,
includeAttachments,
sourceHierarchy,
sourceLowLevel
sourceLowLevel,
includeChildren
)
await this.exportSpaceRelations(
doc,
@@ -154,7 +157,8 @@ export class DocumentExporter {
includeAttachments,
sourceHierarchy,
sourceLowLevel,
relations
relations,
includeChildren
)
// Handle attachments
@@ -165,8 +169,12 @@ export class DocumentExporter {
// Handle collaborative content blobs (e.g., document content)
await this.attachmentExporter.exportCollaborativeContent(doc, sourceHierarchy)
// Handle collections (child documents)
await this.exportCollections(doc, targetId, sourceHierarchy, sourceLowLevel, relations)
// Handle collections (child documents) — only when explicitly requested.
// When disabled, only the top-level documents matched by the export query
// are exported and their attached collection items are skipped.
if (includeChildren) {
await this.exportCollections(doc, targetId, sourceHierarchy, sourceLowLevel, relations, includeChildren)
}
return true
} catch (err: any) {
@@ -230,7 +238,8 @@ export class DocumentExporter {
includeAttachments: boolean,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage,
relations: RelationDefinition[]
relations: RelationDefinition[],
includeChildren: boolean
): Promise<void> {
try {
if (this.relationExporter === undefined) {
@@ -256,7 +265,8 @@ export class DocumentExporter {
conflictStrategy,
includeAttachments,
sourceHierarchy,
sourceLowLevel
sourceLowLevel,
includeChildren
)
} catch (err: any) {
this.context.error(`Failed to export relations for space ${space}:`, {
@@ -310,7 +320,8 @@ export class DocumentExporter {
targetDocId: Ref<Doc>,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage,
relations: RelationDefinition[]
relations: RelationDefinition[],
includeChildren: boolean
): Promise<void> {
const attributes = sourceHierarchy.getAllAttributes(sourceDoc._class)
@@ -349,7 +360,8 @@ export class DocumentExporter {
sourceHierarchy,
sourceLowLevel,
new Map(),
relations
relations,
includeChildren
)
} catch (err: any) {
this.context.error(`Failed to export collection item ${collectionDoc._id}:`, {
@@ -34,7 +34,8 @@ export type ExportDocumentFn = (
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage,
existingDocsMap: Map<Ref<Doc>, Doc>,
relations: RelationDefinition[]
relations: RelationDefinition[],
includeChildren: boolean
) => Promise<boolean>
/**
@@ -56,7 +57,8 @@ export class RelationExporter {
conflictStrategy: 'skip' | 'duplicate',
includeAttachments: boolean,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage
sourceLowLevel: LowLevelStorage,
includeChildren: boolean = false
): Promise<void> {
for (const relation of relations) {
const direction = relation.direction ?? 'forward'
@@ -71,7 +73,8 @@ export class RelationExporter {
includeAttachments,
sourceHierarchy,
sourceLowLevel,
relations
relations,
includeChildren
)
} catch (err: any) {
this.context.error(`Failed to export forward relation ${relation.field} for document ${doc._id}:`, {
@@ -92,7 +95,8 @@ export class RelationExporter {
conflictStrategy: 'skip' | 'duplicate',
includeAttachments: boolean,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage
sourceLowLevel: LowLevelStorage,
includeChildren: boolean = false
): Promise<void> {
for (const relation of relations) {
const direction = relation.direction ?? 'forward'
@@ -107,7 +111,8 @@ export class RelationExporter {
includeAttachments,
sourceHierarchy,
sourceLowLevel,
relations
relations,
includeChildren
)
} catch (err: any) {
this.context.error(`Failed to export inverse relation ${relation.field} for document ${doc._id}:`, {
@@ -125,7 +130,8 @@ export class RelationExporter {
conflictStrategy: 'skip' | 'duplicate',
includeAttachments: boolean,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage
sourceLowLevel: LowLevelStorage,
includeChildren: boolean = false
): Promise<void> {
await this.exportForwardRelations(
doc,
@@ -133,7 +139,8 @@ export class RelationExporter {
conflictStrategy,
includeAttachments,
sourceHierarchy,
sourceLowLevel
sourceLowLevel,
includeChildren
)
await this.exportInverseRelations(
doc,
@@ -141,7 +148,8 @@ export class RelationExporter {
conflictStrategy,
includeAttachments,
sourceHierarchy,
sourceLowLevel
sourceLowLevel,
includeChildren
)
}
@@ -152,7 +160,8 @@ export class RelationExporter {
includeAttachments: boolean,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage,
relations: RelationDefinition[]
relations: RelationDefinition[],
includeChildren: boolean
): Promise<void> {
if (relation.sourceClass !== undefined && !sourceHierarchy.isDerived(doc._class, relation.sourceClass)) {
return
@@ -185,7 +194,8 @@ export class RelationExporter {
includeAttachments,
sourceHierarchy,
sourceLowLevel,
relations
relations,
includeChildren
)
}
}
@@ -197,7 +207,8 @@ export class RelationExporter {
includeAttachments: boolean,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage,
relations: RelationDefinition[]
relations: RelationDefinition[],
includeChildren: boolean
): Promise<void> {
if (relation.sourceClass !== undefined && !sourceHierarchy.isDerived(doc._class, relation.sourceClass)) {
return
@@ -232,7 +243,8 @@ export class RelationExporter {
sourceHierarchy,
sourceLowLevel,
new Map(),
relations
relations,
includeChildren
)
}
}
@@ -244,7 +256,8 @@ export class RelationExporter {
includeAttachments: boolean,
sourceHierarchy: Hierarchy,
sourceLowLevel: LowLevelStorage,
relations: RelationDefinition[]
relations: RelationDefinition[],
includeChildren: boolean
): Promise<void> {
if (this.state.idMapping.has(ref)) {
return
@@ -274,7 +287,8 @@ export class RelationExporter {
sourceHierarchy,
sourceLowLevel,
new Map(),
relations
relations,
includeChildren
)
}
}
@@ -84,6 +84,10 @@ export interface ExportOptions {
skipDeletedObsolete?: boolean
// Whether to export only documents with effective status
exportOnlyEffective?: boolean
// Whether to recursively export child (collection) documents of each exported doc.
// When false, only the documents matched by the top-level query are exported and
// their attached collection items are skipped.
includeChildren?: boolean
// Class-specific export handlers, applied before the default flow. Useful
// for collapsing or deduplicating documents (e.g. ProductVersion).
customHandlers?: CustomExportHandler[]
@@ -98,7 +98,8 @@ export class CrossWorkspaceExporter {
sourceHierarchy,
sourceLowLevel,
existingDocsMap,
relations
relations,
includeChildren
) => {
return await this.documentExporter.exportDocument(
doc,
@@ -107,7 +108,8 @@ export class CrossWorkspaceExporter {
sourceHierarchy,
sourceLowLevel,
existingDocsMap,
relations
relations,
includeChildren
)
}
)
@@ -128,6 +130,7 @@ export class CrossWorkspaceExporter {
fieldMappers = {},
skipDeletedObsolete = true,
exportOnlyEffective = false,
includeChildren = false,
customHandlers = []
} = options
@@ -258,7 +261,8 @@ export class CrossWorkspaceExporter {
hierarchy,
lowLevelStorage,
existingDocsMap,
resolvedRelations
resolvedRelations,
includeChildren
)
if (exported) {
result.exportedCount++