mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-17 18:05:42 +02:00
feat: Add import notifications (#10464)
* feat: Add import notifications Signed-off-by: Artem Savchenko <armisav@gmail.com> * Fix svelte check Signed-off-by: Artem Savchenko <armisav@gmail.com> --------- Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Generated
+27
@@ -8067,9 +8067,18 @@ importers:
|
||||
'@hcengineering/model-core':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../core
|
||||
'@hcengineering/model-notification':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../notification
|
||||
'@hcengineering/model-presentation':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../presentation
|
||||
'@hcengineering/model-view':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../view
|
||||
'@hcengineering/notification':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../plugins/notification
|
||||
'@hcengineering/platform':
|
||||
specifier: workspace:^0.7.19
|
||||
version: link:../../foundations/core/packages/platform
|
||||
@@ -8079,6 +8088,9 @@ importers:
|
||||
'@hcengineering/ui':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../packages/ui
|
||||
'@hcengineering/view':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../plugins/view
|
||||
'@hcengineering/workbench':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../plugins/workbench
|
||||
@@ -20563,6 +20575,9 @@ importers:
|
||||
'@hcengineering/core':
|
||||
specifier: workspace:^0.7.24
|
||||
version: link:../../foundations/core/packages/core
|
||||
'@hcengineering/notification':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../notification
|
||||
'@hcengineering/platform':
|
||||
specifier: workspace:^0.7.19
|
||||
version: link:../../foundations/core/packages/platform
|
||||
@@ -20679,6 +20694,12 @@ importers:
|
||||
'@hcengineering/login':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../login
|
||||
'@hcengineering/notification':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../notification
|
||||
'@hcengineering/panel':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../packages/panel
|
||||
'@hcengineering/platform':
|
||||
specifier: workspace:^0.7.19
|
||||
version: link:../../foundations/core/packages/platform
|
||||
@@ -20691,6 +20712,12 @@ importers:
|
||||
'@hcengineering/ui':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../../packages/ui
|
||||
'@hcengineering/view':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../view
|
||||
'@hcengineering/view-resources':
|
||||
specifier: workspace:^0.7.0
|
||||
version: link:../view-resources
|
||||
svelte:
|
||||
specifier: ^4.2.20
|
||||
version: 4.2.20
|
||||
|
||||
@@ -42,7 +42,11 @@
|
||||
"@hcengineering/workbench": "workspace:^0.7.0",
|
||||
"@hcengineering/presentation": "workspace:^0.7.0",
|
||||
"@hcengineering/model-presentation": "workspace:^0.7.0",
|
||||
"@hcengineering/model-view": "workspace:^0.7.0",
|
||||
"@hcengineering/model-notification": "workspace:^0.7.0",
|
||||
"@hcengineering/export-resources": "workspace:^0.7.0",
|
||||
"@hcengineering/export": "workspace:^0.7.0"
|
||||
"@hcengineering/export": "workspace:^0.7.0",
|
||||
"@hcengineering/view": "workspace:^0.7.0",
|
||||
"@hcengineering/notification": "workspace:^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,24 +13,94 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Builder } from '@hcengineering/model'
|
||||
import core from '@hcengineering/model-core'
|
||||
import type { Class, Doc, Domain, Ref } from '@hcengineering/core'
|
||||
import type { ExportResultRecord } from '@hcengineering/export'
|
||||
import { type Builder, Model, Prop, ArrOf, TypeRef, TypeString, TypeNumber, UX } from '@hcengineering/model'
|
||||
import core, { TDoc } from '@hcengineering/model-core'
|
||||
import presentation from '@hcengineering/model-presentation'
|
||||
import workbench from '@hcengineering/workbench'
|
||||
import exportPlugin from './plugin'
|
||||
import view from '@hcengineering/model-view'
|
||||
import notification from '@hcengineering/notification'
|
||||
import exportPlugin from '@hcengineering/export'
|
||||
|
||||
import exportModelPlugin from './plugin'
|
||||
|
||||
export { exportId } from '@hcengineering/export'
|
||||
export * from './migration'
|
||||
export default exportPlugin
|
||||
export default exportModelPlugin
|
||||
|
||||
export const DOMAIN_EXPORT = 'export' as Domain
|
||||
|
||||
@Model(exportPlugin.class.ExportResultRecord, core.class.Doc, DOMAIN_EXPORT)
|
||||
@UX(exportPlugin.string.ImportCompleted, exportPlugin.icon.Export)
|
||||
export class TExportResultRecord extends TDoc implements ExportResultRecord {
|
||||
@Prop(TypeString(), exportPlugin.string.SourceWorkspace)
|
||||
sourceWorkspace!: string
|
||||
|
||||
@Prop(TypeString(), exportPlugin.string.TargetWorkspace)
|
||||
targetWorkspace!: string
|
||||
|
||||
@Prop(TypeNumber(), exportPlugin.string.ExportedCount)
|
||||
exportedCount!: number
|
||||
|
||||
@Prop(ArrOf(TypeRef(core.class.Doc)), exportPlugin.string.ExportedDocumentIds)
|
||||
exportedDocumentIds!: Ref<Doc>[]
|
||||
|
||||
@Prop(TypeRef(core.class.Class), exportPlugin.string.ExportedDocumentClass)
|
||||
objectClass!: Ref<Class<Doc>>
|
||||
|
||||
@Prop(TypeString(), view.string.Title)
|
||||
title?: string
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TExportResultRecord)
|
||||
|
||||
builder.mixin(exportPlugin.class.ExportResultRecord, core.class.Class, view.mixin.ObjectPresenter, {
|
||||
presenter: view.component.BaseDocPresenter
|
||||
})
|
||||
|
||||
builder.mixin(exportPlugin.class.ExportResultRecord, core.class.Class, view.mixin.ObjectPanel, {
|
||||
component: exportPlugin.component.ExportResultPanel
|
||||
})
|
||||
|
||||
builder.mixin(exportPlugin.class.ExportResultRecord, core.class.Class, view.mixin.ObjectTitle, {
|
||||
titleProvider: exportPlugin.function.ExportResultTitleProvider
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationGroup,
|
||||
core.space.Model,
|
||||
{
|
||||
label: exportPlugin.string.Import,
|
||||
icon: exportPlugin.icon.Export,
|
||||
objectClass: exportPlugin.class.ExportResultRecord
|
||||
},
|
||||
exportPlugin.ids.ImportNotificationGroup
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
notification.class.NotificationType,
|
||||
core.space.Model,
|
||||
{
|
||||
hidden: false,
|
||||
generated: false,
|
||||
label: exportPlugin.string.ImportedDocuments,
|
||||
group: exportPlugin.ids.ImportNotificationGroup,
|
||||
txClasses: [],
|
||||
objectClass: exportPlugin.class.ExportResultRecord,
|
||||
defaultEnabled: true
|
||||
},
|
||||
exportPlugin.ids.ImportedDocumentsNotification
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
presentation.class.ComponentPointExtension,
|
||||
core.space.Model,
|
||||
{
|
||||
extension: workbench.extensions.SpecialViewAction,
|
||||
component: exportPlugin.component.ExportButton
|
||||
component: exportModelPlugin.component.ExportButton
|
||||
},
|
||||
exportPlugin.extensions.ExportButton
|
||||
exportModelPlugin.extensions.ExportButton
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Export zahájen. Až bude dokončen, obdržíte oznámení.",
|
||||
"ExportToWorkspaceCompleted": "Export dokončen",
|
||||
"ExportToWorkspaceCompletedMessage": "Export byl úspěšně dokončen.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} dokumentů importováno do vašeho pracovního prostoru",
|
||||
"ImportCompleted": "Dokumenty importovány do pracovního prostoru",
|
||||
"SourceWorkspace": "Zdrojový pracovní prostor",
|
||||
"ExportedCount": "Počet exportovaných",
|
||||
"ExportedDocumentIds": "ID exportovaných dokumentů",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 dokument byl importován z pracovního prostoru {workspace}} other {# dokumentů bylo importováno z pracovního prostoru {workspace}}}:",
|
||||
"ExportedDocumentClass": "Třída exportovaných dokumentů",
|
||||
"Import": "Import",
|
||||
"ImportedDocuments": "Nové dokumenty",
|
||||
"ExportToWorkspaceFailed": "Export se nezdařil",
|
||||
"SelectWorkspace": "Vybrat pracovní prostor",
|
||||
"SelectWorkspaceToExport": "Vybrat pracovní prostor pro export {count, plural, =1 {1 dokument} other {# dokumentů}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Vybrat prostor",
|
||||
"NoSelectedDocuments": "Žádné dokumenty nevybrány",
|
||||
"RequestPermissionToImport": "Prosím, požádejte vlastníka cílového pracovního prostoru o povolení k importu dokumentů.",
|
||||
"SkipDeletedObsolete": "Přeskočit archivované nebo zastaralé dokumenty"
|
||||
"SkipDeletedObsolete": "Přeskočit archivované nebo zastaralé dokumenty",
|
||||
"ExportResultRecordTitle": "Export dokumentů z pracovního prostoru {workspace} ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Export gestartet. Sie erhalten eine Benachrichtigung, wenn der Export abgeschlossen ist.",
|
||||
"ExportToWorkspaceCompleted": "Export abgeschlossen",
|
||||
"ExportToWorkspaceCompletedMessage": "Export erfolgreich abgeschlossen.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} Dokumente in Ihren Arbeitsbereich importiert",
|
||||
"ImportCompleted": "Dokumente in Arbeitsbereich importiert",
|
||||
"SourceWorkspace": "Quell-Arbeitsbereich",
|
||||
"ExportedCount": "Exportierte Anzahl",
|
||||
"ExportedDocumentIds": "IDs exportierter Dokumente",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 Dokument wurde aus dem Arbeitsbereich {workspace} importiert} other {# Dokumente wurden aus dem Arbeitsbereich {workspace} importiert}}:",
|
||||
"ExportedDocumentClass": "Klasse exportierter Dokumente",
|
||||
"Import": "Import",
|
||||
"ImportedDocuments": "Neue Dokumente",
|
||||
"ExportToWorkspaceFailed": "Export fehlgeschlagen",
|
||||
"SelectWorkspace": "Arbeitsbereich auswählen",
|
||||
"SelectWorkspaceToExport": "Arbeitsbereich zum Exportieren von {count, plural, =1 {1 Dokument} other {# Dokumenten}} auswählen",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Bereich auswählen",
|
||||
"NoSelectedDocuments": "Keine Dokumente ausgewählt",
|
||||
"RequestPermissionToImport": "Bitte fordern Sie die Berechtigung vom Eigentümer des Ziel-Arbeitsbereichs an, um Dokumente zu importieren.",
|
||||
"SkipDeletedObsolete": "Archivierte oder veraltete Dokumente überspringen"
|
||||
"SkipDeletedObsolete": "Archivierte oder veraltete Dokumente überspringen",
|
||||
"ExportResultRecordTitle": "Export von Dokumenten aus dem Arbeitsbereich {workspace} ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Export started. You will receive a notification when it completes.",
|
||||
"ExportToWorkspaceCompleted": "Export completed",
|
||||
"ExportToWorkspaceCompletedMessage": "Export completed successfully.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} documents imported to your workspace",
|
||||
"ImportCompleted": "Documents imported to workspace",
|
||||
"SourceWorkspace": "Source workspace",
|
||||
"ExportedCount": "Exported count",
|
||||
"ExportedDocumentIds": "Exported document IDs",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 document was imported from {workspace} workspace} other {# documents were imported from {workspace} workspace}}:",
|
||||
"ExportedDocumentClass": "Exported document class",
|
||||
"Import": "Import",
|
||||
"ImportedDocuments": "New documents",
|
||||
"ExportToWorkspaceFailed": "Export failed",
|
||||
"SelectWorkspace": "Select workspace",
|
||||
"SelectWorkspaceToExport": "Select workspace to export {count, plural, =1 {1 document} other {# documents}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Select space",
|
||||
"NoSelectedDocuments": "No documents selected",
|
||||
"RequestPermissionToImport": "Please request permission from the target workspace owner to import documents.",
|
||||
"SkipDeletedObsolete": "Skip archived or obsolete documents"
|
||||
"SkipDeletedObsolete": "Skip archived or obsolete documents",
|
||||
"ExportResultRecordTitle": "Export of documents from {workspace} workspace ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Exportación iniciada. Recibirá una notificación cuando se complete.",
|
||||
"ExportToWorkspaceCompleted": "Exportación completada",
|
||||
"ExportToWorkspaceCompletedMessage": "Exportación completada exitosamente.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} documentos importados a su espacio de trabajo",
|
||||
"ImportCompleted": "Documentos importados al espacio de trabajo",
|
||||
"SourceWorkspace": "Espacio de trabajo de origen",
|
||||
"ExportedCount": "Cantidad exportada",
|
||||
"ExportedDocumentIds": "ID de documentos exportados",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 documento fue importado desde el espacio de trabajo {workspace}} other {# documentos fueron importados desde el espacio de trabajo {workspace}}}:",
|
||||
"ExportedDocumentClass": "Clase de documentos exportados",
|
||||
"Import": "Importar",
|
||||
"ImportedDocuments": "Documentos nuevos",
|
||||
"ExportToWorkspaceFailed": "Exportación fallida",
|
||||
"SelectWorkspace": "Seleccionar espacio de trabajo",
|
||||
"SelectWorkspaceToExport": "Seleccionar espacio de trabajo para exportar {count, plural, =1 {1 documento} other {# documentos}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Seleccionar espacio",
|
||||
"NoSelectedDocuments": "No hay documentos seleccionados",
|
||||
"RequestPermissionToImport": "Por favor, solicite permiso al propietario del espacio de trabajo de destino para importar documentos.",
|
||||
"SkipDeletedObsolete": "Omitir documentos archivados u obsoletos"
|
||||
"SkipDeletedObsolete": "Omitir documentos archivados u obsoletos",
|
||||
"ExportResultRecordTitle": "Exportación de documentos del espacio de trabajo {workspace} ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Exportation démarrée. Vous recevrez une notification une fois terminée.",
|
||||
"ExportToWorkspaceCompleted": "Exportation terminée",
|
||||
"ExportToWorkspaceCompletedMessage": "Exportation terminée avec succès.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} documents importés dans votre espace de travail",
|
||||
"ImportCompleted": "Documents importés dans l'espace de travail",
|
||||
"SourceWorkspace": "Espace de travail source",
|
||||
"ExportedCount": "Nombre exporté",
|
||||
"ExportedDocumentIds": "ID des documents exportés",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 document a été importé depuis l'espace de travail {workspace}} other {# documents ont été importés depuis l'espace de travail {workspace}}}:",
|
||||
"ExportedDocumentClass": "Classe des documents exportés",
|
||||
"Import": "Import",
|
||||
"ImportedDocuments": "Nouveaux documents",
|
||||
"ExportToWorkspaceFailed": "Exportation échouée",
|
||||
"SelectWorkspace": "Sélectionner l'espace de travail",
|
||||
"SelectWorkspaceToExport": "Sélectionner l'espace de travail pour exporter {count, plural, =1 {1 document} other {# documents}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Sélectionner l'espace",
|
||||
"NoSelectedDocuments": "Aucun document sélectionné",
|
||||
"RequestPermissionToImport": "Veuillez demander l'autorisation au propriétaire de l'espace de travail cible pour importer des documents.",
|
||||
"SkipDeletedObsolete": "Ignorer les documents archivés ou obsolètes"
|
||||
"SkipDeletedObsolete": "Ignorer les documents archivés ou obsolètes",
|
||||
"ExportResultRecordTitle": "Export de documents depuis l'espace de travail {workspace} ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Esportazione avviata. Riceverai una notifica quando sarà completata.",
|
||||
"ExportToWorkspaceCompleted": "Esportazione completata",
|
||||
"ExportToWorkspaceCompletedMessage": "Esportazione completata con successo.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} documenti importati nel tuo spazio di lavoro",
|
||||
"ImportCompleted": "Documenti importati nell'area di lavoro",
|
||||
"SourceWorkspace": "Spazio di lavoro di origine",
|
||||
"ExportedCount": "Conteggio esportato",
|
||||
"ExportedDocumentIds": "ID documenti esportati",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 documento è stato importato dallo spazio di lavoro {workspace}} other {# documenti sono stati importati dallo spazio di lavoro {workspace}}}:",
|
||||
"ExportedDocumentClass": "Classe documenti esportati",
|
||||
"Import": "Importa",
|
||||
"ImportedDocuments": "Nuovi documenti",
|
||||
"ExportToWorkspaceFailed": "Esportazione fallita",
|
||||
"SelectWorkspace": "Seleziona spazio di lavoro",
|
||||
"SelectWorkspaceToExport": "Seleziona spazio di lavoro per esportare {count, plural, =1 {1 documento} other {# documenti}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Seleziona spazio",
|
||||
"NoSelectedDocuments": "Nessun documento selezionato",
|
||||
"RequestPermissionToImport": "Si prega di richiedere l'autorizzazione al proprietario dello spazio di lavoro di destinazione per importare documenti.",
|
||||
"SkipDeletedObsolete": "Salta documenti archivati o obsoleti"
|
||||
"SkipDeletedObsolete": "Salta documenti archivati o obsoleti",
|
||||
"ExportResultRecordTitle": "Esportazione di documenti dallo spazio di lavoro {workspace} ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "エクスポートを開始しました。完了すると通知が届きます。",
|
||||
"ExportToWorkspaceCompleted": "エクスポート完了",
|
||||
"ExportToWorkspaceCompletedMessage": "エクスポートが正常に完了しました。",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} 件のドキュメントがワークスペースにインポートされました",
|
||||
"ImportCompleted": "ドキュメントがワークスペースにインポートされました",
|
||||
"SourceWorkspace": "ソースワークスペース",
|
||||
"ExportedCount": "エクスポート数",
|
||||
"ExportedDocumentIds": "エクスポートされたドキュメントのID",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 件のドキュメントがワークスペース {workspace} からインポートされました} other {# 件のドキュメントがワークスペース {workspace} からインポートされました}}:",
|
||||
"ExportedDocumentClass": "エクスポートされたドキュメントのクラス",
|
||||
"Import": "インポート",
|
||||
"ImportedDocuments": "新しいドキュメント",
|
||||
"ExportToWorkspaceFailed": "エクスポート失敗",
|
||||
"SelectWorkspace": "ワークスペースを選択",
|
||||
"SelectWorkspaceToExport": "{count, plural, =1 {1 件のドキュメント} other {# 件のドキュメント}}をエクスポートするワークスペースを選択",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "スペースを選択",
|
||||
"NoSelectedDocuments": "ドキュメントが選択されていません",
|
||||
"RequestPermissionToImport": "ドキュメントをインポートするには、対象ワークスペースの所有者に許可をリクエストしてください。",
|
||||
"SkipDeletedObsolete": "アーカイブ済みまたは廃止されたドキュメントをスキップ"
|
||||
"SkipDeletedObsolete": "アーカイブ済みまたは廃止されたドキュメントをスキップ",
|
||||
"ExportResultRecordTitle": "ワークスペース {workspace} からのドキュメントのエクスポート ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Exportação iniciada. Você receberá uma notificação quando for concluída.",
|
||||
"ExportToWorkspaceCompleted": "Exportação concluída",
|
||||
"ExportToWorkspaceCompletedMessage": "Exportação concluída com sucesso.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} documentos importados para o seu espaço de trabalho",
|
||||
"ImportCompleted": "Documentos importados para o espaço de trabalho",
|
||||
"SourceWorkspace": "Espaço de trabalho de origem",
|
||||
"ExportedCount": "Quantidade exportada",
|
||||
"ExportedDocumentIds": "IDs dos documentos exportados",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 documento foi importado do espaço de trabalho {workspace}} other {# documentos foram importados do espaço de trabalho {workspace}}}:",
|
||||
"ExportedDocumentClass": "Classe dos documentos exportados",
|
||||
"Import": "Importar",
|
||||
"ImportedDocuments": "Novos documentos",
|
||||
"ExportToWorkspaceFailed": "Exportação falhou",
|
||||
"SelectWorkspace": "Selecionar espaço de trabalho",
|
||||
"SelectWorkspaceToExport": "Selecionar espaço de trabalho para exportar {count, plural, =1 {1 documento} other {# documentos}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Selecionar espaço",
|
||||
"NoSelectedDocuments": "Nenhum documento selecionado",
|
||||
"RequestPermissionToImport": "Por favor, solicite permissão ao proprietário do espaço de trabalho de destino para importar documentos.",
|
||||
"SkipDeletedObsolete": "Pular documentos arquivados ou obsoletos"
|
||||
"SkipDeletedObsolete": "Pular documentos arquivados ou obsoletos",
|
||||
"ExportResultRecordTitle": "Exportação de documentos do espaço de trabalho {workspace} ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Экспорт начат. Вы получите уведомление, когда он будет завершен.",
|
||||
"ExportToWorkspaceCompleted": "Экспорт завершен",
|
||||
"ExportToWorkspaceCompletedMessage": "Экспорт успешно завершен.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} документов импортировано в ваше рабочее пространство",
|
||||
"ImportCompleted": "Документы импортированы в рабочее пространство",
|
||||
"SourceWorkspace": "Исходное рабочее пространство",
|
||||
"ExportedCount": "Количество экспортированных",
|
||||
"ExportedDocumentIds": "ID экспортированных документов",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 документ импортирован из рабочего пространства {workspace}} few {# документа импортированы из рабочего пространства {workspace}} other {# документов импортировано из рабочего пространства {workspace}}}:",
|
||||
"ExportedDocumentClass": "Класс экспортированных документов",
|
||||
"Import": "Импорт",
|
||||
"ImportedDocuments": "Новые документы",
|
||||
"ExportToWorkspaceFailed": "Экспорт не удался",
|
||||
"SelectWorkspace": "Выбрать рабочее пространство",
|
||||
"SelectWorkspaceToExport": "Выбрать рабочее пространство для экспорта {count, plural, =1 {1 документ} one {# документ} few {# документа} other {# документов}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Выбрать пространство",
|
||||
"NoSelectedDocuments": "Документы не выбраны",
|
||||
"RequestPermissionToImport": "Пожалуйста, запросите разрешение у владельца рабочего пространства, куда вы хотите экспортировать документы.",
|
||||
"SkipDeletedObsolete": "Пропускать архивированные или устаревшие документы"
|
||||
"SkipDeletedObsolete": "Пропускать архивированные или устаревшие документы",
|
||||
"ExportResultRecordTitle": "Экспорт документов из пространства {workspace} ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "Dışa aktarma başladı. Tamamlandığında bir bildirim alacaksınız.",
|
||||
"ExportToWorkspaceCompleted": "Dışa aktarma tamamlandı",
|
||||
"ExportToWorkspaceCompletedMessage": "Dışa aktarma başarıyla tamamlandı.",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} belge çalışma alanınıza içe aktarıldı",
|
||||
"ImportCompleted": "Belgeler çalışma alanına içe aktarıldı",
|
||||
"SourceWorkspace": "Kaynak çalışma alanı",
|
||||
"ExportedCount": "Dışa aktarılan sayı",
|
||||
"ExportedDocumentIds": "Dışa aktarılan belge kimlikleri",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 belge {workspace} çalışma alanından içe aktarıldı} other {# belge {workspace} çalışma alanından içe aktarıldı}}:",
|
||||
"ExportedDocumentClass": "Dışa aktarılan belge sınıfı",
|
||||
"Import": "İçe aktarma",
|
||||
"ImportedDocuments": "Yeni belgeler",
|
||||
"ExportToWorkspaceFailed": "Dışa aktarma başarısız oldu",
|
||||
"SelectWorkspace": "Çalışma alanı seç",
|
||||
"SelectWorkspaceToExport": "{count, plural, =1 {1 belgeyi} other {# belgeyi}} dışa aktarmak için çalışma alanı seç",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "Alan seç",
|
||||
"NoSelectedDocuments": "Seçili belge yok",
|
||||
"RequestPermissionToImport": "Belgeleri içe aktarmak için lütfen hedef çalışma alanı sahibinden izin isteyin.",
|
||||
"SkipDeletedObsolete": "Arşivlenmiş veya kullanımdan kaldırılmış belgeleri atla"
|
||||
"SkipDeletedObsolete": "Arşivlenmiş veya kullanımdan kaldırılmış belgeleri atla",
|
||||
"ExportResultRecordTitle": "{workspace} çalışma alanından belge dışa aktarma ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
"ExportStartedMessage": "导出已开始。完成后您将收到通知。",
|
||||
"ExportToWorkspaceCompleted": "导出完成",
|
||||
"ExportToWorkspaceCompletedMessage": "导出已成功完成。",
|
||||
"ImportToWorkspaceNotificationMessage": "{count} 个文档已导入到您的工作区",
|
||||
"ImportCompleted": "文档已导入到工作区",
|
||||
"SourceWorkspace": "源工作区",
|
||||
"ExportedCount": "导出数量",
|
||||
"ExportedDocumentIds": "已导出文档的 ID",
|
||||
"DocumentsImportedFromWorkspace": "{count, plural, one {1 个文档已从工作区 {workspace} 导入} other {# 个文档已从工作区 {workspace} 导入}}:",
|
||||
"ExportedDocumentClass": "已导出文档的类",
|
||||
"Import": "导入",
|
||||
"ImportedDocuments": "新文档",
|
||||
"ExportToWorkspaceFailed": "导出失败",
|
||||
"SelectWorkspace": "选择工作区",
|
||||
"SelectWorkspaceToExport": "选择工作区以导出 {count, plural, =1 {1 文档} other {# 个文档}}",
|
||||
@@ -38,6 +47,7 @@
|
||||
"SelectSpace": "选择空间",
|
||||
"NoSelectedDocuments": "未选择文档",
|
||||
"RequestPermissionToImport": "请向目标工作区所有者请求导入文档的权限。",
|
||||
"SkipDeletedObsolete": "跳过已归档或已过时的文档"
|
||||
"SkipDeletedObsolete": "跳过已归档或已过时的文档",
|
||||
"ExportResultRecordTitle": "从工作区 {workspace} 导出文档 ({date})"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
"@hcengineering/ui": "workspace:^0.7.0",
|
||||
"@hcengineering/export": "workspace:^0.7.0",
|
||||
"@hcengineering/login": "workspace:^0.7.0",
|
||||
"@hcengineering/theme": "workspace:^0.7.0"
|
||||
"@hcengineering/notification": "workspace:^0.7.0",
|
||||
"@hcengineering/panel": "workspace:^0.7.0",
|
||||
"@hcengineering/theme": "workspace:^0.7.0",
|
||||
"@hcengineering/view": "workspace:^0.7.0",
|
||||
"@hcengineering/view-resources": "workspace:^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { type Class, type Doc, type Ref } from '@hcengineering/core'
|
||||
import exportPlugin, { type ExportResultRecord } from '@hcengineering/export'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { Panel } from '@hcengineering/panel'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Button, IconMoreH, Label } from '@hcengineering/ui'
|
||||
import { DocNavLink, ObjectPresenter, showMenu } from '@hcengineering/view-resources'
|
||||
import view from '@hcengineering/view'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
|
||||
export let _id: Ref<ExportResultRecord>
|
||||
export let _class: Ref<Class<ExportResultRecord>>
|
||||
export let embedded: boolean = false
|
||||
|
||||
const query = createQuery()
|
||||
const docsQuery = createQuery()
|
||||
const inboxClient = getResource(notification.function.GetInboxNotificationsClient).then((res) => res())
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let object: ExportResultRecord | undefined = undefined
|
||||
let lastId: Ref<Doc> | undefined = undefined
|
||||
let exportedDocs: Doc[] = []
|
||||
|
||||
$: query.query(_class, { _id }, (result) => {
|
||||
object = result[0]
|
||||
})
|
||||
|
||||
$: docClass = object?.objectClass ?? core.class.Doc
|
||||
$: hasExportedDocs = (object?.exportedDocumentIds?.length ?? 0) > 0
|
||||
$: if (hasExportedDocs && object != null) {
|
||||
docsQuery.query(docClass, { _id: { $in: object.exportedDocumentIds } }, (result) => {
|
||||
exportedDocs = result
|
||||
})
|
||||
} else {
|
||||
docsQuery.unsubscribe()
|
||||
exportedDocs = []
|
||||
}
|
||||
|
||||
$: if (object?._id !== lastId) {
|
||||
const prev = lastId
|
||||
lastId = object?._id
|
||||
if (prev !== undefined) {
|
||||
void inboxClient.then((c) => {
|
||||
void c.readDoc(prev)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
void inboxClient.then((c) => {
|
||||
if (_id !== undefined) void c.readDoc(_id)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if object}
|
||||
<Panel
|
||||
isHeader={false}
|
||||
isSub={false}
|
||||
isAside={true}
|
||||
{embedded}
|
||||
{object}
|
||||
on:open
|
||||
on:close={() => dispatch('close')}
|
||||
withoutInput
|
||||
withoutActivity
|
||||
>
|
||||
<svelte:fragment slot="title">
|
||||
<DocNavLink noUnderline {object}>
|
||||
<div class="title">
|
||||
{object.title ??
|
||||
`Import completed – ${object.exportedCount} document${object.exportedCount !== 1 ? 's' : ''}`}
|
||||
</div>
|
||||
</DocNavLink>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="utils">
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
dataId="btnMoreActions"
|
||||
on:click={(e) => {
|
||||
showMenu(e, { object, excludedActions: [view.action.Open] })
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
|
||||
<div class="export-result-content flex-col flex-grow flex-no-shrink step-tb-6">
|
||||
<p class="export-result-summary">
|
||||
<Label
|
||||
label={exportPlugin.string.DocumentsImportedFromWorkspace}
|
||||
params={{ count: object.exportedCount, workspace: object.sourceWorkspace }}
|
||||
/>
|
||||
</p>
|
||||
{#if exportedDocs.length > 0}
|
||||
<div class="doc-links">
|
||||
{#each exportedDocs as doc (doc._id)}
|
||||
<DocNavLink noUnderline object={doc}>
|
||||
<ObjectPresenter
|
||||
_class={docClass}
|
||||
value={doc}
|
||||
props={{ inline: true, size: 'small', withIcon: true, isGray: true }}
|
||||
/>
|
||||
</DocNavLink>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Panel>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.export-result-content {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
.export-result-summary {
|
||||
margin: 0 0 0.75rem;
|
||||
}
|
||||
.doc-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -13,19 +13,50 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type Resources } from '@hcengineering/platform'
|
||||
import type { Client, Doc, Ref } from '@hcengineering/core'
|
||||
import exportPlugin, { type ExportResultRecord } from '@hcengineering/export'
|
||||
import { type Resources, translate } from '@hcengineering/platform'
|
||||
import { themeStore } from '@hcengineering/ui'
|
||||
import { get } from 'svelte/store'
|
||||
import ExportButton from './components/ExportButton.svelte'
|
||||
import ExportSettings from './components/ExportSettings.svelte'
|
||||
import ExportToWorkspaceModal from './components/ExportToWorkspaceModal.svelte'
|
||||
import ExportResultPanel from './components/ExportResultPanel.svelte'
|
||||
|
||||
export { default as ExportButton } from './components/ExportButton.svelte'
|
||||
export { default as ExportSettings } from './components/ExportSettings.svelte'
|
||||
export { default as ExportToWorkspaceModal } from './components/ExportToWorkspaceModal.svelte'
|
||||
export { default as ExportResultPanel } from './components/ExportResultPanel.svelte'
|
||||
|
||||
export async function getExportResultTitle (_client: Client, _ref: Ref<Doc>, doc?: Doc): Promise<string> {
|
||||
const record = doc as ExportResultRecord | undefined
|
||||
if (record === undefined) return ''
|
||||
if (record.title !== undefined && record.title !== '') return record.title
|
||||
const lang = get(themeStore).language
|
||||
const createdOn = record.createdOn ?? Date.now()
|
||||
const dateStr = new Date(createdOn).toLocaleDateString(lang, {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric'
|
||||
})
|
||||
return await translate(
|
||||
exportPlugin.string.ExportResultRecordTitle,
|
||||
{
|
||||
workspace: record.sourceWorkspace,
|
||||
date: dateStr
|
||||
},
|
||||
lang
|
||||
)
|
||||
}
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
ExportButton,
|
||||
ExportSettings,
|
||||
ExportToWorkspaceModal
|
||||
ExportToWorkspaceModal,
|
||||
ExportResultPanel
|
||||
},
|
||||
function: {
|
||||
ExportResultTitleProvider: getExportResultTitle
|
||||
}
|
||||
})
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"dependencies": {
|
||||
"@hcengineering/platform": "workspace:^0.7.19",
|
||||
"@hcengineering/core": "workspace:^0.7.24",
|
||||
"@hcengineering/ui": "workspace:^0.7.0"
|
||||
"@hcengineering/ui": "workspace:^0.7.0",
|
||||
"@hcengineering/notification": "workspace:^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,29 +13,53 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { type IntlString, type Metadata, type Plugin, plugin, type Asset } from '@hcengineering/platform'
|
||||
import type { Class, Client, Doc, Ref } from '@hcengineering/core'
|
||||
import { type IntlString, type Metadata, type Plugin, plugin, type Resource, type Asset } from '@hcengineering/platform'
|
||||
import { type AnyComponent } from '@hcengineering/ui/src/types'
|
||||
import type { NotificationGroup, NotificationType } from '@hcengineering/notification'
|
||||
import type { ExportResultRecord } from './types'
|
||||
|
||||
export const exportId = 'export' as Plugin
|
||||
|
||||
export const exportPlugin = plugin(exportId, {
|
||||
ids: {
|
||||
ImportNotificationGroup: '' as Ref<NotificationGroup>,
|
||||
ImportedDocumentsNotification: '' as Ref<NotificationType>
|
||||
},
|
||||
class: {
|
||||
ExportResultRecord: '' as Ref<Class<ExportResultRecord>>
|
||||
},
|
||||
string: {
|
||||
Export: '' as IntlString,
|
||||
ExportCompleted: '' as IntlString,
|
||||
ExportFailed: '' as IntlString,
|
||||
ExportToWorkspace: '' as IntlString,
|
||||
TargetWorkspace: '' as IntlString
|
||||
TargetWorkspace: '' as IntlString,
|
||||
ImportCompleted: '' as IntlString,
|
||||
ImportToWorkspaceNotificationMessage: '' as IntlString,
|
||||
SourceWorkspace: '' as IntlString,
|
||||
ExportedCount: '' as IntlString,
|
||||
ExportedDocumentIds: '' as IntlString,
|
||||
DocumentsImportedFromWorkspace: '' as IntlString,
|
||||
ExportedDocumentClass: '' as IntlString,
|
||||
Import: '' as IntlString,
|
||||
ImportedDocuments: '' as IntlString,
|
||||
ExportResultRecordTitle: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
ExportButton: '' as AnyComponent,
|
||||
ExportSettings: '' as AnyComponent,
|
||||
ExportToWorkspaceModal: '' as AnyComponent
|
||||
ExportToWorkspaceModal: '' as AnyComponent,
|
||||
ExportResultPanel: '' as AnyComponent
|
||||
},
|
||||
icon: {
|
||||
Export: '' as Asset
|
||||
},
|
||||
metadata: {
|
||||
ExportUrl: '' as Metadata<string>
|
||||
},
|
||||
function: {
|
||||
ExportResultTitleProvider: '' as Resource<(client: Client, ref: Ref<Doc>, doc?: Doc) => Promise<string>>
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -14,6 +14,26 @@
|
||||
//
|
||||
import type { Class, Doc, Ref } from '@hcengineering/core'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ExportResultDoc {
|
||||
docId: Ref<Doc>
|
||||
name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ExportResultRecord extends Doc {
|
||||
sourceWorkspace: string
|
||||
targetWorkspace: string
|
||||
exportedCount: number
|
||||
exportedDocumentIds: Ref<Doc>[]
|
||||
objectClass: Ref<Class<Doc>>
|
||||
title?: string
|
||||
}
|
||||
|
||||
export enum OperationType {
|
||||
IDENTITY = 'identity',
|
||||
GROUP_BY = 'group_by'
|
||||
|
||||
@@ -13,109 +13,93 @@
|
||||
//
|
||||
|
||||
import { getClient } from '@hcengineering/account-client'
|
||||
import {
|
||||
import core, {
|
||||
AccountRole,
|
||||
concatLink,
|
||||
Doc,
|
||||
type AccountUuid,
|
||||
type Class,
|
||||
type Doc,
|
||||
generateId,
|
||||
MeasureContext,
|
||||
Ref,
|
||||
type Ref,
|
||||
systemAccountUuid,
|
||||
type TxOperations,
|
||||
WorkspaceIds,
|
||||
WorkspaceUuid
|
||||
} from '@hcengineering/core'
|
||||
import exportPlugin from '@hcengineering/export'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { generateToken } from '@hcengineering/server-token'
|
||||
import envConfig from './config'
|
||||
|
||||
export async function sendExportCompletionEmail (
|
||||
export async function sendExportCompletionNotification (
|
||||
ctx: MeasureContext,
|
||||
targetTxOps: TxOperations,
|
||||
targetWorkspace: WorkspaceUuid,
|
||||
targetWsIds: WorkspaceIds,
|
||||
exportedDocuments: Array<{ docId: Ref<Doc>, name: string }>,
|
||||
sourceWsIds: WorkspaceIds
|
||||
sourceWsIds: WorkspaceIds,
|
||||
objectClass: Ref<Class<Doc>>
|
||||
): Promise<void> {
|
||||
try {
|
||||
const mailURL = envConfig.MailURL
|
||||
if (mailURL == null || typeof mailURL !== 'string' || mailURL === '') {
|
||||
ctx.warn('Mail service URL not configured, skipping email notification')
|
||||
return
|
||||
}
|
||||
// Get workspace members to find owners
|
||||
const count = exportedDocuments.length
|
||||
const resultId = generateId<Doc>()
|
||||
|
||||
await targetTxOps.createDoc(
|
||||
exportPlugin.class.ExportResultRecord,
|
||||
core.space.Space,
|
||||
{
|
||||
sourceWorkspace: sourceWsIds.url,
|
||||
targetWorkspace: targetWsIds.url,
|
||||
exportedCount: count,
|
||||
exportedDocumentIds: exportedDocuments.map((d) => d.docId),
|
||||
objectClass
|
||||
},
|
||||
resultId
|
||||
)
|
||||
|
||||
const targetWsToken = generateToken(systemAccountUuid, targetWorkspace, { service: 'export' })
|
||||
const targetAccountClient = getClient(envConfig.AccountsUrl, targetWsToken)
|
||||
const members = await targetAccountClient.getWorkspaceMembers()
|
||||
|
||||
// Find workspace owners
|
||||
const owners = members.filter((m: any) => m.role === AccountRole.Owner)
|
||||
const owners = members.filter((m: { role: string }) => m.role === AccountRole.Owner) as Array<{
|
||||
person: AccountUuid
|
||||
}>
|
||||
|
||||
if (owners.length === 0) {
|
||||
ctx.warn('No workspace owners found for email notification', { targetWorkspace })
|
||||
ctx.warn('No workspace owners found for export notification', { targetWorkspace })
|
||||
return
|
||||
}
|
||||
|
||||
// Get email addresses for owners
|
||||
const ownerEmails: string[] = []
|
||||
for (const owner of owners) {
|
||||
try {
|
||||
const personInfo = await targetAccountClient.getPersonInfo(owner.person)
|
||||
const emailSocialId = personInfo.socialIds.find(
|
||||
(sid: any) => (sid.type === 'EMAIL' || sid.type === 'GOOGLE') && sid.verifiedOn > 0 && sid.isDeleted !== true
|
||||
)
|
||||
if (emailSocialId?.value != null && emailSocialId.value !== '') {
|
||||
ownerEmails.push(emailSocialId.value)
|
||||
}
|
||||
} catch (err) {
|
||||
ctx.warn('Failed to get email for workspace owner', { owner: owner.person, error: err })
|
||||
}
|
||||
}
|
||||
|
||||
if (ownerEmails.length === 0) {
|
||||
ctx.warn('No email addresses found for workspace owners', { targetWorkspace })
|
||||
return
|
||||
}
|
||||
|
||||
// Build email content
|
||||
const documentList = exportedDocuments.map((doc) => ` - ${doc.name}`).join('\n')
|
||||
const subject = `Export completed: ${exportedDocuments.length} document${exportedDocuments.length !== 1 ? 's' : ''} exported to your workspace`
|
||||
const text = `The following ${exportedDocuments.length} document${exportedDocuments.length !== 1 ? 's have' : ' has'} been successfully exported to your workspace:\n\n${documentList}\n\nSource workspace: ${sourceWsIds.uuid}\nTarget workspace: ${targetWsIds.uuid}`
|
||||
const html = `<p>The following <strong>${exportedDocuments.length}</strong> document${exportedDocuments.length !== 1 ? 's have' : ' has'} been successfully exported to your workspace:</p><ul>${exportedDocuments.map((doc) => `<li>${escapeHtml(doc.name)}</li>`).join('')}</ul><p>Source workspace: ${sourceWsIds.uuid}<br>Target workspace: ${targetWsIds.uuid}</p>`
|
||||
|
||||
// Send email to all owners
|
||||
const mailAuth = envConfig.MailAuthToken
|
||||
for (const email of ownerEmails) {
|
||||
try {
|
||||
const response = await fetch(concatLink(mailURL, '/send'), {
|
||||
method: 'post',
|
||||
keepalive: true,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(mailAuth != null ? { Authorization: `Bearer ${mailAuth}` } : {})
|
||||
},
|
||||
body: JSON.stringify({
|
||||
text,
|
||||
html,
|
||||
subject,
|
||||
to: [email]
|
||||
})
|
||||
const docNotifyContextId = await targetTxOps.createDoc(notification.class.DocNotifyContext, core.space.Space, {
|
||||
objectId: resultId,
|
||||
objectClass: exportPlugin.class.ExportResultRecord,
|
||||
objectSpace: core.space.Space,
|
||||
user: owner.person,
|
||||
isPinned: false,
|
||||
hidden: false
|
||||
})
|
||||
|
||||
await targetTxOps.createDoc(notification.class.CommonInboxNotification, core.space.Space, {
|
||||
user: owner.person,
|
||||
objectId: resultId,
|
||||
objectClass: exportPlugin.class.ExportResultRecord,
|
||||
icon: exportPlugin.icon.Export,
|
||||
message: exportPlugin.string.ImportToWorkspaceNotificationMessage,
|
||||
props: {
|
||||
count,
|
||||
sourceWorkspace: sourceWsIds.uuid
|
||||
},
|
||||
isViewed: false,
|
||||
archived: false,
|
||||
docNotifyContext: docNotifyContextId,
|
||||
types: [exportPlugin.ids.ImportedDocumentsNotification]
|
||||
})
|
||||
if (!response.ok) {
|
||||
ctx.error(`Failed to send export completion email: ${response.statusText}`, { email })
|
||||
} else {
|
||||
ctx.info('Export completion email sent', { email, documentCount: exportedDocuments.length })
|
||||
}
|
||||
} catch (err) {
|
||||
ctx.error('Could not send export completion email', { err, email })
|
||||
ctx.error('Failed to create export notification for owner', { owner: owner.person, err })
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
ctx.error('Failed to send export completion email', { err })
|
||||
ctx.error('Failed to send export completion notification', { err })
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml (text: string): string {
|
||||
return text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ import { getConfig } from '@hcengineering/server-pipeline'
|
||||
import { buildStorageFromConfig } from '@hcengineering/server-storage'
|
||||
import { Token, decodeToken, generateToken } from '@hcengineering/server-token'
|
||||
import archiver from 'archiver'
|
||||
import { sendExportCompletionEmail } from './notifications'
|
||||
import { sendExportCompletionNotification } from './notifications'
|
||||
import cors from 'cors'
|
||||
import express, { type Express, type NextFunction, type Request, type Response } from 'express'
|
||||
import { createWriteStream } from 'fs'
|
||||
@@ -537,12 +537,14 @@ export function createServer (
|
||||
const exportResult: ExportResult = await exporter.export(options)
|
||||
|
||||
if (exportResult.success && exportResult.exportedCount > 0) {
|
||||
await sendExportCompletionEmail(
|
||||
await sendExportCompletionNotification(
|
||||
measureCtx,
|
||||
targetTxOps,
|
||||
targetWorkspace,
|
||||
targetWsIds,
|
||||
exportResult.exportedDocuments,
|
||||
wsIds
|
||||
wsIds,
|
||||
_class
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -239,10 +239,14 @@ export class CrossWorkspaceExporter {
|
||||
(mappedDoc as any).title ??
|
||||
hierarchy.getClass(mappedDoc._class)?.label ??
|
||||
mappedDoc._id
|
||||
result.exportedDocuments.push({
|
||||
docId: mappedDoc._id,
|
||||
name: typeof docName === 'string' ? docName : String(docName)
|
||||
})
|
||||
// Use target workspace doc id so the notification panel can resolve docs in the target workspace
|
||||
const targetDocId = this.state.idMapping.get(mappedDoc._id)
|
||||
if (targetDocId !== undefined) {
|
||||
result.exportedDocuments.push({
|
||||
docId: targetDocId,
|
||||
name: typeof docName === 'string' ? docName : String(docName)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
result.skippedCount++
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user