From 41a77ff0253fc947f5dae1fccf9a7c1a4a1ce408 Mon Sep 17 00:00:00 2001 From: Richard Kenneth <79406473+richarddkenneth@users.noreply.github.com> Date: Tue, 18 Aug 2026 12:00:52 +0100 Subject: [PATCH] fix: save regenerated course link on generate (#904) * improvement: save regenerated course link on generate * improvements: remove disabled prop from "new course link generate" btn as loading prop already serves; added console error logs for uncaught errs during save or new link generation --------- Co-authored-by: richarddkenneth Co-authored-by: Rotimi Best --- .../lib/features/automation/pages/mcp.svelte | 84 +++++++++---------- .../lib/features/course/pages/settings.svelte | 46 ++++++++-- .../src/lib/utils/translations/da.json | 6 +- .../src/lib/utils/translations/de.json | 6 +- .../src/lib/utils/translations/en.json | 6 +- .../src/lib/utils/translations/es.json | 6 +- .../src/lib/utils/translations/fr.json | 6 +- .../src/lib/utils/translations/hi.json | 6 +- .../src/lib/utils/translations/pl.json | 6 +- .../src/lib/utils/translations/pt.json | 6 +- .../src/lib/utils/translations/ru.json | 6 +- .../src/lib/utils/translations/vi.json | 6 +- .../routes/(app)/org/[slug]/mcp/+page.svelte | 7 +- 13 files changed, 131 insertions(+), 66 deletions(-) diff --git a/apps/dashboard/src/lib/features/automation/pages/mcp.svelte b/apps/dashboard/src/lib/features/automation/pages/mcp.svelte index 144649ef..ab6cc169 100644 --- a/apps/dashboard/src/lib/features/automation/pages/mcp.svelte +++ b/apps/dashboard/src/lib/features/automation/pages/mcp.svelte @@ -234,53 +234,53 @@ - - - {$t('automation.mcp.setup.title')} - - {$t('automation.mcp.setup.description')} + + + {$t('automation.mcp.setup.title')} + + {$t('automation.mcp.setup.description')} - - - {$t('automation.clients.cursor')} - {$t('automation.clients.claude_code')} - {$t('automation.clients.codex')} - {$t('automation.clients.opencode')} - + + + {$t('automation.clients.cursor')} + {$t('automation.clients.claude_code')} + {$t('automation.clients.codex')} + {$t('automation.clients.opencode')} + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + ([]); let initialTagIds = $state([]); let loadedCourseTagsForId = $state(null); + let initializedCourseId = $state(null); let isTagPopoverOpen = $state(false); function normalizeTagIds(tagIds: string[]) { @@ -285,14 +287,29 @@ hasUnsavedChanges = false; } } catch (error) { + console.error(error); snackbar.error(); } } - const generateNewCourseLink = () => { - if (!courseApi.course) return; - courseApi.course.slug = generateSlug(courseApi.course.title, { appendTimestamp: true }); - hasUnsavedChanges = true; + const generateNewCourseLink = async () => { + if (!courseApi.course || isGeneratingLink) return; + + isGeneratingLink = true; + try { + const newSlug = generateSlug(courseApi.course.title, { appendTimestamp: true }); + const response = await courseApi.update(courseApi.course.id, { slug: newSlug }, { showSuccessToast: false }); + + if (courseApi.success && response) { + courseApi.course.slug = response.slug ?? newSlug; + snackbar.success('snackbar.course_settings.success.link_generated'); + } + } catch (error) { + console.error(error); + snackbar.error(); + } finally { + isGeneratingLink = false; + } }; async function setDefault(course: Course) { @@ -389,8 +406,10 @@ }); $effect(() => { - if (courseApi.course) { - setDefault(courseApi.course); + const course = courseApi.course; + if (course?.id && initializedCourseId !== course.id) { + initializedCourseId = course.id; + setDefault(course); } }); @@ -590,10 +609,19 @@ >{$t('course.navItem.settings.link')}
- + - +
@@ -606,6 +634,8 @@ onclick={() => { copyToClipboard(courseLink); }} + disabled={isGeneratingLink} + tooltip={$t('course.navItem.settings.copy_link')} > diff --git a/apps/dashboard/src/lib/utils/translations/da.json b/apps/dashboard/src/lib/utils/translations/da.json index 92a470ce..54f13a06 100644 --- a/apps/dashboard/src/lib/utils/translations/da.json +++ b/apps/dashboard/src/lib/utils/translations/da.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Alle kursusartikler er låst op", "all_content_already_unlocked": "Alt indhold er allerede låst op", "content_grouping_enabled": "Indholdsgruppering aktiveret", - "content_grouping_disabled": "Indholdsgruppering deaktiveret" + "content_grouping_disabled": "Indholdsgruppering deaktiveret", + "link_generated": "Kursuslinket blev opdateret" } }, "people": { @@ -859,6 +860,9 @@ "description_live": "Låste lektioner og øvelser forbliver skjult for eleverne, indtil du låser dem op - nyttigt, hvis du udgiver indhold uge for uge.", "unlock_all": "Lås alle op" }, + "generate_link": "Generer nyt link", + "open_link": "Åbn link i ny fane", + "copy_link": "Kopiér link", "certificate_deadline_required": "Indstil certifikatfrist først", "certificate_deadline_required_description": "Overholdelseskurser kræver en certifikatfrist, før elever kan tilmeldes. Indstil venligst en deadline i kursusindstillingerne før udgivelse.", "go_to_completion_deadline": "Gå til fuldførelsesfristen", diff --git a/apps/dashboard/src/lib/utils/translations/de.json b/apps/dashboard/src/lib/utils/translations/de.json index 7d866f4a..d48d7017 100644 --- a/apps/dashboard/src/lib/utils/translations/de.json +++ b/apps/dashboard/src/lib/utils/translations/de.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Alle Kursgegenstände freigeschaltet", "all_content_already_unlocked": "Alle Inhalte sind bereits freigeschaltet", "content_grouping_enabled": "Inhaltsgruppierung aktiviert", - "content_grouping_disabled": "Inhaltsgruppierung deaktiviert" + "content_grouping_disabled": "Inhaltsgruppierung deaktiviert", + "link_generated": "Der Kurslink wurde erfolgreich aktualisiert" } }, "people": { @@ -859,6 +860,9 @@ "description_live": "Gesperrte Lektionen und Übungen bleiben den Schülern verborgen, bis Sie sie entsperren – nützlich, wenn Sie Inhalte Woche für Woche veröffentlichen.", "unlock_all": "Schalte alle frei" }, + "generate_link": "Neuen Link generieren", + "open_link": "Link in neuem Tab öffnen", + "copy_link": "Link kopieren", "certificate_deadline_required": "Legen Sie zuerst die Frist für das Zertifikat fest", "certificate_deadline_required_description": "Für Compliance-Kurse ist eine Zertifikatsfrist erforderlich, bevor Lernende eingeschrieben werden können. Bitte legen Sie vor der Veröffentlichung eine Frist in den Kurseinstellungen fest.", "go_to_completion_deadline": "Gehen Sie zur Abschlussfrist", diff --git a/apps/dashboard/src/lib/utils/translations/en.json b/apps/dashboard/src/lib/utils/translations/en.json index 3311d3aa..fb53d3da 100644 --- a/apps/dashboard/src/lib/utils/translations/en.json +++ b/apps/dashboard/src/lib/utils/translations/en.json @@ -3623,6 +3623,9 @@ "setup_landing_for_link": "Setup landing page to get course link", "coming_soon": "Coming soon", "link": "Course Link", + "generate_link": "Generate new link", + "open_link": "Open link in new tab", + "copy_link": "Copy link", "grading": "Grading", "reports": "Make grading reports available for lessons", "disabled": "Disabled", @@ -4251,7 +4254,8 @@ "saved": "Saved successfully", "successful_integration": "Integration successful", "successful_deletion": "Integration deleted", - "update_successful": "Update successful" + "update_successful": "Update successful", + "link_generated": "Course link updated successfully" }, "error": { "not_right": "Something's not right - Please try later", diff --git a/apps/dashboard/src/lib/utils/translations/es.json b/apps/dashboard/src/lib/utils/translations/es.json index d0b3fe97..f9534591 100644 --- a/apps/dashboard/src/lib/utils/translations/es.json +++ b/apps/dashboard/src/lib/utils/translations/es.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Todos los elementos del curso desbloqueados", "all_content_already_unlocked": "Todo el contenido ya está desbloqueado", "content_grouping_enabled": "Agrupación de contenidos activada", - "content_grouping_disabled": "Agrupación de contenidos desactivada" + "content_grouping_disabled": "Agrupación de contenidos desactivada", + "link_generated": "Enlace del curso actualizado exitosamente" } }, "people": { @@ -859,6 +860,9 @@ "description_live": "Las lecciones y ejercicios bloqueados permanecen ocultos para los estudiantes hasta que los desbloqueas, lo que resulta útil si publicas contenido semana tras semana.", "unlock_all": "Desbloquear todo" }, + "generate_link": "Generar nuevo enlace", + "open_link": "Abrir enlace en nueva pestaña", + "copy_link": "Copiar enlace", "certificate_deadline_required": "Establecer la fecha límite del certificado primero", "certificate_deadline_required_description": "Los cursos de cumplimiento requieren una fecha límite para el certificado antes de que los estudiantes puedan inscribirse. Establezca una fecha límite en la configuración del curso antes de publicarlo.", "go_to_completion_deadline": "Ir a la fecha límite de finalización", diff --git a/apps/dashboard/src/lib/utils/translations/fr.json b/apps/dashboard/src/lib/utils/translations/fr.json index eb53fa9c..5b8bbb05 100644 --- a/apps/dashboard/src/lib/utils/translations/fr.json +++ b/apps/dashboard/src/lib/utils/translations/fr.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Tous les éléments de cours débloqués", "all_content_already_unlocked": "Tout le contenu est déjà déverrouillé", "content_grouping_enabled": "Regroupement de contenu activé", - "content_grouping_disabled": "Regroupement de contenu désactivé" + "content_grouping_disabled": "Regroupement de contenu désactivé", + "link_generated": "Lien du cours mis à jour avec succès" } }, "people": { @@ -859,6 +860,9 @@ "description_live": "Les leçons et les exercices verrouillés restent cachés aux étudiants jusqu'à ce que vous les déverrouilliez, ce qui est utile si vous publiez du contenu semaine après semaine.", "unlock_all": "Débloquez tout" }, + "generate_link": "Générer un nouveau lien", + "open_link": "Ouvrir le lien dans un nouvel onglet", + "copy_link": "Copier le lien", "certificate_deadline_required": "Définir d'abord la date limite du certificat", "certificate_deadline_required_description": "Les cours de conformité nécessitent une date limite de certificat avant que les apprenants puissent être inscrits. Veuillez définir une date limite dans les paramètres du cours avant de publier.", "go_to_completion_deadline": "Accéder à la date limite d'achèvement", diff --git a/apps/dashboard/src/lib/utils/translations/hi.json b/apps/dashboard/src/lib/utils/translations/hi.json index 5eb93a82..ff1734e8 100644 --- a/apps/dashboard/src/lib/utils/translations/hi.json +++ b/apps/dashboard/src/lib/utils/translations/hi.json @@ -295,7 +295,8 @@ "unlocked_all_content": "सभी पाठ्यक्रम आइटम अनलॉक हो गए", "all_content_already_unlocked": "सभी सामग्री पहले से अनलॉक है", "content_grouping_enabled": "सामग्री समूहीकरण सक्षम", - "content_grouping_disabled": "सामग्री समूहीकरण अक्षम" + "content_grouping_disabled": "सामग्री समूहीकरण अक्षम", + "link_generated": "पाठ्यक्रम लिंक सफलतापूर्वक अपडेट किया गया" } }, "people": { @@ -860,6 +861,9 @@ "unlock_all": "सबको अनलॉक करें" }, "certificate_deadline_required": "पहले प्रमाणपत्र की समय सीमा निर्धारित करें", + "generate_link": "नया लिंक जनरेट करें", + "open_link": "नए टैब में लिंक खोलें", + "copy_link": "लिंक कॉपी करें", "certificate_deadline_required_description": "अनुपालन पाठ्यक्रमों में शिक्षार्थियों के नामांकन से पहले प्रमाणपत्र की समय सीमा की आवश्यकता होती है। कृपया प्रकाशन से पहले पाठ्यक्रम सेटिंग में एक समय सीमा निर्धारित करें।", "go_to_completion_deadline": "समापन समय सीमा पर जाएं", "completion_deadline_label": "कोर्स पूरा करने की समय सीमा", diff --git a/apps/dashboard/src/lib/utils/translations/pl.json b/apps/dashboard/src/lib/utils/translations/pl.json index 5209b98d..4a1e00d7 100644 --- a/apps/dashboard/src/lib/utils/translations/pl.json +++ b/apps/dashboard/src/lib/utils/translations/pl.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Wszystkie elementy kursu odblokowane", "all_content_already_unlocked": "Cała treść jest już odblokowana", "content_grouping_enabled": "Grupowanie treści włączone", - "content_grouping_disabled": "Grupowanie treści wyłączone" + "content_grouping_disabled": "Grupowanie treści wyłączone", + "link_generated": "Link do kursu został pomyślnie zaktualizowany" } }, "people": { @@ -860,6 +861,9 @@ "unlock_all": "Odblokuj wszystko" }, "certificate_deadline_required": "Najpierw ustal termin wydania certyfikatu", + "generate_link": "Wygeneruj nowy link", + "open_link": "Otwórz link w nowej karcie", + "copy_link": "Skopiuj link", "certificate_deadline_required_description": "Kursy zgodności wymagają wystawienia certyfikatu przed zapisaniem się na nie uczestników. Przed publikacją ustaw termin w ustawieniach kursu.", "go_to_completion_deadline": "Przejdź do terminu ukończenia", "completion_deadline_label": "Termin zakończenia kursu", diff --git a/apps/dashboard/src/lib/utils/translations/pt.json b/apps/dashboard/src/lib/utils/translations/pt.json index bf557863..ebea3cc9 100644 --- a/apps/dashboard/src/lib/utils/translations/pt.json +++ b/apps/dashboard/src/lib/utils/translations/pt.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Todos os itens do curso desbloqueados", "all_content_already_unlocked": "Todo o conteúdo já está desbloqueado", "content_grouping_enabled": "Agrupamento de conteúdo ativado", - "content_grouping_disabled": "Agrupamento de conteúdo desativado" + "content_grouping_disabled": "Agrupamento de conteúdo desativado", + "link_generated": "Link do curso atualizado com sucesso" } }, "people": { @@ -859,6 +860,9 @@ "description_live": "Aulas e exercícios bloqueados permanecem ocultos aos alunos até que você os desbloqueie – o que é útil se você liberar conteúdo semana após semana.", "unlock_all": "Desbloquear tudo" }, + "generate_link": "Gerar novo link", + "open_link": "Abrir link em nova aba", + "copy_link": "Copiar link", "certificate_deadline_required": "Defina o prazo do certificado primeiro", "certificate_deadline_required_description": "Os cursos de conformidade exigem um prazo de certificação antes que os alunos possam ser matriculados. Defina um prazo nas configurações do curso antes de publicar.", "go_to_completion_deadline": "Ir para o prazo de conclusão", diff --git a/apps/dashboard/src/lib/utils/translations/ru.json b/apps/dashboard/src/lib/utils/translations/ru.json index 290b1c76..bebb681d 100644 --- a/apps/dashboard/src/lib/utils/translations/ru.json +++ b/apps/dashboard/src/lib/utils/translations/ru.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Все предметы курса разблокированы", "all_content_already_unlocked": "Весь контент уже разблокирован", "content_grouping_enabled": "Группировка контента включена", - "content_grouping_disabled": "Группировка контента отключена" + "content_grouping_disabled": "Группировка контента отключена", + "link_generated": "Ссылка на курс успешно обновлена" } }, "people": { @@ -859,6 +860,9 @@ "description_live": "Заблокированные уроки и упражнения остаются скрытыми от учащихся, пока вы их не разблокируете. Это полезно, если вы выпускаете контент еженедельно.", "unlock_all": "Разблокировать все" }, + "generate_link": "Создать новую ссылку", + "open_link": "Открыть ссылку в новой вкладке", + "copy_link": "Скопировать ссылку", "certificate_deadline_required": "Сначала установите срок действия сертификата", "certificate_deadline_required_description": "Для прохождения курсов по соблюдению требований требуется крайний срок получения сертификата, прежде чем учащиеся смогут быть зачислены. Перед публикацией установите крайний срок в настройках курса.", "go_to_completion_deadline": "Перейти к сроку завершения", diff --git a/apps/dashboard/src/lib/utils/translations/vi.json b/apps/dashboard/src/lib/utils/translations/vi.json index e532274f..3f0e204f 100644 --- a/apps/dashboard/src/lib/utils/translations/vi.json +++ b/apps/dashboard/src/lib/utils/translations/vi.json @@ -295,7 +295,8 @@ "unlocked_all_content": "Tất cả các mục khóa học đã được mở khóa", "all_content_already_unlocked": "Tất cả nội dung đã được mở khóa", "content_grouping_enabled": "Đã bật nhóm nội dung", - "content_grouping_disabled": "Đã tắt nhóm nội dung" + "content_grouping_disabled": "Đã tắt nhóm nội dung", + "link_generated": "Liên kết khóa học được cập nhật thành công" } }, "people": { @@ -859,6 +860,9 @@ "description_live": "Các bài học và bài tập bị khóa sẽ được ẩn khỏi học sinh cho đến khi bạn mở khóa chúng — hữu ích nếu bạn phát hành nội dung hàng tuần.", "unlock_all": "Mở khóa tất cả" }, + "generate_link": "Tạo liên kết mới", + "open_link": "Mở liên kết trong tab mới", + "copy_link": "Sao chép liên kết", "certificate_deadline_required": "Đặt thời hạn chứng chỉ đầu tiên", "certificate_deadline_required_description": "Các khóa học tuân thủ yêu cầu thời hạn cấp chứng chỉ trước khi người học có thể đăng ký. Vui lòng đặt thời hạn trong cài đặt khóa học trước khi xuất bản.", "go_to_completion_deadline": "Đi tới thời hạn hoàn thành", diff --git a/apps/dashboard/src/routes/(app)/org/[slug]/mcp/+page.svelte b/apps/dashboard/src/routes/(app)/org/[slug]/mcp/+page.svelte index 1b448792..c0c05544 100644 --- a/apps/dashboard/src/routes/(app)/org/[slug]/mcp/+page.svelte +++ b/apps/dashboard/src/routes/(app)/org/[slug]/mcp/+page.svelte @@ -27,12 +27,7 @@ {$t('automation.mcp.page_subtitle')} -