Compare commits

..

1 Commits

Author SHA1 Message Date
Philipinho 12bd213236 fix 2026-04-13 23:53:16 +01:00
38 changed files with 58 additions and 1283 deletions
-3
View File
@@ -43,9 +43,6 @@ POSTMARK_TOKEN=
# for custom drawio server
DRAWIO_URL=
# Gotenberg URL for server-side PDF export
GOTENBERG_URL=
DISABLE_TELEMETRY=false
# Enable debug logging in production (default: false)
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
"version": "0.80.0",
"version": "0.71.1",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
@@ -739,93 +739,6 @@
"Removed page restriction": "Seitenbeschränkung entfernt",
"Added page permission": "Seitenberechtigung hinzugefügt",
"Removed page permission": "Seitenberechtigung entfernt",
"day": "Tag",
"days": "Tage",
"week": "Woche",
"weeks": "Wochen",
"month": "Monat",
"months": "Monate",
"year": "Jahr",
"years": "Jahre",
"Period": "Zeitraum",
"Fixed date": "Festes Datum",
"Indefinitely": "Unbegrenzt",
"Days": "Tage",
"Weeks": "Wochen",
"Months": "Monate",
"Years": "Jahre",
"Pick a date": "Datum auswählen",
"Maximum is {{max}} {{unit}} for this unit": "Das Maximum für diese Einheit beträgt {{max}} {{unit}}",
"Never expires. Verifiers can re-verify at any time.": "Läuft nie ab. Prüfer können die Seite jederzeit erneut verifizieren.",
"Verified": "Verifiziert",
"Review needed": "Prüfung erforderlich",
"Verification expired": "Verifizierung abgelaufen",
"Draft": "Entwurf",
"In Approval": "In Genehmigung",
"In approval": "In Genehmigung",
"Approved": "Genehmigt",
"Obsolete": "Veraltet",
"Expiring": "Läuft bald ab",
"Set up verification": "Verifizierung einrichten",
"Verify page": "Seite verifizieren",
"Page verification": "Seitenverifizierung",
"Add verification": "Verifizierung hinzufügen",
"Edit verification": "Verifizierung bearbeiten",
"Search by title": "Nach Titel suchen",
"Choose how this page should stay accurate.": "Wählen Sie aus, wie diese Seite aktuell gehalten werden soll.",
"Recurring verification": "Wiederkehrende Verifizierung",
"Verifiers re-confirm this page on a schedule.": "Prüfer bestätigen diese Seite nach einem Zeitplan erneut.",
"Re-verify on a schedule (e.g every 30 days )": "Nach einem Zeitplan erneut verifizieren (z. B. alle 30 Tage)",
"Page stays editable at all times": "Die Seite bleibt jederzeit bearbeitbar",
"Best for runbooks, FAQs, living documentation": "Am besten für Runbooks, FAQs und lebende Dokumentation geeignet",
"Approval workflow": "Genehmigungsworkflow",
"Formal document lifecycle with named approvers.": "Formaler Dokumentenlebenszyklus mit benannten Genehmigern.",
"Draft → In approval → Approved → Obsolete": "Entwurf → In Genehmigung → Genehmigt → Veraltet",
"Locked once approved, with full history": "Nach der Genehmigung gesperrt, mit vollständiger Historie",
"Designed for ISO 9001, ISO 13485, and FDA": "Entwickelt für ISO 9001, ISO 13485 und FDA",
"Best for SOPs and controlled documents": "Am besten für SOPs und kontrollierte Dokumente geeignet",
"Back": "Zurück",
"Quality management": "Qualitätsmanagement",
"Recurring": "Wiederkehrend",
"Pages move through draft, approval, and approved stages.": "Seiten durchlaufen die Phasen Entwurf, Genehmigung und Genehmigt.",
"Verifiers": "Prüfer",
"Add verifier": "Prüfer hinzufügen",
"I've reviewed this page for accuracy": "Ich habe diese Seite auf Richtigkeit geprüft",
"Set up": "Einrichten",
"Remove verification": "Verifizierung entfernen",
"Are you sure you want to remove verification from this page?": "Möchten Sie die Verifizierung wirklich von dieser Seite entfernen?",
"Assigned verifiers must periodically re-verify this page.": "Zugewiesene Prüfer müssen diese Seite regelmäßig erneut verifizieren.",
"Last verified by {{name}} {{time}} (expired)": "Zuletzt von {{name}} {{time}} verifiziert (abgelaufen)",
"The fixed expiration date has passed.": "Das feste Ablaufdatum ist überschritten.",
"Verified by {{name}} {{time}}": "Verifiziert von {{name}} {{time}}",
"Expires {{date}}": "Läuft ab am {{date}}",
"Expired {{date}}": "Abgelaufen am {{date}}",
"Mark as obsolete": "Als veraltet markieren",
"Mark obsolete": "Als veraltet markieren",
"Returned by {{name}} {{time}}": "Zurückgegeben von {{name}} {{time}}",
"No approval has been requested yet.": "Es wurde noch keine Genehmigung angefordert.",
"Submitted by {{name}} {{time}}": "Eingereicht von {{name}} {{time}}",
"Someone": "Jemand",
"Approved by {{name}} {{time}}": "Genehmigt von {{name}} {{time}}",
"This document has been marked as obsolete.": "Dieses Dokument wurde als veraltet markiert.",
"Rejection comment": "Ablehnungskommentar",
"Reason for returning this document...": "Grund für die Rückgabe dieses Dokuments...",
"Confirm rejection": "Ablehnung bestätigen",
"Submit for approval": "Zur Genehmigung einreichen",
"Reject": "Ablehnen",
"Approve": "Genehmigen",
"Re-submit for approval": "Erneut zur Genehmigung einreichen",
"Verified until": "Verifiziert bis",
"QMS": "QMS",
"Verified pages": "Verifizierte Seiten",
"Search pages...": "Seiten suchen...",
"Filter by space": "Nach Bereich filtern",
"Filter by type": "Nach Typ filtern",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> hat eine Seite verifiziert",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> hat eine Seite zu Ihrer Genehmigung eingereicht",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> hat eine Seite zur Überarbeitung zurückgegeben",
"Page verification expires soon": "Die Seitenverifizierung läuft bald ab",
"Page verification has expired": "Die Seitenverifizierung ist abgelaufen",
"Verifying your email": "Ihre E-Mail wird bestätigt",
"Please wait...": "Bitte warten...",
"Verification failed. The link may have expired.": "Überprüfung fehlgeschlagen. Der Link ist möglicherweise abgelaufen.",
@@ -739,93 +739,6 @@
"Removed page restriction": "Restricción de página eliminada",
"Added page permission": "Permiso de página añadido",
"Removed page permission": "Permiso de página eliminado",
"day": "día",
"days": "días",
"week": "semana",
"weeks": "semanas",
"month": "mes",
"months": "meses",
"year": "año",
"years": "años",
"Period": "Período",
"Fixed date": "Fecha fija",
"Indefinitely": "Indefinidamente",
"Days": "Días",
"Weeks": "Semanas",
"Months": "Meses",
"Years": "Años",
"Pick a date": "Selecciona una fecha",
"Maximum is {{max}} {{unit}} for this unit": "El máximo es {{max}} {{unit}} para esta unidad",
"Never expires. Verifiers can re-verify at any time.": "Nunca caduca. Los verificadores pueden volver a verificar en cualquier momento.",
"Verified": "Verificado",
"Review needed": "Revisión necesaria",
"Verification expired": "La verificación ha caducado",
"Draft": "Borrador",
"In Approval": "En aprobación",
"In approval": "En aprobación",
"Approved": "Aprobado",
"Obsolete": "Obsoleto",
"Expiring": "Próximo a caducar",
"Set up verification": "Configurar verificación",
"Verify page": "Verificar página",
"Page verification": "Verificación de página",
"Add verification": "Añadir verificación",
"Edit verification": "Editar verificación",
"Search by title": "Buscar por título",
"Choose how this page should stay accurate.": "Elige cómo debe mantenerse precisa esta página.",
"Recurring verification": "Verificación periódica",
"Verifiers re-confirm this page on a schedule.": "Los verificadores vuelven a confirmar esta página según una programación.",
"Re-verify on a schedule (e.g every 30 days )": "Volver a verificar según una programación (p. ej., cada 30 días)",
"Page stays editable at all times": "La página permanece editable en todo momento",
"Best for runbooks, FAQs, living documentation": "Ideal para runbooks, preguntas frecuentes y documentación viva",
"Approval workflow": "Flujo de aprobación",
"Formal document lifecycle with named approvers.": "Ciclo de vida formal del documento con aprobadores designados.",
"Draft → In approval → Approved → Obsolete": "Borrador → En aprobación → Aprobado → Obsoleto",
"Locked once approved, with full history": "Bloqueado una vez aprobado, con historial completo",
"Designed for ISO 9001, ISO 13485, and FDA": "Diseñado para ISO 9001, ISO 13485 y FDA",
"Best for SOPs and controlled documents": "Ideal para SOP y documentos controlados",
"Back": "Atrás",
"Quality management": "Gestión de calidad",
"Recurring": "Periódica",
"Pages move through draft, approval, and approved stages.": "Las páginas pasan por las etapas de borrador, aprobación y aprobado.",
"Verifiers": "Verificadores",
"Add verifier": "Añadir verificador",
"I've reviewed this page for accuracy": "He revisado la exactitud de esta página",
"Set up": "Configurar",
"Remove verification": "Eliminar verificación",
"Are you sure you want to remove verification from this page?": "¿Seguro que quieres eliminar la verificación de esta página?",
"Assigned verifiers must periodically re-verify this page.": "Los verificadores asignados deben volver a verificar esta página periódicamente.",
"Last verified by {{name}} {{time}} (expired)": "Última verificación por {{name}} {{time}} (caducada)",
"The fixed expiration date has passed.": "La fecha fija de vencimiento ya pasó.",
"Verified by {{name}} {{time}}": "Verificado por {{name}} {{time}}",
"Expires {{date}}": "Caduca el {{date}}",
"Expired {{date}}": "Caducó el {{date}}",
"Mark as obsolete": "Marcar como obsoleto",
"Mark obsolete": "Marcar como obsoleto",
"Returned by {{name}} {{time}}": "Devuelto por {{name}} {{time}}",
"No approval has been requested yet.": "Aún no se ha solicitado aprobación.",
"Submitted by {{name}} {{time}}": "Enviado por {{name}} {{time}}",
"Someone": "Alguien",
"Approved by {{name}} {{time}}": "Aprobado por {{name}} {{time}}",
"This document has been marked as obsolete.": "Este documento ha sido marcado como obsoleto.",
"Rejection comment": "Comentario de rechazo",
"Reason for returning this document...": "Motivo de la devolución de este documento...",
"Confirm rejection": "Confirmar rechazo",
"Submit for approval": "Enviar para aprobación",
"Reject": "Rechazar",
"Approve": "Aprobar",
"Re-submit for approval": "Volver a enviar para aprobación",
"Verified until": "Verificado hasta",
"QMS": "SGC",
"Verified pages": "Páginas verificadas",
"Search pages...": "Buscar páginas...",
"Filter by space": "Filtrar por espacio",
"Filter by type": "Filtrar por tipo",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> verificó una página",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> envió una página para tu aprobación",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> devolvió una página para revisión",
"Page verification expires soon": "La verificación de la página caduca pronto",
"Page verification has expired": "La verificación de la página ha caducado",
"Verifying your email": "Verificando tu correo electrónico",
"Please wait...": "Por favor, espera...",
"Verification failed. The link may have expired.": "La verificación ha fallado. Es posible que el enlace haya expirado.",
@@ -739,93 +739,6 @@
"Removed page restriction": "Restriction de la page supprimée",
"Added page permission": "Autorisation de la page ajoutée",
"Removed page permission": "Autorisation de la page supprimée",
"day": "jour",
"days": "jours",
"week": "semaine",
"weeks": "semaines",
"month": "mois",
"months": "mois",
"year": "an",
"years": "ans",
"Period": "Période",
"Fixed date": "Date fixe",
"Indefinitely": "Indéfiniment",
"Days": "Jours",
"Weeks": "Semaines",
"Months": "Mois",
"Years": "Ans",
"Pick a date": "Choisir une date",
"Maximum is {{max}} {{unit}} for this unit": "Le maximum est de {{max}} {{unit}} pour cette unité",
"Never expires. Verifiers can re-verify at any time.": "Nexpire jamais. Les vérificateurs peuvent revérifier à tout moment.",
"Verified": "Vérifié",
"Review needed": "Révision nécessaire",
"Verification expired": "Vérification expirée",
"Draft": "Brouillon",
"In Approval": "En approbation",
"In approval": "En approbation",
"Approved": "Approuvé",
"Obsolete": "Obsolète",
"Expiring": "Expire bientôt",
"Set up verification": "Configurer la vérification",
"Verify page": "Vérifier la page",
"Page verification": "Vérification de la page",
"Add verification": "Ajouter une vérification",
"Edit verification": "Modifier la vérification",
"Search by title": "Rechercher par titre",
"Choose how this page should stay accurate.": "Choisissez comment cette page doit rester exacte.",
"Recurring verification": "Vérification récurrente",
"Verifiers re-confirm this page on a schedule.": "Les vérificateurs reconfirment cette page selon une fréquence définie.",
"Re-verify on a schedule (e.g every 30 days )": "Revérifier selon une fréquence définie (p. ex. tous les 30 jours)",
"Page stays editable at all times": "La page reste modifiable en permanence",
"Best for runbooks, FAQs, living documentation": "Idéal pour les runbooks, FAQ et la documentation évolutive",
"Approval workflow": "Flux dapprobation",
"Formal document lifecycle with named approvers.": "Cycle de vie formel du document avec des approbateurs désignés.",
"Draft → In approval → Approved → Obsolete": "Brouillon → En approbation → Approuvé → Obsolète",
"Locked once approved, with full history": "Verrouillé une fois approuvé, avec historique complet",
"Designed for ISO 9001, ISO 13485, and FDA": "Conçu pour lISO 9001, lISO 13485 et la FDA",
"Best for SOPs and controlled documents": "Idéal pour les SOP et les documents contrôlés",
"Back": "Retour",
"Quality management": "Gestion de la qualité",
"Recurring": "Récurrent",
"Pages move through draft, approval, and approved stages.": "Les pages passent par les étapes brouillon, approbation et approuvé.",
"Verifiers": "Vérificateurs",
"Add verifier": "Ajouter un vérificateur",
"I've reviewed this page for accuracy": "Jai vérifié lexactitude de cette page",
"Set up": "Configurer",
"Remove verification": "Supprimer la vérification",
"Are you sure you want to remove verification from this page?": "Voulez-vous vraiment supprimer la vérification de cette page ?",
"Assigned verifiers must periodically re-verify this page.": "Les vérificateurs assignés doivent revérifier périodiquement cette page.",
"Last verified by {{name}} {{time}} (expired)": "Dernière vérification par {{name}} {{time}} (expirée)",
"The fixed expiration date has passed.": "La date dexpiration fixe est passée.",
"Verified by {{name}} {{time}}": "Vérifié par {{name}} {{time}}",
"Expires {{date}}": "Expire le {{date}}",
"Expired {{date}}": "Expiré le {{date}}",
"Mark as obsolete": "Marquer comme obsolète",
"Mark obsolete": "Marquer comme obsolète",
"Returned by {{name}} {{time}}": "Renvoyé par {{name}} {{time}}",
"No approval has been requested yet.": "Aucune approbation na encore été demandée.",
"Submitted by {{name}} {{time}}": "Soumis par {{name}} {{time}}",
"Someone": "Quelquun",
"Approved by {{name}} {{time}}": "Approuvé par {{name}} {{time}}",
"This document has been marked as obsolete.": "Ce document a été marqué comme obsolète.",
"Rejection comment": "Commentaire de rejet",
"Reason for returning this document...": "Raison du renvoi de ce document...",
"Confirm rejection": "Confirmer le rejet",
"Submit for approval": "Soumettre pour approbation",
"Reject": "Rejeter",
"Approve": "Approuver",
"Re-submit for approval": "Soumettre à nouveau pour approbation",
"Verified until": "Vérifié jusquau",
"QMS": "SMQ",
"Verified pages": "Pages vérifiées",
"Search pages...": "Rechercher des pages...",
"Filter by space": "Filtrer par espace",
"Filter by type": "Filtrer par type",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> a vérifié une page",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> a soumis une page à votre approbation",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> a renvoyé une page pour révision",
"Page verification expires soon": "La vérification de la page expire bientôt",
"Page verification has expired": "La vérification de la page a expiré",
"Verifying your email": "Vérification de votre e-mail",
"Please wait...": "Veuillez patienter...",
"Verification failed. The link may have expired.": "Échec de la vérification. Le lien a peut-être expiré.",
@@ -739,93 +739,6 @@
"Removed page restriction": "Restrizione della pagina rimossa",
"Added page permission": "Permesso sulla pagina aggiunto",
"Removed page permission": "Permesso sulla pagina rimosso",
"day": "giorno",
"days": "giorni",
"week": "settimana",
"weeks": "settimane",
"month": "mese",
"months": "mesi",
"year": "anno",
"years": "anni",
"Period": "Periodo",
"Fixed date": "Data fissa",
"Indefinitely": "A tempo indeterminato",
"Days": "Giorni",
"Weeks": "Settimane",
"Months": "Mesi",
"Years": "Anni",
"Pick a date": "Scegli una data",
"Maximum is {{max}} {{unit}} for this unit": "Il massimo consentito è {{max}} {{unit}} per questa unità",
"Never expires. Verifiers can re-verify at any time.": "Non scade mai. I verificatori possono verificare nuovamente in qualsiasi momento.",
"Verified": "Verificato",
"Review needed": "Revisione necessaria",
"Verification expired": "Verifica scaduta",
"Draft": "Bozza",
"In Approval": "In approvazione",
"In approval": "In approvazione",
"Approved": "Approvato",
"Obsolete": "Obsoleto",
"Expiring": "In scadenza",
"Set up verification": "Configura la verifica",
"Verify page": "Verifica la pagina",
"Page verification": "Verifica della pagina",
"Add verification": "Aggiungi verifica",
"Edit verification": "Modifica verifica",
"Search by title": "Cerca per titolo",
"Choose how this page should stay accurate.": "Scegli come mantenere accurata questa pagina.",
"Recurring verification": "Verifica ricorrente",
"Verifiers re-confirm this page on a schedule.": "I verificatori riconfermano questa pagina secondo una pianificazione.",
"Re-verify on a schedule (e.g every 30 days )": "Verifica nuovamente secondo una pianificazione (ad es. ogni 30 giorni)",
"Page stays editable at all times": "La pagina resta sempre modificabile",
"Best for runbooks, FAQs, living documentation": "Ideale per runbook, FAQ e documentazione dinamica",
"Approval workflow": "Flusso di approvazione",
"Formal document lifecycle with named approvers.": "Ciclo di vita formale del documento con approvatori nominati.",
"Draft → In approval → Approved → Obsolete": "Bozza → In approvazione → Approvato → Obsoleto",
"Locked once approved, with full history": "Bloccato una volta approvato, con cronologia completa",
"Designed for ISO 9001, ISO 13485, and FDA": "Progettato per ISO 9001, ISO 13485 e FDA",
"Best for SOPs and controlled documents": "Ideale per SOP e documenti controllati",
"Back": "Indietro",
"Quality management": "Gestione della qualità",
"Recurring": "Ricorrente",
"Pages move through draft, approval, and approved stages.": "Le pagine passano attraverso le fasi di bozza, approvazione e approvato.",
"Verifiers": "Verificatori",
"Add verifier": "Aggiungi verificatore",
"I've reviewed this page for accuracy": "Ho controllato l'accuratezza di questa pagina",
"Set up": "Configura",
"Remove verification": "Rimuovi verifica",
"Are you sure you want to remove verification from this page?": "Sei sicuro di voler rimuovere la verifica da questa pagina?",
"Assigned verifiers must periodically re-verify this page.": "I verificatori assegnati devono verificare nuovamente questa pagina periodicamente.",
"Last verified by {{name}} {{time}} (expired)": "Ultima verifica effettuata da {{name}} {{time}} (scaduta)",
"The fixed expiration date has passed.": "La data di scadenza fissa è trascorsa.",
"Verified by {{name}} {{time}}": "Verificato da {{name}} {{time}}",
"Expires {{date}}": "Scade il {{date}}",
"Expired {{date}}": "Scaduto il {{date}}",
"Mark as obsolete": "Contrassegna come obsoleto",
"Mark obsolete": "Contrassegna come obsoleto",
"Returned by {{name}} {{time}}": "Restituito da {{name}} {{time}}",
"No approval has been requested yet.": "Non è stata ancora richiesta alcuna approvazione.",
"Submitted by {{name}} {{time}}": "Inviato da {{name}} {{time}}",
"Someone": "Qualcuno",
"Approved by {{name}} {{time}}": "Approvato da {{name}} {{time}}",
"This document has been marked as obsolete.": "Questo documento è stato contrassegnato come obsoleto.",
"Rejection comment": "Commento di rifiuto",
"Reason for returning this document...": "Motivo della restituzione di questo documento...",
"Confirm rejection": "Conferma rifiuto",
"Submit for approval": "Invia per approvazione",
"Reject": "Rifiuta",
"Approve": "Approva",
"Re-submit for approval": "Invia nuovamente per approvazione",
"Verified until": "Verificato fino al",
"QMS": "QMS",
"Verified pages": "Pagine verificate",
"Search pages...": "Cerca pagine...",
"Filter by space": "Filtra per spazio",
"Filter by type": "Filtra per tipo",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> ha verificato una pagina",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> ha inviato una pagina per la tua approvazione",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> ha restituito una pagina per la revisione",
"Page verification expires soon": "La verifica della pagina scadrà presto",
"Page verification has expired": "La verifica della pagina è scaduta",
"Verifying your email": "Verifica della tua email in corso",
"Please wait...": "Attendere...",
"Verification failed. The link may have expired.": "Verifica non riuscita. Il link potrebbe essere scaduto.",
@@ -739,93 +739,6 @@
"Removed page restriction": "ページの制限を解除しました",
"Added page permission": "ページの権限を追加しました",
"Removed page permission": "ページの権限を削除しました",
"day": "日",
"days": "日",
"week": "週",
"weeks": "週",
"month": "か月",
"months": "か月",
"year": "年",
"years": "年",
"Period": "期間",
"Fixed date": "指定日",
"Indefinitely": "無期限",
"Days": "日",
"Weeks": "週",
"Months": "か月",
"Years": "年",
"Pick a date": "日付を選択",
"Maximum is {{max}} {{unit}} for this unit": "この単位の最大値は{{max}}{{unit}}です",
"Never expires. Verifiers can re-verify at any time.": "有効期限はありません。検証者はいつでも再検証できます。",
"Verified": "検証済み",
"Review needed": "確認が必要",
"Verification expired": "検証期限切れ",
"Draft": "下書き",
"In Approval": "承認中",
"In approval": "承認中",
"Approved": "承認済み",
"Obsolete": "廃止",
"Expiring": "期限間近",
"Set up verification": "検証を設定",
"Verify page": "ページを検証",
"Page verification": "ページ検証",
"Add verification": "検証を追加",
"Edit verification": "検証を編集",
"Search by title": "タイトルで検索",
"Choose how this page should stay accurate.": "このページの正確性をどのように維持するか選択してください。",
"Recurring verification": "定期検証",
"Verifiers re-confirm this page on a schedule.": "検証者がこのページを定期的に再確認します。",
"Re-verify on a schedule (e.g every 30 days )": "スケジュールに従って再検証(例:30日ごと)",
"Page stays editable at all times": "ページは常に編集可能です",
"Best for runbooks, FAQs, living documentation": "運用手順書、FAQ、継続的に更新されるドキュメントに最適",
"Approval workflow": "承認ワークフロー",
"Formal document lifecycle with named approvers.": "指定された承認者による正式な文書ライフサイクルです。",
"Draft → In approval → Approved → Obsolete": "下書き → 承認中 → 承認済み → 廃止",
"Locked once approved, with full history": "承認後はロックされ、完全な履歴が残ります",
"Designed for ISO 9001, ISO 13485, and FDA": "ISO 9001、ISO 13485、FDA向けに設計",
"Best for SOPs and controlled documents": "SOPや管理文書に最適",
"Back": "戻る",
"Quality management": "品質管理",
"Recurring": "定期",
"Pages move through draft, approval, and approved stages.": "ページは下書き、承認中、承認済みの各段階を進みます。",
"Verifiers": "検証者",
"Add verifier": "検証者を追加",
"I've reviewed this page for accuracy": "このページの正確性を確認しました",
"Set up": "設定",
"Remove verification": "検証を削除",
"Are you sure you want to remove verification from this page?": "このページから検証を削除してもよろしいですか?",
"Assigned verifiers must periodically re-verify this page.": "割り当てられた検証者はこのページを定期的に再検証する必要があります。",
"Last verified by {{name}} {{time}} (expired)": "最終検証者:{{name}} {{time}}(期限切れ)",
"The fixed expiration date has passed.": "指定された有効期限を過ぎています。",
"Verified by {{name}} {{time}}": "{{name}}が{{time}}に検証",
"Expires {{date}}": "有効期限:{{date}}",
"Expired {{date}}": "{{date}}に期限切れ",
"Mark as obsolete": "廃止としてマーク",
"Mark obsolete": "廃止にする",
"Returned by {{name}} {{time}}": "{{name}}が{{time}}に差し戻し",
"No approval has been requested yet.": "まだ承認は依頼されていません。",
"Submitted by {{name}} {{time}}": "{{name}}が{{time}}に提出",
"Someone": "誰か",
"Approved by {{name}} {{time}}": "{{name}}が{{time}}に承認",
"This document has been marked as obsolete.": "この文書は廃止としてマークされています。",
"Rejection comment": "差し戻しコメント",
"Reason for returning this document...": "この文書を差し戻す理由...",
"Confirm rejection": "差し戻しを確定",
"Submit for approval": "承認を申請",
"Reject": "差し戻す",
"Approve": "承認",
"Re-submit for approval": "再度承認を申請",
"Verified until": "検証有効期限",
"QMS": "QMS",
"Verified pages": "検証済みページ",
"Search pages...": "ページを検索...",
"Filter by space": "スペースで絞り込み",
"Filter by type": "タイプで絞り込み",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold>がページを検証しました",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold>があなたの承認のためにページを提出しました",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold>がページを修正のため差し戻しました",
"Page verification expires soon": "ページ検証の期限が間もなく切れます",
"Page verification has expired": "ページ検証の期限が切れています",
"Verifying your email": "メールアドレスを確認しています",
"Please wait...": "お待ちください…",
"Verification failed. The link may have expired.": "認証に失敗しました。リンクの有効期限が切れている可能性があります。",
@@ -739,93 +739,6 @@
"Removed page restriction": "페이지 제한이 제거됨",
"Added page permission": "페이지 권한이 추가됨",
"Removed page permission": "페이지 권한이 제거됨",
"day": "일",
"days": "일",
"week": "주",
"weeks": "주",
"month": "개월",
"months": "개월",
"year": "년",
"years": "년",
"Period": "기간",
"Fixed date": "고정 날짜",
"Indefinitely": "무기한",
"Days": "일",
"Weeks": "주",
"Months": "개월",
"Years": "년",
"Pick a date": "날짜 선택",
"Maximum is {{max}} {{unit}} for this unit": "이 단위의 최대값은 {{max}} {{unit}}입니다",
"Never expires. Verifiers can re-verify at any time.": "만료되지 않습니다. 검증자는 언제든지 다시 검증할 수 있습니다.",
"Verified": "검증됨",
"Review needed": "검토 필요",
"Verification expired": "검증 만료됨",
"Draft": "초안",
"In Approval": "승인 진행 중",
"In approval": "승인 진행 중",
"Approved": "승인됨",
"Obsolete": "폐기됨",
"Expiring": "만료 예정",
"Set up verification": "검증 설정",
"Verify page": "페이지 검증",
"Page verification": "페이지 검증",
"Add verification": "검증 추가",
"Edit verification": "검증 편집",
"Search by title": "제목으로 검색",
"Choose how this page should stay accurate.": "이 페이지의 정확성을 유지할 방법을 선택하세요.",
"Recurring verification": "반복 검증",
"Verifiers re-confirm this page on a schedule.": "검증자가 일정에 따라 이 페이지를 다시 확인합니다.",
"Re-verify on a schedule (e.g every 30 days )": "일정에 따라 다시 검증(예: 30일마다)",
"Page stays editable at all times": "페이지는 항상 편집 가능합니다",
"Best for runbooks, FAQs, living documentation": "런북, FAQ, 살아 있는 문서에 적합",
"Approval workflow": "승인 워크플로",
"Formal document lifecycle with named approvers.": "지정된 승인자가 있는 공식 문서 수명 주기입니다.",
"Draft → In approval → Approved → Obsolete": "초안 → 승인 진행 중 → 승인됨 → 폐기됨",
"Locked once approved, with full history": "승인되면 잠기며 전체 이력이 유지됩니다",
"Designed for ISO 9001, ISO 13485, and FDA": "ISO 9001, ISO 13485 및 FDA용으로 설계됨",
"Best for SOPs and controlled documents": "SOP 및 관리 문서에 적합",
"Back": "뒤로",
"Quality management": "품질 관리",
"Recurring": "반복",
"Pages move through draft, approval, and approved stages.": "페이지는 초안, 승인, 승인됨 단계를 거칩니다.",
"Verifiers": "검증자",
"Add verifier": "검증자 추가",
"I've reviewed this page for accuracy": "이 페이지의 정확성을 검토했습니다",
"Set up": "설정",
"Remove verification": "검증 제거",
"Are you sure you want to remove verification from this page?": "이 페이지에서 검증을 제거하시겠습니까?",
"Assigned verifiers must periodically re-verify this page.": "지정된 검증자는 이 페이지를 주기적으로 다시 검증해야 합니다.",
"Last verified by {{name}} {{time}} (expired)": "마지막 검증자: {{name}} {{time}} (만료됨)",
"The fixed expiration date has passed.": "고정된 만료일이 지났습니다.",
"Verified by {{name}} {{time}}": "검증자: {{name}} {{time}}",
"Expires {{date}}": "{{date}}에 만료",
"Expired {{date}}": "{{date}}에 만료됨",
"Mark as obsolete": "폐기로 표시",
"Mark obsolete": "폐기 표시",
"Returned by {{name}} {{time}}": "반려자: {{name}} {{time}}",
"No approval has been requested yet.": "아직 승인이 요청되지 않았습니다.",
"Submitted by {{name}} {{time}}": "제출자: {{name}} {{time}}",
"Someone": "누군가",
"Approved by {{name}} {{time}}": "승인자: {{name}} {{time}}",
"This document has been marked as obsolete.": "이 문서는 폐기로 표시되었습니다.",
"Rejection comment": "반려 사유",
"Reason for returning this document...": "이 문서를 반려하는 이유...",
"Confirm rejection": "반려 확인",
"Submit for approval": "승인 요청",
"Reject": "반려",
"Approve": "승인",
"Re-submit for approval": "승인 재요청",
"Verified until": "다음까지 검증됨",
"QMS": "QMS",
"Verified pages": "검증된 페이지",
"Search pages...": "페이지 검색...",
"Filter by space": "스페이스별 필터",
"Filter by type": "유형별 필터",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold>님이 페이지를 검증했습니다",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold>님이 승인을 위해 페이지를 제출했습니다",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold>님이 수정을 위해 페이지를 반려했습니다",
"Page verification expires soon": "페이지 검토가 곧 만료됩니다",
"Page verification has expired": "페이지 검토가 만료되었습니다",
"Verifying your email": "이메일 확인 중",
"Please wait...": "잠시만 기다려 주세요...",
"Verification failed. The link may have expired.": "인증에 실패했습니다. 링크가 만료되었을 수 있습니다.",
@@ -739,93 +739,6 @@
"Removed page restriction": "Pagina-restrictie verwijderd",
"Added page permission": "Paginatoestemming toegevoegd",
"Removed page permission": "Paginatoestemming verwijderd",
"day": "dag",
"days": "dagen",
"week": "week",
"weeks": "weken",
"month": "maand",
"months": "maanden",
"year": "jaar",
"years": "jaren",
"Period": "Periode",
"Fixed date": "Vaste datum",
"Indefinitely": "Voor onbepaalde tijd",
"Days": "Dagen",
"Weeks": "Weken",
"Months": "Maanden",
"Years": "Jaren",
"Pick a date": "Kies een datum",
"Maximum is {{max}} {{unit}} for this unit": "Maximum is {{max}} {{unit}} voor deze eenheid",
"Never expires. Verifiers can re-verify at any time.": "Verloopt nooit. Verificateurs kunnen op elk moment opnieuw verifiëren.",
"Verified": "Geverifieerd",
"Review needed": "Beoordeling nodig",
"Verification expired": "Verificatie verlopen",
"Draft": "Concept",
"In Approval": "In goedkeuring",
"In approval": "In goedkeuring",
"Approved": "Goedgekeurd",
"Obsolete": "Verouderd",
"Expiring": "Verloopt binnenkort",
"Set up verification": "Verificatie instellen",
"Verify page": "Pagina verifiëren",
"Page verification": "Paginaverificatie",
"Add verification": "Verificatie toevoegen",
"Edit verification": "Verificatie bewerken",
"Search by title": "Zoeken op titel",
"Choose how this page should stay accurate.": "Kies hoe deze pagina accuraat moet blijven.",
"Recurring verification": "Terugkerende verificatie",
"Verifiers re-confirm this page on a schedule.": "Verificateurs bevestigen deze pagina opnieuw volgens een schema.",
"Re-verify on a schedule (e.g every 30 days )": "Opnieuw verifiëren volgens een schema (bijv. elke 30 dagen)",
"Page stays editable at all times": "Pagina blijft altijd bewerkbaar",
"Best for runbooks, FAQs, living documentation": "Het beste voor runbooks, veelgestelde vragen en levende documentatie",
"Approval workflow": "Goedkeuringsworkflow",
"Formal document lifecycle with named approvers.": "Formele documentlevenscyclus met benoemde goedkeurders.",
"Draft → In approval → Approved → Obsolete": "Concept → In goedkeuring → Goedgekeurd → Verouderd",
"Locked once approved, with full history": "Vergrendeld zodra goedgekeurd, met volledige geschiedenis",
"Designed for ISO 9001, ISO 13485, and FDA": "Ontworpen voor ISO 9001, ISO 13485 en FDA",
"Best for SOPs and controlled documents": "Het beste voor SOP's en beheerde documenten",
"Back": "Terug",
"Quality management": "Kwaliteitsmanagement",
"Recurring": "Terugkerend",
"Pages move through draft, approval, and approved stages.": "Pagina's doorlopen de fasen concept, goedkeuring en goedgekeurd.",
"Verifiers": "Verificateurs",
"Add verifier": "Verificateur toevoegen",
"I've reviewed this page for accuracy": "Ik heb deze pagina op nauwkeurigheid beoordeeld",
"Set up": "Instellen",
"Remove verification": "Verificatie verwijderen",
"Are you sure you want to remove verification from this page?": "Weet je zeker dat je verificatie van deze pagina wilt verwijderen?",
"Assigned verifiers must periodically re-verify this page.": "Toegewezen verificateurs moeten deze pagina periodiek opnieuw verifiëren.",
"Last verified by {{name}} {{time}} (expired)": "Laatst geverifieerd door {{name}} {{time}} (verlopen)",
"The fixed expiration date has passed.": "De vaste vervaldatum is verstreken.",
"Verified by {{name}} {{time}}": "Geverifieerd door {{name}} {{time}}",
"Expires {{date}}": "Verloopt op {{date}}",
"Expired {{date}}": "Verlopen op {{date}}",
"Mark as obsolete": "Markeren als verouderd",
"Mark obsolete": "Markeer als verouderd",
"Returned by {{name}} {{time}}": "Teruggestuurd door {{name}} {{time}}",
"No approval has been requested yet.": "Er is nog geen goedkeuring aangevraagd.",
"Submitted by {{name}} {{time}}": "Ingediend door {{name}} {{time}}",
"Someone": "Iemand",
"Approved by {{name}} {{time}}": "Goedgekeurd door {{name}} {{time}}",
"This document has been marked as obsolete.": "Dit document is als verouderd gemarkeerd.",
"Rejection comment": "Afwijzingsopmerking",
"Reason for returning this document...": "Reden om dit document terug te sturen...",
"Confirm rejection": "Afwijzing bevestigen",
"Submit for approval": "Indienen voor goedkeuring",
"Reject": "Afwijzen",
"Approve": "Goedkeuren",
"Re-submit for approval": "Opnieuw indienen voor goedkeuring",
"Verified until": "Geverifieerd tot",
"QMS": "QMS",
"Verified pages": "Geverifieerde pagina's",
"Search pages...": "Pagina's zoeken...",
"Filter by space": "Filteren op ruimte",
"Filter by type": "Filteren op type",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> heeft een pagina geverifieerd",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> heeft een pagina voor jouw goedkeuring ingediend",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> heeft een pagina teruggestuurd voor revisie",
"Page verification expires soon": "Paginaverificatie verloopt binnenkort",
"Page verification has expired": "Paginaverificatie is verlopen",
"Verifying your email": "Je e-mailadres wordt geverifieerd",
"Please wait...": "Even geduld...",
"Verification failed. The link may have expired.": "Verificatie mislukt. De link is mogelijk verlopen.",
@@ -739,93 +739,6 @@
"Removed page restriction": "Restrição de página removida",
"Added page permission": "Permissão de página adicionada",
"Removed page permission": "Permissão de página removida",
"day": "dia",
"days": "dias",
"week": "semana",
"weeks": "semanas",
"month": "mês",
"months": "meses",
"year": "ano",
"years": "anos",
"Period": "Período",
"Fixed date": "Data fixa",
"Indefinitely": "Indefinidamente",
"Days": "Dias",
"Weeks": "Semanas",
"Months": "Meses",
"Years": "Anos",
"Pick a date": "Escolha uma data",
"Maximum is {{max}} {{unit}} for this unit": "O máximo é {{max}} {{unit}} para esta unidade",
"Never expires. Verifiers can re-verify at any time.": "Nunca expira. Os verificadores podem verificar novamente a qualquer momento.",
"Verified": "Verificado",
"Review needed": "Revisão necessária",
"Verification expired": "A verificação expirou",
"Draft": "Rascunho",
"In Approval": "Em aprovação",
"In approval": "Em aprovação",
"Approved": "Aprovado",
"Obsolete": "Obsoleto",
"Expiring": "Expirando",
"Set up verification": "Configurar verificação",
"Verify page": "Verificar página",
"Page verification": "Verificação da página",
"Add verification": "Adicionar verificação",
"Edit verification": "Editar verificação",
"Search by title": "Pesquisar por título",
"Choose how this page should stay accurate.": "Escolha como esta página deve permanecer precisa.",
"Recurring verification": "Verificação recorrente",
"Verifiers re-confirm this page on a schedule.": "Os verificadores confirmam novamente esta página em uma programação definida.",
"Re-verify on a schedule (e.g every 30 days )": "Verificar novamente em uma programação definida (ex.: a cada 30 dias)",
"Page stays editable at all times": "A página permanece editável o tempo todo",
"Best for runbooks, FAQs, living documentation": "Ideal para runbooks, FAQs e documentação viva",
"Approval workflow": "Fluxo de aprovação",
"Formal document lifecycle with named approvers.": "Ciclo de vida formal do documento com aprovadores nomeados.",
"Draft → In approval → Approved → Obsolete": "Rascunho → Em aprovação → Aprovado → Obsoleto",
"Locked once approved, with full history": "Bloqueado após a aprovação, com histórico completo",
"Designed for ISO 9001, ISO 13485, and FDA": "Desenvolvido para ISO 9001, ISO 13485 e FDA",
"Best for SOPs and controlled documents": "Ideal para POPs e documentos controlados",
"Back": "Voltar",
"Quality management": "Gestão da qualidade",
"Recurring": "Recorrente",
"Pages move through draft, approval, and approved stages.": "As páginas passam pelos estágios de rascunho, aprovação e aprovado.",
"Verifiers": "Verificadores",
"Add verifier": "Adicionar verificador",
"I've reviewed this page for accuracy": "Revisei esta página quanto à precisão",
"Set up": "Configurar",
"Remove verification": "Remover verificação",
"Are you sure you want to remove verification from this page?": "Tem certeza de que deseja remover a verificação desta página?",
"Assigned verifiers must periodically re-verify this page.": "Os verificadores atribuídos devem verificar novamente esta página periodicamente.",
"Last verified by {{name}} {{time}} (expired)": "Verificado pela última vez por {{name}} {{time}} (expirado)",
"The fixed expiration date has passed.": "A data fixa de expiração já passou.",
"Verified by {{name}} {{time}}": "Verificado por {{name}} {{time}}",
"Expires {{date}}": "Expira em {{date}}",
"Expired {{date}}": "Expirou em {{date}}",
"Mark as obsolete": "Marcar como obsoleto",
"Mark obsolete": "Marcar como obsoleto",
"Returned by {{name}} {{time}}": "Devolvido por {{name}} {{time}}",
"No approval has been requested yet.": "Nenhuma aprovação foi solicitada ainda.",
"Submitted by {{name}} {{time}}": "Enviado por {{name}} {{time}}",
"Someone": "Alguém",
"Approved by {{name}} {{time}}": "Aprovado por {{name}} {{time}}",
"This document has been marked as obsolete.": "Este documento foi marcado como obsoleto.",
"Rejection comment": "Comentário de rejeição",
"Reason for returning this document...": "Motivo para devolver este documento...",
"Confirm rejection": "Confirmar rejeição",
"Submit for approval": "Enviar para aprovação",
"Reject": "Rejeitar",
"Approve": "Aprovar",
"Re-submit for approval": "Reenviar para aprovação",
"Verified until": "Verificado até",
"QMS": "SGQ",
"Verified pages": "Páginas verificadas",
"Search pages...": "Pesquisar páginas...",
"Filter by space": "Filtrar por espaço",
"Filter by type": "Filtrar por tipo",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> verificou uma página",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> enviou uma página para sua aprovação",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> devolveu uma página para revisão",
"Page verification expires soon": "A verificação da página expirará em breve",
"Page verification has expired": "A verificação da página expirou",
"Verifying your email": "Verificando seu e-mail",
"Please wait...": "Por favor, aguarde...",
"Verification failed. The link may have expired.": "Falha na verificação. O link pode ter expirado.",
@@ -739,93 +739,6 @@
"Removed page restriction": "Ограничение доступа к странице удалено",
"Added page permission": "Добавлено разрешение доступа к странице",
"Removed page permission": "Удалено разрешение доступа к странице",
"day": "день",
"days": "дни",
"week": "неделя",
"weeks": "недели",
"month": "месяц",
"months": "месяцы",
"year": "год",
"years": "годы",
"Period": "Период",
"Fixed date": "Фиксированная дата",
"Indefinitely": "Бессрочно",
"Days": "Дни",
"Weeks": "Недели",
"Months": "Месяцы",
"Years": "Годы",
"Pick a date": "Выберите дату",
"Maximum is {{max}} {{unit}} for this unit": "Максимум для этой единицы измерения — {{max}} {{unit}}",
"Never expires. Verifiers can re-verify at any time.": "Срок действия не истекает. Проверяющие могут повторно подтверждать в любое время.",
"Verified": "Проверено",
"Review needed": "Требуется проверка",
"Verification expired": "Срок проверки истёк",
"Draft": "Черновик",
"In Approval": "На утверждении",
"In approval": "На утверждении",
"Approved": "Утверждено",
"Obsolete": "Устарело",
"Expiring": "Истекает",
"Set up verification": "Настроить проверку",
"Verify page": "Проверить страницу",
"Page verification": "Проверка страницы",
"Add verification": "Добавить проверку",
"Edit verification": "Изменить проверку",
"Search by title": "Поиск по заголовку",
"Choose how this page should stay accurate.": "Выберите, как поддерживать актуальность этой страницы.",
"Recurring verification": "Регулярная проверка",
"Verifiers re-confirm this page on a schedule.": "Проверяющие повторно подтверждают эту страницу по расписанию.",
"Re-verify on a schedule (e.g every 30 days )": "Повторно проверять по расписанию (например, каждые 30 дней)",
"Page stays editable at all times": "Страница остаётся редактируемой в любое время",
"Best for runbooks, FAQs, living documentation": "Лучше всего подходит для инструкций, FAQ и живой документации",
"Approval workflow": "Процесс утверждения",
"Formal document lifecycle with named approvers.": "Формальный жизненный цикл документа с назначенными утверждающими.",
"Draft → In approval → Approved → Obsolete": "Черновик → На утверждении → Утверждено → Устарело",
"Locked once approved, with full history": "После утверждения блокируется, с полной историей",
"Designed for ISO 9001, ISO 13485, and FDA": "Разработано для ISO 9001, ISO 13485 и FDA",
"Best for SOPs and controlled documents": "Лучше всего подходит для СОП и контролируемых документов",
"Back": "Назад",
"Quality management": "Управление качеством",
"Recurring": "Регулярно",
"Pages move through draft, approval, and approved stages.": "Страницы проходят стадии черновика, утверждения и утверждённого состояния.",
"Verifiers": "Проверяющие",
"Add verifier": "Добавить проверяющего",
"I've reviewed this page for accuracy": "Я проверил(а) эту страницу на точность",
"Set up": "Настроить",
"Remove verification": "Удалить проверку",
"Are you sure you want to remove verification from this page?": "Вы уверены, что хотите удалить проверку с этой страницы?",
"Assigned verifiers must periodically re-verify this page.": "Назначенные проверяющие должны периодически повторно проверять эту страницу.",
"Last verified by {{name}} {{time}} (expired)": "Последняя проверка: {{name}}, {{time}} (срок истёк)",
"The fixed expiration date has passed.": "Фиксированная дата истечения срока уже прошла.",
"Verified by {{name}} {{time}}": "Проверено: {{name}}, {{time}}",
"Expires {{date}}": "Истекает {{date}}",
"Expired {{date}}": "Срок истёк {{date}}",
"Mark as obsolete": "Отметить как устаревшее",
"Mark obsolete": "Отметить как устаревшее",
"Returned by {{name}} {{time}}": "Возвращено: {{name}}, {{time}}",
"No approval has been requested yet.": "Запрос на утверждение ещё не отправлен.",
"Submitted by {{name}} {{time}}": "Отправлено: {{name}}, {{time}}",
"Someone": "Кто-то",
"Approved by {{name}} {{time}}": "Утверждено: {{name}}, {{time}}",
"This document has been marked as obsolete.": "Этот документ был отмечен как устаревший.",
"Rejection comment": "Комментарий к отклонению",
"Reason for returning this document...": "Причина возврата этого документа...",
"Confirm rejection": "Подтвердить отклонение",
"Submit for approval": "Отправить на утверждение",
"Reject": "Отклонить",
"Approve": "Утвердить",
"Re-submit for approval": "Повторно отправить на утверждение",
"Verified until": "Проверено до",
"QMS": "QMS",
"Verified pages": "Проверенные страницы",
"Search pages...": "Поиск страниц...",
"Filter by space": "Фильтр по пространству",
"Filter by type": "Фильтр по типу",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> проверил(а) страницу",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> отправил(а) страницу вам на утверждение",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> вернул(а) страницу на доработку",
"Page verification expires soon": "Срок проверки страницы скоро истекает",
"Page verification has expired": "Срок проверки страницы истёк",
"Verifying your email": "Подтверждение вашего адреса электронной почты",
"Please wait...": "Пожалуйста, подождите...",
"Verification failed. The link may have expired.": "Ошибка проверки. Ссылка могла устареть.",
@@ -739,93 +739,6 @@
"Removed page restriction": "Обмеження сторінки видалено",
"Added page permission": "Додано дозвіл на сторінку",
"Removed page permission": "Дозвіл на сторінку видалено",
"day": "день",
"days": "дні",
"week": "тиждень",
"weeks": "тижні",
"month": "місяць",
"months": "місяці",
"year": "рік",
"years": "роки",
"Period": "Період",
"Fixed date": "Фіксована дата",
"Indefinitely": "Безстроково",
"Days": "Дні",
"Weeks": "Тижні",
"Months": "Місяці",
"Years": "Роки",
"Pick a date": "Виберіть дату",
"Maximum is {{max}} {{unit}} for this unit": "Максимум для цієї одиниці — {{max}} {{unit}}",
"Never expires. Verifiers can re-verify at any time.": "Термін дії не спливає. Верифікатори можуть повторно перевірити будь-коли.",
"Verified": "Перевірено",
"Review needed": "Потрібен перегляд",
"Verification expired": "Термін перевірки сплив",
"Draft": "Чернетка",
"In Approval": "На погодженні",
"In approval": "На погодженні",
"Approved": "Погоджено",
"Obsolete": "Застаріло",
"Expiring": "Термін дії спливає",
"Set up verification": "Налаштувати перевірку",
"Verify page": "Перевірити сторінку",
"Page verification": "Перевірка сторінки",
"Add verification": "Додати перевірку",
"Edit verification": "Редагувати перевірку",
"Search by title": "Пошук за назвою",
"Choose how this page should stay accurate.": "Виберіть, як підтримувати актуальність цієї сторінки.",
"Recurring verification": "Регулярна перевірка",
"Verifiers re-confirm this page on a schedule.": "Верифікатори повторно підтверджують цю сторінку за розкладом.",
"Re-verify on a schedule (e.g every 30 days )": "Повторно перевіряти за розкладом (наприклад, кожні 30 днів)",
"Page stays editable at all times": "Сторінка залишається доступною для редагування в будь-який час",
"Best for runbooks, FAQs, living documentation": "Найкраще підходить для runbook-ів, FAQ і живої документації",
"Approval workflow": "Процес погодження",
"Formal document lifecycle with named approvers.": "Формальний життєвий цикл документа з призначеними погоджувачами.",
"Draft → In approval → Approved → Obsolete": "Чернетка → На погодженні → Погоджено → Застаріло",
"Locked once approved, with full history": "Після погодження блокується, із повною історією",
"Designed for ISO 9001, ISO 13485, and FDA": "Призначено для ISO 9001, ISO 13485 та FDA",
"Best for SOPs and controlled documents": "Найкраще підходить для SOP і контрольованих документів",
"Back": "Назад",
"Quality management": "Управління якістю",
"Recurring": "Регулярна",
"Pages move through draft, approval, and approved stages.": "Сторінки проходять стадії чернетки, погодження та погодженого документа.",
"Verifiers": "Верифікатори",
"Add verifier": "Додати верифікатора",
"I've reviewed this page for accuracy": "Я перевірив(ла) цю сторінку на точність",
"Set up": "Налаштувати",
"Remove verification": "Видалити перевірку",
"Are you sure you want to remove verification from this page?": "Ви впевнені, що хочете видалити перевірку з цієї сторінки?",
"Assigned verifiers must periodically re-verify this page.": "Призначені верифікатори мають періодично повторно перевіряти цю сторінку.",
"Last verified by {{name}} {{time}} (expired)": "Востаннє перевірив(-ла) {{name}} {{time}} (термін дії сплив)",
"The fixed expiration date has passed.": "Фіксована дата завершення вже минула.",
"Verified by {{name}} {{time}}": "Перевірено: {{name}} {{time}}",
"Expires {{date}}": "Термін дії спливає {{date}}",
"Expired {{date}}": "Термін дії сплив {{date}}",
"Mark as obsolete": "Позначити як застаріле",
"Mark obsolete": "Позначити як застаріле",
"Returned by {{name}} {{time}}": "Повернуто: {{name}} {{time}}",
"No approval has been requested yet.": "Запит на погодження ще не було надіслано.",
"Submitted by {{name}} {{time}}": "Надіслано: {{name}} {{time}}",
"Someone": "Хтось",
"Approved by {{name}} {{time}}": "Погоджено: {{name}} {{time}}",
"This document has been marked as obsolete.": "Цей документ позначено як застарілий.",
"Rejection comment": "Коментар щодо відхилення",
"Reason for returning this document...": "Причина повернення цього документа...",
"Confirm rejection": "Підтвердити відхилення",
"Submit for approval": "Надіслати на погодження",
"Reject": "Відхилити",
"Approve": "Погодити",
"Re-submit for approval": "Повторно надіслати на погодження",
"Verified until": "Перевірено до",
"QMS": "QMS",
"Verified pages": "Перевірені сторінки",
"Search pages...": "Шукати сторінки...",
"Filter by space": "Фільтрувати за простором",
"Filter by type": "Фільтрувати за типом",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> перевірив(-ла) сторінку",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> надіслав(-ла) сторінку вам на погодження",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> повернув(-ла) сторінку на доопрацювання",
"Page verification expires soon": "Термін перевірки сторінки скоро спливає",
"Page verification has expired": "Термін перевірки сторінки сплив",
"Verifying your email": "Перевірка вашої електронної пошти",
"Please wait...": "Будь ласка, зачекайте...",
"Verification failed. The link may have expired.": "Підтвердження не вдалося. Посилання могло втратити чинність.",
@@ -739,93 +739,6 @@
"Removed page restriction": "已移除页面限制",
"Added page permission": "已添加页面权限",
"Removed page permission": "已移除页面权限",
"day": "天",
"days": "天",
"week": "周",
"weeks": "周",
"month": "个月",
"months": "个月",
"year": "年",
"years": "年",
"Period": "周期",
"Fixed date": "固定日期",
"Indefinitely": "无限期",
"Days": "天",
"Weeks": "周",
"Months": "个月",
"Years": "年",
"Pick a date": "选择日期",
"Maximum is {{max}} {{unit}} for this unit": "此单位的最大值为 {{max}} {{unit}}",
"Never expires. Verifiers can re-verify at any time.": "永不过期。验证者可随时重新验证。",
"Verified": "已验证",
"Review needed": "需要审核",
"Verification expired": "验证已过期",
"Draft": "草稿",
"In Approval": "审批中",
"In approval": "审批中",
"Approved": "已批准",
"Obsolete": "已作废",
"Expiring": "即将过期",
"Set up verification": "设置验证",
"Verify page": "验证页面",
"Page verification": "页面验证",
"Add verification": "添加验证",
"Edit verification": "编辑验证",
"Search by title": "按标题搜索",
"Choose how this page should stay accurate.": "选择此页面保持准确的方式。",
"Recurring verification": "定期验证",
"Verifiers re-confirm this page on a schedule.": "验证者按计划重新确认此页面。",
"Re-verify on a schedule (e.g every 30 days )": "按计划重新验证(例如每 30 天一次)",
"Page stays editable at all times": "页面始终可编辑",
"Best for runbooks, FAQs, living documentation": "最适合运行手册、常见问题和动态文档",
"Approval workflow": "审批工作流",
"Formal document lifecycle with named approvers.": "具有指定审批人的正式文档生命周期。",
"Draft → In approval → Approved → Obsolete": "草稿 → 审批中 → 已批准 → 已作废",
"Locked once approved, with full history": "批准后锁定,并保留完整历史记录",
"Designed for ISO 9001, ISO 13485, and FDA": "专为 ISO 9001、ISO 13485 和 FDA 设计",
"Best for SOPs and controlled documents": "最适合 SOP 和受控文档",
"Back": "返回",
"Quality management": "质量管理",
"Recurring": "定期",
"Pages move through draft, approval, and approved stages.": "页面会经历草稿、审批中和已批准阶段。",
"Verifiers": "验证者",
"Add verifier": "添加验证者",
"I've reviewed this page for accuracy": "我已审核此页面的准确性",
"Set up": "设置",
"Remove verification": "移除验证",
"Are you sure you want to remove verification from this page?": "确定要移除此页面的验证吗?",
"Assigned verifiers must periodically re-verify this page.": "指定的验证者必须定期重新验证此页面。",
"Last verified by {{name}} {{time}} (expired)": "最后由 {{name}} 于 {{time}} 验证(已过期)",
"The fixed expiration date has passed.": "固定到期日已过。",
"Verified by {{name}} {{time}}": "由 {{name}} 于 {{time}} 验证",
"Expires {{date}}": "于 {{date}} 到期",
"Expired {{date}}": "已于 {{date}} 过期",
"Mark as obsolete": "标记为作废",
"Mark obsolete": "标记作废",
"Returned by {{name}} {{time}}": "由 {{name}} 于 {{time}} 退回",
"No approval has been requested yet.": "尚未请求审批。",
"Submitted by {{name}} {{time}}": "由 {{name}} 于 {{time}} 提交",
"Someone": "某人",
"Approved by {{name}} {{time}}": "由 {{name}} 于 {{time}} 批准",
"This document has been marked as obsolete.": "此文档已被标记为作废。",
"Rejection comment": "退回意见",
"Reason for returning this document...": "退回此文档的原因...",
"Confirm rejection": "确认退回",
"Submit for approval": "提交审批",
"Reject": "退回",
"Approve": "批准",
"Re-submit for approval": "重新提交审批",
"Verified until": "验证有效期至",
"QMS": "QMS",
"Verified pages": "已验证页面",
"Search pages...": "搜索页面...",
"Filter by space": "按空间筛选",
"Filter by type": "按类型筛选",
"<bold>{{name}}</bold> verified a page": "<bold>{{name}}</bold> 验证了一个页面",
"<bold>{{name}}</bold> submitted a page for your approval": "<bold>{{name}}</bold> 提交了一个页面供您审批",
"<bold>{{name}}</bold> returned a page for revision": "<bold>{{name}}</bold> 退回了一个页面以供修改",
"Page verification expires soon": "页面验证即将过期",
"Page verification has expired": "页面验证已过期",
"Verifying your email": "正在验证您的邮箱",
"Please wait...": "请稍候……",
"Verification failed. The link may have expired.": "验证失败。该链接可能已过期。",
-2
View File
@@ -26,7 +26,6 @@ import Security from "@/ee/security/pages/security.tsx";
import License from "@/ee/licence/pages/license.tsx";
import { useRedirectToCloudSelect } from "@/ee/hooks/use-redirect-to-cloud-select.tsx";
import SharedPage from "@/pages/share/shared-page.tsx";
import PdfRenderPage from "@/ee/pdf-export/pdf-render-page.tsx";
import Shares from "@/pages/settings/shares/shares.tsx";
import ShareLayout from "@/features/share/components/share-layout.tsx";
import ShareRedirect from "@/pages/share/share-redirect.tsx";
@@ -82,7 +81,6 @@ export default function App() {
<Route path={"/share/p/:pageSlug"} element={<SharedPage />} />
</Route>
<Route path={"/pdf-render/:pageId"} element={<PdfRenderPage />} />
<Route path={"/share/:shareId"} element={<ShareRedirect />} />
<Route path={"/p/:pageSlug"} element={<PageRedirect />} />
@@ -1,64 +0,0 @@
import "@/features/editor/styles/index.css";
import { useEffect, useState } from "react";
import { useParams, useSearchParams } from "react-router-dom";
import ReadonlyPageEditor from "@/features/editor/readonly-page-editor";
import { Container } from "@mantine/core";
type PdfRenderData = {
pageId: string;
title: string;
content: any;
};
export default function PdfRenderPage() {
const { pageId } = useParams<{ pageId: string }>();
const [searchParams] = useSearchParams();
const token = searchParams.get("token");
const [data, setData] = useState<PdfRenderData | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!pageId || !token) {
setError("Missing page ID or token");
return;
}
fetch('/api/pdf-export/render', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pageId, token }),
})
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then((result) => setData(result.data))
.catch((err) => setError(err.message));
}, [pageId, token]);
useEffect(() => {
if (data?.title) {
document.title = data.title;
}
}, [data?.title]);
if (error) {
return <div>{error}</div>;
}
if (!data) {
return null;
}
return (
<Container size={900} p={0}>
<ReadonlyPageEditor
key={data.pageId}
title={data.title}
content={data.content}
pageId={data.pageId}
/>
</Container>
);
}
@@ -102,7 +102,6 @@ function PageByline({
<Group
gap="sm"
mb="md"
className="print-hide"
style={{ marginTop: "-0.5em", paddingLeft: "3rem" }}
>
{creator && (
@@ -14,11 +14,11 @@ import {
} from "../services/favorite-service";
import { FavoriteType } from "../types/favorite.types";
export function useFavoritesQuery(type?: FavoriteType, spaceId?: string) {
export function useFavoritesQuery(type?: FavoriteType) {
return useInfiniteQuery({
queryKey: ["favorites", type, spaceId],
queryKey: ["favorites", type],
queryFn: ({ pageParam }) =>
getFavorites({ type, spaceId, cursor: pageParam, limit: 15 }),
getFavorites({ type, cursor: pageParam, limit: 15 }),
initialPageParam: undefined as string | undefined,
getNextPageParam: (lastPage) =>
lastPage.meta.hasNextPage ? lastPage.meta.nextCursor : undefined,
@@ -26,10 +26,10 @@ export function useFavoritesQuery(type?: FavoriteType, spaceId?: string) {
});
}
export function useFavoriteIds(type: FavoriteType, spaceId?: string): Set<string> {
export function useFavoriteIds(type: FavoriteType): Set<string> {
const { data } = useQuery({
queryKey: ["favorite-ids", type, spaceId],
queryFn: () => getFavoriteIds(type, spaceId),
queryKey: ["favorite-ids", type],
queryFn: () => getFavoriteIds(type),
refetchOnMount: true,
});
@@ -52,9 +52,9 @@ export function useAddFavoriteMutation() {
onSuccess: (_result, variables) => {
const entityId = getEntityId(variables);
if (entityId) {
queryClient.setQueriesData<{ items: string[]; meta: any }>(
{ queryKey: ["favorite-ids", variables.type] },
(old) => {
queryClient.setQueryData(
["favorite-ids", variables.type],
(old: { items: string[]; meta: any } | undefined) => {
if (!old) return old;
if (old.items.includes(entityId)) return old;
return { ...old, items: [...old.items, entityId] };
@@ -76,9 +76,9 @@ export function useRemoveFavoriteMutation() {
onSuccess: (_result, variables) => {
const entityId = getEntityId(variables);
if (entityId) {
queryClient.setQueriesData<{ items: string[]; meta: any }>(
{ queryKey: ["favorite-ids", variables.type] },
(old) => {
queryClient.setQueryData(
["favorite-ids", variables.type],
(old: { items: string[]; meta: any } | undefined) => {
if (!old) return old;
return { ...old, items: old.items.filter((id) => id !== entityId) };
},
@@ -21,14 +21,13 @@ export async function removeFavorite(
await api.post("/favorites/remove", params);
}
export async function getFavoriteIds(type: FavoriteType, spaceId?: string): Promise<IPagination<string>> {
const req = await api.post<IPagination<string>>("/favorites/ids", { type, spaceId });
export async function getFavoriteIds(type: FavoriteType): Promise<IPagination<string>> {
const req = await api.post<IPagination<string>>("/favorites/ids", { type });
return req.data;
}
export async function getFavorites(params?: {
type?: FavoriteType;
spaceId?: string;
limit?: number;
cursor?: string;
}): Promise<IPagination<IFavorite>> {
@@ -18,11 +18,7 @@ import { getSpaceUrl } from "@/lib/config";
import { useTranslation } from "react-i18next";
import { getInitialsColor } from "@/lib/get-initials-color";
interface Props {
spaceId?: string;
}
export default function FavoritesPages({ spaceId }: Props) {
export default function FavoritesPages() {
const { t } = useTranslation();
const {
data,
@@ -31,7 +27,7 @@ export default function FavoritesPages({ spaceId }: Props) {
hasNextPage,
fetchNextPage,
isFetchingNextPage,
} = useFavoritesQuery("page", spaceId);
} = useFavoritesQuery("page");
const favorites = data?.pages.flatMap((p) => p.items) ?? [];
@@ -76,21 +72,19 @@ export default function FavoritesPages({ spaceId }: Props) {
</Group>
</UnstyledButton>
</Table.Td>
{!spaceId && (
<Table.Td>
{fav.space && (
<Badge
color={getInitialsColor(fav.space.name)}
variant="light"
component={Link}
to={getSpaceUrl(fav.space.slug)}
style={{ cursor: "pointer" }}
>
{fav.space.name}
</Badge>
)}
</Table.Td>
)}
<Table.Td>
{fav.space && (
<Badge
color={getInitialsColor(fav.space.name)}
variant="light"
component={Link}
to={getSpaceUrl(fav.space.slug)}
style={{ cursor: "pointer" }}
>
{fav.space.name}
</Badge>
)}
</Table.Td>
<Table.Td>
<Text
c="dimmed"
@@ -145,7 +145,7 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
] = useDisclosure(false);
const [pageEditor] = useAtom(pageEditorAtom);
const pageUpdatedAt = useTimeAgo(page?.updatedAt);
const favoriteIds = useFavoriteIds("page", page?.spaceId);
const favoriteIds = useFavoriteIds("page");
const addFavoriteMutation = useAddFavoriteMutation();
const removeFavoriteMutation = useRemoveFavoriteMutation();
const isFavorited = page?.id ? favoriteIds.has(page.id) : false;
@@ -509,7 +509,7 @@ function NodeMenu({ node, treeApi, spaceId }: NodeMenuProps) {
copyPageModalOpened,
{ open: openCopyPageModal, close: closeCopySpaceModal },
] = useDisclosure(false);
const favoriteIds = useFavoriteIds("page", spaceId);
const favoriteIds = useFavoriteIds("page");
const addFavorite = useAddFavoriteMutation();
const removeFavorite = useRemoveFavoriteMutation();
const isFavorited = favoriteIds.has(node.data.id);
@@ -47,7 +47,7 @@ export default function SpaceHomeTabs() {
{space?.id && <RecentChanges spaceId={space.id} />}
</Tabs.Panel>
<Tabs.Panel value="favorites">
{space?.id && <FavoritesPages spaceId={space.id} />}
<FavoritesPages />
</Tabs.Panel>
<Tabs.Panel value="created">
{space?.id && <CreatedByMe spaceId={space.id} />}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "server",
"version": "0.80.0",
"version": "0.71.1",
"description": "",
"author": "",
"private": true,
-1
View File
@@ -18,7 +18,6 @@ export const Feature = {
SHARING_CONTROLS: 'sharing:controls',
VIEWER_COMMENTS: 'comment:viewer',
TEMPLATES: 'templates',
PDF_EXPORT: 'export:pdf',
} as const;
export type FeatureKey = (typeof Feature)[keyof typeof Feature];
@@ -5,8 +5,6 @@ export enum JwtType {
ATTACHMENT = 'attachment',
MFA_TOKEN = 'mfa_token',
API_KEY = 'api_key',
PDF_RENDER = 'pdf_render',
PDF_EXPORT_DOWNLOAD = 'pdf_export_download',
}
export type JwtPayload = {
sub: string;
@@ -47,15 +45,3 @@ export type JwtApiKeyPayload = {
apiKeyId: string;
type: 'api_key';
};
export type JwtPdfRenderPayload = {
pageId: string;
workspaceId: string;
type: 'pdf_render';
};
export type JwtPdfExportDownloadPayload = {
fileTaskId: string;
workspaceId: string;
type: 'pdf_export_download';
};
@@ -13,8 +13,6 @@ import {
JwtExchangePayload,
JwtMfaTokenPayload,
JwtPayload,
JwtPdfExportDownloadPayload,
JwtPdfRenderPayload,
JwtType,
} from '../dto/jwt-payload';
import { User } from '@docmost/db/types/entity.types';
@@ -117,30 +115,6 @@ export class TokenService {
return this.jwtService.sign(payload, expiresIn ? { expiresIn } : {});
}
async generatePdfRenderToken(
pageId: string,
workspaceId: string,
): Promise<string> {
const payload: JwtPdfRenderPayload = {
pageId,
workspaceId,
type: JwtType.PDF_RENDER,
};
return this.jwtService.sign(payload, { expiresIn: '60s' });
}
async generatePdfExportDownloadToken(
fileTaskId: string,
workspaceId: string,
): Promise<string> {
const payload: JwtPdfExportDownloadPayload = {
fileTaskId,
workspaceId,
type: JwtType.PDF_EXPORT_DOWNLOAD,
};
return this.jwtService.sign(payload, { expiresIn: '1h' });
}
async verifyJwt(token: string, tokenType: string) {
const payload = await this.jwtService.verifyAsync(token, {
secret: this.environmentService.getAppSecret(),
@@ -1,12 +1,8 @@
import { IsIn, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
import { IsIn, IsNotEmpty, IsString } from 'class-validator';
export class FavoriteIdsDto {
@IsString()
@IsNotEmpty()
@IsIn(['page', 'space', 'template'])
type: 'page' | 'space' | 'template';
@IsOptional()
@IsUUID()
spaceId?: string;
}
@@ -1,12 +1,8 @@
import { IsIn, IsOptional, IsString, IsUUID } from 'class-validator';
import { IsIn, IsOptional, IsString } from 'class-validator';
export class ListFavoritesDto {
@IsOptional()
@IsString()
@IsIn(['page', 'space', 'template'])
type?: 'page' | 'space' | 'template';
@IsOptional()
@IsUUID()
spaceId?: string;
}
@@ -82,7 +82,6 @@ export class FavoriteController {
user.id,
workspace.id,
dto.type as FavoriteType,
dto.spaceId,
);
}
@@ -99,7 +98,6 @@ export class FavoriteController {
workspace.id,
pagination,
dto.type as FavoriteType | undefined,
dto.spaceId,
);
}
@@ -20,13 +20,11 @@ export class FavoriteService {
userId: string,
workspaceId: string,
type: FavoriteType,
spaceId?: string,
) {
const result = await this.favoriteRepo.getFavoriteIds(
userId,
workspaceId,
type,
spaceId,
);
if (result.items.length === 0) {
@@ -97,14 +95,12 @@ export class FavoriteService {
workspaceId: string,
pagination: PaginationOptions,
type?: FavoriteType,
spaceId?: string,
) {
const result = await this.favoriteRepo.findUserFavorites(
userId,
workspaceId,
pagination,
type,
spaceId,
);
if (result.items.length === 0) {
@@ -1,32 +0,0 @@
import { Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.alterTable('file_tasks')
.addColumn('page_id', 'uuid', (col) =>
col.references('pages.id').onDelete('set null').ifNotExists(),
)
.execute();
await db.schema
.alterTable('file_tasks')
.addColumn('metadata', 'jsonb', (col) => col.ifNotExists())
.execute();
await db.schema
.createIndex('idx_file_tasks_page_export')
.ifNotExists()
.on('file_tasks')
.columns(['page_id', 'workspace_id'])
.where(sql.ref('type'), '=', 'export')
.where(sql.ref('deleted_at'), 'is', null)
.execute();
}
export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropIndex('idx_file_tasks_page_export').execute();
await db.schema.alterTable('file_tasks').dropColumn('page_id').execute();
await db.schema.alterTable('file_tasks').dropColumn('metadata').execute();
}
@@ -5,7 +5,7 @@ import { InsertableFavorite, Favorite } from '@docmost/db/types/entity.types';
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
import { executeWithCursorPagination } from '@docmost/db/pagination/cursor-pagination';
import { jsonObjectFrom } from 'kysely/helpers/postgres';
import { ExpressionBuilder, SelectQueryBuilder, sql } from 'kysely';
import { ExpressionBuilder, sql } from 'kysely';
import { DB } from '@docmost/db/types/db';
import { dbOrTx } from '@docmost/db/utils';
@@ -66,7 +66,6 @@ export class FavoriteRepo {
userId: string,
workspaceId: string,
type: FavoriteType,
spaceId?: string,
): Promise<{ items: string[]; meta: any }> {
const idColumn =
type === FavoriteType.PAGE
@@ -75,16 +74,12 @@ export class FavoriteRepo {
? 'spaceId'
: 'templateId';
let query = this.db
const query = this.db
.selectFrom('favorites')
.select(['favorites.id', `favorites.${idColumn} as entityId`])
.where('favorites.userId', '=', userId)
.where('favorites.workspaceId', '=', workspaceId)
.where('favorites.type', '=', type);
if (spaceId) {
query = this.applySpaceFilter(query, type, spaceId);
}
.where('userId', '=', userId)
.where('workspaceId', '=', workspaceId)
.where('type', '=', type);
const result = await executeWithCursorPagination(query, {
perPage: 250,
@@ -105,7 +100,6 @@ export class FavoriteRepo {
workspaceId: string,
pagination: PaginationOptions,
type?: FavoriteType,
spaceId?: string,
) {
let query = this.db
.selectFrom('favorites')
@@ -117,10 +111,6 @@ export class FavoriteRepo {
query = query.where('favorites.type', '=', type);
}
if (spaceId) {
query = this.applySpaceFilter(query, type, spaceId);
}
if (type === FavoriteType.PAGE || !type) {
query = query.select((eb) => this.withPage(eb));
}
@@ -194,39 +184,6 @@ export class FavoriteRepo {
.execute();
}
private applySpaceFilter<Q extends SelectQueryBuilder<any, any, any>>(
query: Q,
type: FavoriteType | undefined,
spaceId: string,
): Q {
if (type === FavoriteType.PAGE) {
return query.where((eb: any) =>
eb.exists(
eb
.selectFrom('pages')
.select(sql`1`.as('one'))
.whereRef('pages.id', '=', 'favorites.pageId')
.where('pages.spaceId', '=', spaceId),
),
) as Q;
}
if (type === FavoriteType.SPACE) {
return query.where('favorites.spaceId' as any, '=', spaceId) as Q;
}
if (type === FavoriteType.TEMPLATE) {
return query.where((eb: any) =>
eb.exists(
eb
.selectFrom('templates')
.select(sql`1`.as('one'))
.whereRef('templates.id', '=', 'favorites.templateId')
.where('templates.spaceId', '=', spaceId),
),
) as Q;
}
return query;
}
private withPage(eb: ExpressionBuilder<DB, 'favorites'>) {
return jsonObjectFrom(
eb
-2
View File
@@ -196,8 +196,6 @@ export interface FileTasks {
filePath: string;
fileSize: Int8 | null;
id: Generated<string>;
metadata: Json | null;
pageId: string | null;
source: string | null;
spaceId: string | null;
status: string | null;
@@ -75,10 +75,6 @@ export class EnvironmentService {
return new Date(Date.now() + msUntilExpiry);
}
getGotenbergUrl(): string | undefined {
return this.configService.get<string>('GOTENBERG_URL');
}
getStorageDriver(): string {
return this.configService.get<string>('STORAGE_DRIVER', 'local');
}
@@ -5,9 +5,6 @@ import { QueueJob, QueueName } from 'src/integrations/queue/constants';
import { FileImportTaskService } from '../services/file-import-task.service';
import { FileTaskStatus } from '../utils/file.utils';
import { StorageService } from '../../storage/storage.service';
import { ModuleRef } from '@nestjs/core';
import { InjectKysely } from 'nestjs-kysely';
import { KyselyDB } from '@docmost/db/types/kysely.types';
@Processor(QueueName.FILE_TASK_QUEUE)
export class FileTaskProcessor extends WorkerHost implements OnModuleDestroy {
@@ -16,8 +13,6 @@ export class FileTaskProcessor extends WorkerHost implements OnModuleDestroy {
constructor(
private readonly fileTaskService: FileImportTaskService,
private readonly storageService: StorageService,
private readonly moduleRef: ModuleRef,
@InjectKysely() private readonly db: KyselyDB,
) {
super();
}
@@ -28,11 +23,8 @@ export class FileTaskProcessor extends WorkerHost implements OnModuleDestroy {
case QueueJob.IMPORT_TASK:
await this.fileTaskService.processZIpImport(job.data.fileTaskId);
break;
case QueueJob.PDF_EXPORT_TASK:
await this.processExportTask(job.data.fileTaskId);
break;
case QueueJob.PDF_EXPORT_CLEANUP:
await this.processExportCleanup();
case QueueJob.EXPORT_TASK:
// TODO: export task
break;
}
} catch (err) {
@@ -41,24 +33,6 @@ export class FileTaskProcessor extends WorkerHost implements OnModuleDestroy {
}
}
private getPdfExportService() {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const PdfExportModule = require('./../../../ee/pdf-export/pdf-export.service');
return this.moduleRef.get(PdfExportModule.PdfExportService, {
strict: false,
});
}
private async processExportTask(fileTaskId: string): Promise<void> {
const pdfExportService = this.getPdfExportService();
await pdfExportService.generateAndStorePdf(fileTaskId);
}
private async processExportCleanup(): Promise<void> {
const pdfExportService = this.getPdfExportService();
await pdfExportService.cleanupExpiredExports();
}
@OnWorkerEvent('active')
onActive(job: Job) {
this.logger.debug(`Processing ${job.name} job`);
@@ -67,39 +41,32 @@ export class FileTaskProcessor extends WorkerHost implements OnModuleDestroy {
@OnWorkerEvent('failed')
async onFailed(job: Job) {
this.logger.error(
`Error processing ${job.name} job. File Task ID: ${job.data?.fileTaskId}. Reason: ${job.failedReason}`,
`Error processing ${job.name} job. Import Task ID: ${job.data.fileTaskId}. Reason: ${job.failedReason}`,
);
if (job.name === QueueJob.IMPORT_TASK) {
await this.handleFailedImportJob(job);
} else if (job.name === QueueJob.PDF_EXPORT_TASK) {
await this.handleFailedExportJob(job);
}
await this.handleFailedJob(job);
}
@OnWorkerEvent('completed')
async onCompleted(job: Job) {
this.logger.log(
`Completed ${job.name} job for File task ID ${job.data?.fileTaskId}`,
`Completed ${job.name} job for File task ID ${job.data.fileTaskId}`,
);
if (job.name === QueueJob.IMPORT_TASK) {
try {
const fileTask = await this.fileTaskService.getFileTask(
job.data.fileTaskId,
);
if (fileTask) {
await this.storageService.delete(fileTask.filePath);
this.logger.debug(`Deleted imported zip file: ${fileTask.filePath}`);
}
} catch (err) {
this.logger.error(`Failed to delete imported zip file:`, err);
try {
const fileTask = await this.fileTaskService.getFileTask(
job.data.fileTaskId,
);
if (fileTask) {
await this.storageService.delete(fileTask.filePath);
this.logger.debug(`Deleted imported zip file: ${fileTask.filePath}`);
}
} catch (err) {
this.logger.error(`Failed to delete imported zip file:`, err);
}
// Export tasks: do NOT delete the file on completion (kept for 24h cache)
}
private async handleFailedImportJob(job: Job) {
private async handleFailedJob(job: Job) {
try {
const fileTaskId = job.data.fileTaskId;
const reason = job.failedReason || 'Unknown error';
@@ -119,25 +86,6 @@ export class FileTaskProcessor extends WorkerHost implements OnModuleDestroy {
}
}
private async handleFailedExportJob(job: Job) {
try {
const fileTaskId = job.data.fileTaskId;
const reason = job.failedReason || 'Unknown error';
await this.db
.updateTable('fileTasks')
.set({
status: FileTaskStatus.Failed,
errorMessage: reason,
updatedAt: new Date(),
})
.where('id', '=', fileTaskId)
.execute();
} catch (err) {
this.logger.error(err);
}
}
async onModuleDestroy(): Promise<void> {
if (this.worker) {
await this.worker.close();
@@ -80,7 +80,4 @@ export enum QueueJob {
AUDIT_LOG = 'audit-log',
AUDIT_CLEANUP = 'audit-cleanup',
PDF_EXPORT_TASK = 'pdf-export-task',
PDF_EXPORT_CLEANUP = 'pdf-export-cleanup',
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
"version": "0.80.0",
"version": "0.71.1",
"private": true,
"scripts": {
"build": "nx run-many -t build",