Personenbezogene Daten werden nicht importiert.
Externe Tools werden nicht kopiert.
Der Kurs kann im Folgenden umbenannt werden.",
- "components.molecules.import.courses.options.infoText":
- "Es wird eine Kopie erstellt. Personenbezogene Daten werden nicht importiert. Der Kurs kann im Folgenden umbenannt werden.",
- "components.molecules.import.courses.options.title": "Kurs importieren",
+ "components.molecules.import.courses.rename":
+ "Bei Bedarf kann der Name des Kurses umbenannt werden: ",
+ "components.molecules.import.courses.options.title": "Kurs-Kopie importieren",
"components.molecules.import.lessons.label": "Thema",
- "components.molecules.import.lessons.options.infoText":
- "Es wird eine Kopie erstellt. Personenbezogene Daten werden nicht importiert. Das Thema kann im Folgenden umbenannt werden.",
+ "components.molecules.import.lessons.rename":
+ "Bei Bedarf kann der Name des Themas umbenannt werden: ",
"components.molecules.import.lessons.options.selectCourse.infoText":
"Der Kurs, in den das Thema importiert werden soll, muss im Folgenden ausgewählt werden.",
"components.molecules.import.lessons.options.selectCourse": "Kurs wählen",
@@ -613,9 +614,11 @@ export default {
"components.molecules.import.options.loadingMessage": "Import läuft...",
"components.molecules.import.options.success":
"{name} wurde erfolgreich importiert",
+ "components.molecules.import.options.tableHeader.InfoText":
+ "Folgende Inhalte werden nicht importiert:",
"components.molecules.import.tasks.label": "Aufgabe",
- "components.molecules.import.tasks.options.infoText":
- "Es wird eine Kopie erstellt. Personenbezogene Daten werden nicht importiert. Die Aufgabe kann im Folgenden umbenannt werden.",
+ "components.molecules.import.tasks.rename":
+ "Bei Bedarf kann der Name der Aufgabe umbenannt werden: ",
"components.molecules.import.tasks.options.selectCourse.infoText":
"Der Kurs, in den die Aufgabe importiert werden soll, muss im Folgenden ausgewählt werden.",
"components.molecules.export.options.info":
@@ -654,20 +657,34 @@ export default {
"Organisationsleitung",
"components.molecules.MintEcFooter.chapters": "Kapitelübersicht",
"components.molecules.share.columnBoard.options.infoText":
- "Mit dem folgenden Link kann der Bereich als Kopie von anderen Lehrkräften importiert werden. Personenbezogene Daten werden dabei nicht importiert.",
+ "Mit dem folgenden Link kann der Bereich als Kopie von anderen Lehrkräften importiert werden.",
"components.molecules.share.columnBoard.result.linkLabel":
"Link Bereich-Kopie",
"components.molecules.share.courses.mail.body": "Link zum Kurs:",
"components.molecules.share.courses.mail.subject": "Kurs zum Importieren",
- "components.molecules.share.courses.options.ctlTools.infotext":
- "Externe Tools, die dem Kurs oder Karten im Bereich zugeordnet sind, werden nicht kopiert.",
+ "components.molecules.shareImport.options.ctlTools.infoText.unavailable":
+ "In Zielschule nicht verfügbare, externe Tools",
+ "components.molecules.shareImport.options.ctlTools.infoText.protected":
+ "Geschützte Einstellungen externer Tools",
"components.molecules.share.courses.options.infoText":
- "Mit dem folgenden Link kann der Kurs als Kopie von anderen Lehrkräften importiert werden. Personenbezogene Daten werden dabei nicht importiert.",
+ "Mit dem folgenden Link kann der Kurs als Kopie von anderen Lehrkräften importiert werden.",
+ "components.molecules.shareImport.options.restrictions.infoText.personalData":
+ "Personenbezogene Daten",
+ "components.molecules.shareImport.options.restrictions.infoText.courseFiles":
+ "Dateien unter Kurs-Dateien",
+ "components.molecules.shareImport.options.restrictions.infoText.etherpad":
+ "Inhalte aus Etherpads",
+ "components.molecules.shareImport.options.restrictions.infoText.geogebra":
+ "Geogebra IDs und",
+ "components.molecules.shareImport.options.restrictions.infoText.courseGroups":
+ "Kursgruppen",
+ "components.molecules.share.options.tableHeader.InfoText":
+ "Folgende Inhalte werden nicht kopiert:",
"components.molecules.share.courses.result.linkLabel": "Link Kurskopie",
"components.molecules.share.lessons.mail.body": "Link zum Thema:",
"components.molecules.share.lessons.mail.subject": "Thema zum Importieren",
"components.molecules.share.lessons.options.infoText":
- "Mit dem folgenden Link kann das Thema als Kopie von anderen Lehrkräften importiert werden. Personenbezogene Daten werden dabei nicht importiert.",
+ "Mit dem folgenden Link kann das Thema als Kopie von anderen Lehrkräften importiert werden.",
"components.molecules.share.lessons.result.linkLabel": "Link Themakopie",
"components.molecules.share.options.expiresInDays":
"Link läuft nach 21 Tagen ab",
@@ -681,7 +698,7 @@ export default {
"components.molecules.share.tasks.mail.body": "Link zur Aufgabe:",
"components.molecules.share.tasks.mail.subject": "Aufgabe zum Importieren",
"components.molecules.share.tasks.options.infoText":
- "Mit dem folgenden Link kann die Aufgabe als Kopie von anderen Lehrkräften importiert werden. Personenbezogene Daten werden dabei nicht importiert.",
+ "Mit dem folgenden Link kann die Aufgabe als Kopie von anderen Lehrkräften importiert werden.",
"components.molecules.share.tasks.result.linkLabel": "Link Aufgabekopie",
"components.molecules.TaskItemMenu.confirmDelete.text":
'Bist du dir sicher, dass du die Aufgabe "{taskTitle}" löschen möchtest?',
diff --git a/src/locales/en.ts b/src/locales/en.ts
index bf6a788f59..4e0c95d93b 100644
--- a/src/locales/en.ts
+++ b/src/locales/en.ts
@@ -515,7 +515,7 @@ export default {
"components.molecules.copyResult.ctlTools.info":
"External tools associated with the course and boarding cards are not copied.",
"components.molecules.copyResult.ctlTools.withFeature.info":
- "Protected parts of the tool configurations are not copied.",
+ "External tools and protected parts of the tool configurations that are not available in the target school are not copied.",
"components.molecules.copyResult.etherpadCopy.info":
"Content is not copied for data protection reasons and must be added again.",
"components.molecules.copyResult.failedCopy":
@@ -546,8 +546,9 @@ export default {
"components.molecules.copyResult.label.tldraw": "Whiteboard",
"components.molecules.copyResult.label.link": "Link",
"components.molecules.copyResult.label.timeGroup": "Time Group",
- "components.molecules.copyResult.label.unknown": "Unkown",
+ "components.molecules.copyResult.label.unknown": "Unknown",
"components.molecules.copyResult.label.userGroup": "User Group",
+ "components.molecules.copyResult.label.toolElements": "Tool Element",
"components.molecules.copyResult.metadata": "General Information",
"components.molecules.copyResult.nexboardCopy.info":
"Content is not copied for data protection reasons and must be added again.",
@@ -576,6 +577,8 @@ export default {
"components.molecules.EdusharingFooter.img_alt": "edusharing-logo",
"components.molecules.EdusharingFooter.text": "powered by",
"components.molecules.import.columnBoard.label": "Board title",
+ "components.molecules.import.columnBoard.rename":
+ "If necessary, the name of the board can be renamed: ",
"components.molecules.import.columnBoard.options.infoText":
"The board can be renamed below.",
"components.molecules.import.columnBoard.options.title": "Import board",
@@ -583,18 +586,16 @@ export default {
"Select course",
"components.molecules.import.columnBoard.options.selectCourse.infoText":
"Please select the course into which you would like to import the board.",
- "components.molecules.import.courses.label": "Course",
+ "components.molecules.import.courses.label": "Course name",
"components.molecules.import.columnBoard.options.selectRoom": "Select room",
"components.molecules.import.columnBoard.options.selectRoom.infoText":
"Please select the room into which you would like to import the board.",
- "components.molecules.import.courses.options.ctlTools.infoText":
- "A copy will be created.
Personal data will not be imported.
External tools will not be copied.
The course can be renamed below.",
- "components.molecules.import.courses.options.infoText":
- "Participant-related data will not be copied. The course can be renamed below.",
- "components.molecules.import.courses.options.title": "Import course",
+ "components.molecules.import.courses.rename":
+ "If necessary, the name of the course can be renamed: ",
+ "components.molecules.import.courses.options.title": "Import course copy",
"components.molecules.import.lessons.label": "Topic",
- "components.molecules.import.lessons.options.infoText":
- "Participant-related data will not be copied. The topic can be renamed below.",
+ "components.molecules.import.lessons.rename":
+ "If necessary, the name of the topic can be renamed: ",
"components.molecules.import.lessons.options.selectCourse.infoText":
"Please select the course into which you would like to import the topic.",
"components.molecules.import.lessons.options.selectCourse": "Select course",
@@ -607,9 +608,11 @@ export default {
"Unfortunately, the necessary authorization is missing.",
"components.molecules.import.options.loadingMessage": "Import in progress...",
"components.molecules.import.options.success": "{name} imported successfully",
+ "components.molecules.import.options.tableHeader.InfoText":
+ "The following content will not be imported:",
"components.molecules.import.tasks.label": "Task",
- "components.molecules.import.tasks.options.infoText":
- "Participant-related data will not be copied. The task can be renamed below.",
+ "components.molecules.import.tasks.rename":
+ "If necessary, the name of the task can be renamed: ",
"components.molecules.import.tasks.options.selectCourse.infoText":
"Please select the course into which you would like to import the task.",
"components.molecules.import.tasks.options.selectCourse": "Select course",
@@ -642,18 +645,32 @@ export default {
"components.molecules.MintEcFooter.chapters": "Chapter overview",
"components.molecules.share.courses.mail.body": "Link to the course:",
"components.molecules.share.courses.mail.subject": "Course you can import",
- "components.molecules.share.courses.options.ctlTools.infotext":
- "External tools associated with the course or boarding cards will not be copied.",
+ "components.molecules.shareImport.options.ctlTools.infoText.unavailable":
+ "External tools not available in the target school",
+ "components.molecules.shareImport.options.ctlTools.infoText.protected":
+ "Protected settings of external tools",
"components.molecules.share.courses.options.infoText":
- "With the following link, the course can be imported as a copy by other teachers. Personal data will not be imported.",
+ "With the following link, the course can be imported as a copy by other teachers.",
+ "components.molecules.shareImport.options.restrictions.infoText.personalData":
+ "Personal data",
+ "components.molecules.shareImport.options.restrictions.infoText.courseFiles":
+ "Files under Course Files",
+ "components.molecules.shareImport.options.restrictions.infoText.etherpad":
+ "Content from Etherpads",
+ "components.molecules.shareImport.options.restrictions.infoText.geogebra":
+ "Geogebra IDs and",
+ "components.molecules.shareImport.options.restrictions.infoText.courseGroups":
+ "Course groups",
+ "components.molecules.share.options.tableHeader.InfoText":
+ "The following content will not be copied:",
"components.molecules.share.courses.result.linkLabel": "Link course copy",
"components.molecules.share.lessons.mail.body": "Link to the topic:",
"components.molecules.share.lessons.mail.subject": "Topic you can import",
"components.molecules.share.lessons.options.infoText":
- "With the following link, the topic can be imported as a copy by other teachers. Personal data will not be imported.",
+ "With the following link, the topic can be imported as a copy by other teachers.",
"components.molecules.share.lessons.result.linkLabel": "Link topic copy",
"components.molecules.share.columnBoard.options.infoText":
- "With the following link, the board can be imported as a copy by other teachers. Personal data will not be imported.",
+ "With the following link, the board can be imported as a copy by other teachers.",
"components.molecules.share.columnBoard.result.linkLabel":
"Link to Board copy",
"components.molecules.share.options.expiresInDays":
diff --git a/src/locales/es.ts b/src/locales/es.ts
index edcd7a5fc7..e7e9c76c7d 100644
--- a/src/locales/es.ts
+++ b/src/locales/es.ts
@@ -525,7 +525,7 @@ export default {
"components.molecules.copyResult.ctlTools.info":
"Las herramientas externas asociadas al curso y las tarjetas de embarque no se copian.",
"components.molecules.copyResult.ctlTools.withFeature.info":
- "Las partes protegidas de las configuraciones de herramientas no se copian.",
+ "Las herramientas externas y las partes protegidas de las configuraciones de herramientas que no están disponibles en la escuela de destino no se copian.",
"components.molecules.copyResult.etherpadCopy.info":
"El contenido no se copia por razones de protección de datos y debe agregarse nuevamente.",
"components.molecules.copyResult.failedCopy":
@@ -561,6 +561,8 @@ export default {
"components.molecules.copyResult.label.timeGroup": "Grupo de tiempo",
"components.molecules.copyResult.label.unknown": "Desconocido",
"components.molecules.copyResult.label.userGroup": "Grupo de usuario",
+ "components.molecules.copyResult.label.toolElements":
+ "Elemento de herramienta",
"components.molecules.copyResult.metadata": "Información general",
"components.molecules.copyResult.nexboardCopy.info":
"El contenido no se copia por razones de protección de datos y debe agregarse nuevamente.",
@@ -589,6 +591,8 @@ export default {
"components.molecules.EdusharingFooter.img_alt": "edusharing-logotipo",
"components.molecules.EdusharingFooter.text": "desarrollado por",
"components.molecules.import.columnBoard.label": "Título del tablero",
+ "components.molecules.import.columnBoard.rename":
+ "Si es necesario, se puede cambiar el nombre del tablero: ",
"components.molecules.import.columnBoard.options.infoText":
"Puede cambiar el nombre del tablero a continuación.",
"components.molecules.import.columnBoard.options.title": "Importar tablero",
@@ -596,19 +600,17 @@ export default {
"Elija el curso",
"components.molecules.import.columnBoard.options.selectCourse.infoText":
"Seleccione el curso al que desea importar el tablero.",
- "components.molecules.import.courses.label": "Curso",
+ "components.molecules.import.courses.label": "Nombre del curso",
"components.molecules.import.columnBoard.options.selectRoom":
"Seleccionar sala",
"components.molecules.import.columnBoard.options.selectRoom.infoText":
"Seleccione la sala en la que desea importar el tablero.",
- "components.molecules.import.courses.options.ctlTools.infoText":
- "Se creará una copia.
No se importarán datos personales.
No se copiarán herramientas externas.
Se puede cambiar el nombre del curso a continuación.",
- "components.molecules.import.courses.options.infoText":
- "Los datos relacionados con los participantes no se copiarán. El curso se puede renombrar a continuación.",
- "components.molecules.import.courses.options.title": "Importar curso",
+ "components.molecules.import.courses.rename":
+ "Si es necesario, se puede cambiar el nombre del curso: ",
+ "components.molecules.import.courses.options.title": "Importar copia nuestra",
"components.molecules.import.lessons.label": "Tema",
- "components.molecules.import.lessons.options.infoText":
- "Los datos relacionados con los participantes no se copiarán. El tema se puede renombrar a continuación.",
+ "components.molecules.import.lessons.rename":
+ "Si es necesario, se puede cambiar el nombre del tema: ",
"components.molecules.import.lessons.options.selectCourse.infoText":
"Seleccione el curso al que desea importar el tema.",
"components.molecules.import.lessons.options.selectCourse": "Elija el curso",
@@ -622,9 +624,11 @@ export default {
"components.molecules.import.options.loadingMessage":
"Importación en curso...",
"components.molecules.import.options.success": "{name} importado con éxito",
+ "components.molecules.import.options.tableHeader.InfoText":
+ "No se importará el siguiente contenido:",
"components.molecules.import.tasks.label": "Tarea",
- "components.molecules.import.tasks.options.infoText":
- "Los datos relacionados con los participantes no se copiarán. La tarea se puede renombrar a continuación.",
+ "components.molecules.import.tasks.rename":
+ "Si es necesario, se puede cambiar el nombre de la tarea: ",
"components.molecules.import.tasks.options.selectCourse.infoText":
"Seleccione el curso al que desea importar la tarea.",
"components.molecules.import.tasks.options.selectCourse": "Elija el curso",
@@ -661,16 +665,32 @@ export default {
"Enlace a la copia del tablón",
"components.molecules.share.courses.mail.body": "Enlace al curso:",
"components.molecules.share.courses.mail.subject": "Curso de importación",
- "components.molecules.share.courses.options.ctlTools.infotext":
+ "components.molecules.share.courses.options.ctlTools.infoText":
"No se copiarán herramientas externas asociadas al curso ni tarjetas de embarque.",
+ "components.molecules.shareImport.options.ctlTools.infoText.unavailable":
+ "Herramientas externas no disponibles en la escuela de destino",
+ "components.molecules.shareImport.options.ctlTools.infoText.protected":
+ "Configuraciones protegidas de herramientas externas",
"components.molecules.share.courses.options.infoText":
- "Con el siguiente enlace, el curso puede ser importado como copia por otros profesores. Los datos personales no se importarán.",
+ "Utilizando el siguiente enlace, otros profesores pueden importar el curso como una copia.",
+ "components.molecules.shareImport.options.restrictions.infoText.personalData":
+ "Datos personales",
+ "components.molecules.shareImport.options.restrictions.infoText.courseFiles":
+ "Archivos en Archivos de curso",
+ "components.molecules.shareImport.options.restrictions.infoText.etherpad":
+ "Contenido de Etherpads",
+ "components.molecules.shareImport.options.restrictions.infoText.geogebra":
+ "ID de Geogebra y",
+ "components.molecules.shareImport.options.restrictions.infoText.courseGroups":
+ "Grupos de cursos",
+ "components.molecules.share.options.tableHeader.InfoText":
+ "No se copiará el siguiente contenido:",
"components.molecules.share.courses.result.linkLabel":
"Enlace a la copia del curso",
"components.molecules.share.lessons.mail.body": "Enlace al tema:",
"components.molecules.share.lessons.mail.subject": "Tema de importación",
"components.molecules.share.lessons.options.infoText":
- "Con el siguiente enlace, el tema puede ser importado como copia por otros profesores. Los datos personales no se importarán.",
+ "Con el siguiente enlace, el tema puede ser importado como copia por otros profesores.",
"components.molecules.share.lessons.result.linkLabel":
"Enlace a la copia del tema",
"components.molecules.share.options.expiresInDays":
@@ -685,7 +705,7 @@ export default {
"components.molecules.share.tasks.mail.body": "Enlace a la tarea:",
"components.molecules.share.tasks.mail.subject": "Tarea de importación",
"components.molecules.share.tasks.options.infoText":
- "Con el siguiente enlace, la tarea puede ser importado como copia por otros profesores. Los datos personales no se importarán.",
+ "Con el siguiente enlace, la tarea puede ser importado como copia por otros profesores.",
"components.molecules.share.tasks.result.linkLabel":
"Enlace a la copia de la tarea",
"components.molecules.TaskItemMenu.confirmDelete.text":
diff --git a/src/locales/uk.ts b/src/locales/uk.ts
index b2b2ad29dd..7f754142b3 100644
--- a/src/locales/uk.ts
+++ b/src/locales/uk.ts
@@ -523,7 +523,7 @@ export default {
"components.molecules.copyResult.ctlTools.info":
"Зовнішні інструменти, пов’язані з курсом, і посадкові картки не копіюються.",
"components.molecules.copyResult.ctlTools.withFeature.info":
- "Захищені частини конфігурацій інструменту не копіюються.",
+ "Зовнішні інструменти та захищені частини конфігурацій інструментів, які недоступні в цільовій школі, не копіюються.",
"components.molecules.copyResult.etherpadCopy.info":
"Вміст не копіюється з міркувань захисту даних і повинен бути доданий повторно.",
"components.molecules.copyResult.failedCopy":
@@ -557,6 +557,8 @@ export default {
"components.molecules.copyResult.label.timeGroup": "Група часу",
"components.molecules.copyResult.label.unknown": "Невідомий",
"components.molecules.copyResult.label.userGroup": "Група користувачів",
+ "components.molecules.copyResult.label.toolElements":
+ "Інструментальний елемент",
"components.molecules.copyResult.metadata": "Загальна інформація",
"components.molecules.copyResult.nexboardCopy.info":
"Вміст не копіюється з міркувань захисту даних і повинен бути доданий повторно.",
@@ -585,6 +587,8 @@ export default {
"components.molecules.EdusharingFooter.img_alt": "логотип edusharing",
"components.molecules.EdusharingFooter.text": "на платформі",
"components.molecules.import.columnBoard.label": "Назва дошки",
+ "components.molecules.import.columnBoard.rename":
+ "При необхідності назву дошки можна змінити: ",
"components.molecules.import.columnBoard.options.infoText":
"Ви можете перейменувати дошку нижче",
"components.molecules.import.columnBoard.options.title": "Дошка імпорту",
@@ -592,19 +596,18 @@ export default {
"Оберіть курс",
"components.molecules.import.columnBoard.options.selectCourse.infoText":
"Виберіть курс, до якого ви бажаєте імпортувати дошку.",
- "components.molecules.import.courses.label": "Курс",
+ "components.molecules.import.courses.label": "Назва курсу",
"components.molecules.import.columnBoard.options.selectRoom":
"Оберіть кімнату",
"components.molecules.import.columnBoard.options.selectRoom.infoText":
"Виберіть кімнату, до якого ви бажаєте імпортувати дошку.",
- "components.molecules.import.courses.options.ctlTools.infoText":
- "Буде створено копію.
собисті дані не будуть імпортовані.
Зовнішні інструменти не будуть скопійовані.
Курс можна перейменувати нижче.",
- "components.molecules.import.courses.options.infoText":
- "Дані учасників не будуть скопійовані. Курс можна перейменувати нижче.",
- "components.molecules.import.courses.options.title": "Курс імпорту",
+ "components.molecules.import.courses.rename":
+ "При необхідності назву курсу можна перейменувати: ",
+ "components.molecules.import.courses.options.title":
+ "Імпортувати копію курсу",
"components.molecules.import.lessons.label": "Тема",
- "components.molecules.import.lessons.options.infoText":
- "Дані учасників не будуть скопійовані. Тема можна перейменувати нижче.",
+ "components.molecules.import.lessons.rename":
+ "При необхідності назву теми можна перейменувати: ",
"components.molecules.import.lessons.options.selectCourse.infoText":
"Будь ласка, оберіть курс з якого ви хочете імпортувати тему",
"components.molecules.import.lessons.options.selectCourse": "Оберіть курс",
@@ -618,9 +621,11 @@ export default {
"components.molecules.import.options.loadingMessage":
"Виконується імпорту...",
"components.molecules.import.options.success": "{name} успішно імпортовано",
+ "components.molecules.import.options.tableHeader.InfoText":
+ "Наступний вміст не буде імпортовано:",
"components.molecules.import.tasks.label": "Завдання",
- "components.molecules.import.tasks.options.infoText":
- "Дані, що стосуються учасників, не копіюються. Завдання можна перейменувати нижче.",
+ "components.molecules.import.tasks.rename":
+ "При необхідності назву завдання можна перейменувати: ",
"components.molecules.import.tasks.options.selectCourse.infoText":
"Виберіть курс, до якого ви хочете імпортувати завдання.",
"components.molecules.import.tasks.options.selectCourse": "Оберіть курс",
@@ -658,17 +663,33 @@ export default {
"Посилання на копію дошки",
"components.molecules.share.courses.mail.body": "Посилання на курс:",
"components.molecules.share.courses.mail.subject": "Курс імпорту",
- "components.molecules.share.courses.options.ctlTools.infotext":
+ "components.molecules.share.courses.options.ctlTools.infoText":
"Зовнішні інструменти, пов’язані з курсом або посадочними картками, не будуть скопійовані.",
+ "components.molecules.shareImport.options.ctlTools.infoText.unavailable":
+ "Зовнішні інструменти недоступні в цільовій школі",
+ "components.molecules.shareImport.options.ctlTools.infoText.protected":
+ "Захищені налаштування зовнішніх інструментів",
"components.molecules.share.courses.options.infoText":
- "За наступним посиланням курс може бути імпортований як копія іншими викладачами. Персональні дані не імпортуються.",
+ "Використовуючи наступне посилання, курс може бути імпортований як копія іншими викладачами.",
+ "components.molecules.shareImport.options.restrictions.infoText.personalData":
+ "Персональні дані",
+ "components.molecules.shareImport.options.restrictions.infoText.courseFiles":
+ "Файли в розділі Файли курсу",
+ "components.molecules.shareImport.options.restrictions.infoText.etherpad":
+ "Вміст із Etherpads",
+ "components.molecules.shareImport.options.restrictions.infoText.geogebra":
+ "Ідентифікатори Geogebra та",
+ "components.molecules.shareImport.options.restrictions.infoText.courseGroups":
+ "Групи курсів",
+ "components.molecules.share.options.tableHeader.InfoText":
+ "Наступний вміст не буде скопійовано:",
"components.molecules.share.courses.result.linkLabel":
"Посилання на копію курсу",
"components.molecules.share.lessons.mail.body": "Посилання на курс:",
"components.molecules.share.lessons.mail.subject":
"Теми, які можна імпортувати",
"components.molecules.share.lessons.options.infoText":
- "За наступним посиланням тему можуть імпортувати як копію інші вчителі. Особисті дані не будуть імпортовані.",
+ "За наступним посиланням тему можуть імпортувати як копію інші вчителі.",
"components.molecules.share.lessons.result.linkLabel": "Копія теми посилання",
"components.molecules.share.options.expiresInDays":
"Термін дії посилання закінчується через 21 днів",
@@ -683,7 +704,7 @@ export default {
"components.molecules.share.tasks.mail.subject":
"Завдання, які можна імпортувати",
"components.molecules.share.tasks.options.infoText":
- "За наступним посиланням завдання можуть імпортувати як копію інші вчителі. Особисті дані не будуть імпортовані.",
+ "За наступним посиланням завдання можуть імпортувати як копію інші вчителі.",
"components.molecules.share.tasks.result.linkLabel":
"Зв'язати копію завдання",
"components.molecules.TaskItemMenu.confirmDelete.text":
diff --git a/src/modules/feature/board-deleted-element/DeletedElement.vue b/src/modules/feature/board-deleted-element/DeletedElement.vue
index 3460ff13d0..454a4923cb 100644
--- a/src/modules/feature/board-deleted-element/DeletedElement.vue
+++ b/src/modules/feature/board-deleted-element/DeletedElement.vue
@@ -8,20 +8,6 @@
ref="deletedElement"
:ripple="false"
>
-
- {{
- $t(
- "components.cardElement.deletedElement.warning.externalToolElement",
- {
- toolName: element.content.title,
- }
- )
- }}
-
{{ element.content.title }}
@@ -36,6 +22,20 @@
/>
+
+ {{
+ $t(
+ "components.cardElement.deletedElement.warning.externalToolElement",
+ {
+ toolName: element.content.title,
+ }
+ )
+ }}
+
diff --git a/src/store/copy.ts b/src/store/copy.ts
index a11675d548..3bbb9a45fc 100644
--- a/src/store/copy.ts
+++ b/src/store/copy.ts
@@ -216,6 +216,7 @@ export default class CopyModule extends VuexModule {
if (type === CopyApiResponseTypeEnum.DrawingElement) return true;
if (type === CopyApiResponseTypeEnum.CollaborativeTextEditorElement)
return true;
+ if (type === CopyApiResponseTypeEnum.ExternalToolElement) return true;
return false;
};
From a0274e5d1fc195b53902e2c270bb9538fd276927 Mon Sep 17 00:00:00 2001
From: NFriedo <69233063+NFriedo@users.noreply.github.com>
Date: Tue, 10 Dec 2024 10:43:37 +0100
Subject: [PATCH 11/12] BC-8500 - fix removing members in members table (#3465)
* fix deletion of members via the delete icon in the table
* refactor: roomMemberlist handling
---------
Co-authored-by: hoeppner.dataport
---
.../room/RoomMembers/MembersTable.unit.ts | 444 +++++++++++++-----
.../feature/room/RoomMembers/MembersTable.vue | 89 ++--
.../page/room/RoomMembers.page.unit.ts | 444 ++++++++----------
src/modules/page/room/RoomMembers.page.vue | 39 +-
4 files changed, 588 insertions(+), 428 deletions(-)
diff --git a/src/modules/feature/room/RoomMembers/MembersTable.unit.ts b/src/modules/feature/room/RoomMembers/MembersTable.unit.ts
index b7db2ddbeb..a0da092c36 100644
--- a/src/modules/feature/room/RoomMembers/MembersTable.unit.ts
+++ b/src/modules/feature/room/RoomMembers/MembersTable.unit.ts
@@ -3,175 +3,375 @@ import {
createTestingVuetify,
} from "@@/tests/test-utils/setup";
import MembersTable from "./MembersTable.vue";
-import { Ref } from "vue";
+import { ref } from "vue";
import { mdiMenuDown, mdiMenuUp, mdiMagnify } from "@icons/material";
import { roomMemberResponseFactory } from "@@/tests/test-utils";
-import { RoomMember } from "@data-room";
-import { flushPromises } from "@vue/test-utils";
+import { DOMWrapper, VueWrapper } from "@vue/test-utils";
+import { VDataTable, VTextField } from "vuetify/lib/components/index.mjs";
+import { useConfirmationDialog } from "@ui-confirmation-dialog";
+import setupConfirmationComposableMock from "@@/tests/test-utils/composable-mocks/setupConfirmationComposableMock";
-const mockMembers = roomMemberResponseFactory.buildList(3);
+jest.mock("@ui-confirmation-dialog");
+const mockedUseRemoveConfirmationDialog = jest.mocked(useConfirmationDialog);
describe("MembersTable", () => {
+ let askConfirmationMock: jest.Mock;
+
+ beforeEach(() => {
+ askConfirmationMock = jest.fn();
+ setupConfirmationComposableMock({
+ askConfirmationMock,
+ });
+ mockedUseRemoveConfirmationDialog.mockReturnValue({
+ askConfirmation: askConfirmationMock,
+ isDialogOpen: ref(false),
+ });
+ });
+
+ const tableHeaders = [
+ "common.labels.firstName",
+ "common.labels.lastName",
+ "common.labels.role",
+ "common.words.mainSchool",
+ "",
+ ];
+
const setup = () => {
+ const mockMembers = roomMemberResponseFactory.buildList(3);
const wrapper = mount(MembersTable, {
+ attachTo: document.body,
global: {
plugins: [createTestingVuetify(), createTestingI18n()],
},
- props: { members: mockMembers, selectedMembers: [] },
+ props: { members: mockMembers },
});
- const wrapperVM = wrapper.vm as unknown as {
- members: RoomMember[];
- search: Ref;
- tableTitle: string;
- tableHeader: { title: string; key: string }[];
- selectedMemberList: string[];
- };
+ return { wrapper, mockMembers };
+ };
+
+ // index 0 is the header checkbox
+ const selectCheckboxes = async (indices: number[], wrapper: VueWrapper) => {
+ const dataTable = wrapper.getComponent(VDataTable);
+ const checkboxes = dataTable.findAll("input[type='checkbox']");
- return { wrapper, wrapperVM };
+ for (const index of indices) {
+ const checkbox = checkboxes[index];
+ await checkbox.trigger("click");
+ }
+
+ return { checkboxes };
};
- describe("when component is mounted", () => {
- it("should render member's table", () => {
+ const getCheckedIndices = (checkboxes: DOMWrapper[]) =>
+ checkboxes.reduce((selectedIndices, checkbox, index) => {
+ if (checkbox.attributes("checked") === "") {
+ selectedIndices.push(index);
+ }
+ return selectedIndices;
+ }, [] as Array);
+
+ it("should render members table component", () => {
+ const { wrapper } = setup();
+
+ expect(wrapper.exists()).toBe(true);
+ });
+
+ it("should render data table", () => {
+ const { wrapper, mockMembers } = setup();
+
+ const dataTable = wrapper.getComponent(VDataTable);
+
+ expect(dataTable.props("headers")!.map((header) => header.title)).toEqual(
+ tableHeaders
+ );
+ expect(dataTable.props("items")).toEqual(mockMembers);
+ expect(dataTable.props("sortAscIcon")).toEqual(mdiMenuDown);
+ expect(dataTable.props("sortDescIcon")).toEqual(mdiMenuUp);
+ });
+
+ it("should render checkboxes", async () => {
+ const { wrapper, mockMembers } = setup();
+
+ const dataTable = wrapper.findComponent(VDataTable);
+ const checkboxes = dataTable.findAll("input[type='checkbox']");
+
+ expect(checkboxes.length).toEqual(mockMembers.length + 1); // all checkboxes including header checkbox
+ });
+
+ describe("when selecting members", () => {
+ it("should select all members when header checkbox is clicked", async () => {
const { wrapper } = setup();
- expect(wrapper.exists()).toBe(true);
- expect(wrapper.findComponent(MembersTable)).toBeTruthy();
+ const { checkboxes } = await selectCheckboxes([0], wrapper);
+ const checkedIndices = getCheckedIndices(checkboxes);
+
+ const expectedIndices = [0, 1, 2, 3];
+
+ expect(checkedIndices).toEqual(expectedIndices);
});
- });
- describe("DataTable component", () => {
- it("should render the table component", () => {
- const { wrapper, wrapperVM } = setup();
- const dataTable = wrapper.findComponent({ name: "v-data-table" });
+ it("should emit select:members", async () => {
+ const { wrapper, mockMembers } = setup();
+
+ await selectCheckboxes([1], wrapper);
+
+ const selectEvents = wrapper.emitted("select:members");
+ expect(selectEvents).toHaveLength(1);
+ expect(selectEvents![0]).toEqual([[mockMembers[0].userId]]);
+ });
+
+ it("should render the multi action menu", async () => {
+ const { wrapper } = setup();
+
+ await selectCheckboxes([1], wrapper);
+
+ const multiActionMenu = wrapper.find("[data-testid=multi-action-menu]");
+
+ expect(multiActionMenu.exists()).toBe(true);
+ });
+
+ it("should render selected members remove button", async () => {
+ const { wrapper } = setup();
+
+ await selectCheckboxes([1], wrapper);
+
+ const removeButton = wrapper.findComponent({
+ ref: "removeSelectedMembers",
+ });
+
+ expect(removeButton.exists()).toBe(true);
+ });
+
+ it("should render selected members reset button", async () => {
+ const { wrapper } = setup();
+
+ await selectCheckboxes([1, 2], wrapper);
+
+ const resetButton = wrapper.findComponent({
+ ref: "resetSelectedMembers",
+ });
+
+ expect(resetButton.exists()).toBe(true);
+ });
+
+ it("should reset member selection when clicking reset button", async () => {
+ const { wrapper } = setup();
+
+ askConfirmationMock.mockResolvedValue(false);
+
+ await selectCheckboxes([0], wrapper);
+
+ const resetButton = wrapper.findComponent({
+ ref: "resetSelectedMembers",
+ });
+ await resetButton.trigger("click");
+
+ const checkboxes = wrapper
+ .getComponent(VDataTable)
+ .findAll("input[type='checkbox']");
+
+ const checkedIndices = getCheckedIndices(checkboxes);
+
+ expect(checkedIndices).toEqual([]);
+ });
+
+ it.each([
+ {
+ description: "one member",
+ checkboxesToSelect: [1],
+ },
+ {
+ description: "multiple members",
+ checkboxesToSelect: [1, 2],
+ },
+ ])(
+ "should render number of selected users in multi action menu, when $description selected",
+ async ({ checkboxesToSelect }) => {
+ const { wrapper } = setup();
+
+ await selectCheckboxes(checkboxesToSelect, wrapper);
+
+ const multiActionMenu = wrapper.get("[data-testid=multi-action-menu]");
+
+ expect(multiActionMenu.text()).toBe(
+ `${checkboxesToSelect.length} pages.administration.selected`
+ );
+ }
+ );
+
+ it("should emit remove:members when selected members remove button is clicked", async () => {
+ const { wrapper, mockMembers } = setup();
+
+ askConfirmationMock.mockResolvedValue(true);
+
+ await selectCheckboxes([1], wrapper);
+
+ const removeButton = wrapper.findComponent({
+ ref: "removeSelectedMembers",
+ });
+ await removeButton.trigger("click");
+
+ const removeEvents = wrapper.emitted("remove:members");
+ expect(removeEvents).toHaveLength(1);
+ expect(removeEvents![0]).toEqual([[mockMembers[0].userId]]);
+ });
+
+ it("should not emit remove:members event when remove was cancled", async () => {
+ const { wrapper } = setup();
+
+ askConfirmationMock.mockResolvedValue(false);
- expect(dataTable).toBeTruthy();
- expect(dataTable.vm.items).toEqual(mockMembers);
- expect(dataTable.vm.headers).toEqual(wrapperVM.tableHeader);
- expect(dataTable.vm["sortAscIcon"]).toEqual(mdiMenuDown);
- expect(dataTable.vm["sortDescIcon"]).toEqual(mdiMenuUp);
+ await selectCheckboxes([1], wrapper);
+
+ const removeButton = wrapper.findComponent({
+ ref: "removeSelectedMembers",
+ });
+ await removeButton.trigger("click");
+
+ expect(wrapper.emitted()).not.toHaveProperty("remove:members");
});
- describe("when the remove button is clicked", () => {
- it("should emit the remove event", async () => {
+ it.each([
+ {
+ description: "single member",
+ checkboxesToSelect: [1],
+ expectedMessage: "pages.rooms.members.remove.confirmation",
+ },
+ {
+ description: "multiple members",
+ checkboxesToSelect: [1, 2],
+ expectedMessage: "pages.rooms.members.multipleRemove.confirmation",
+ },
+ ])(
+ "should render confirmation dialog with text for $description when remove button is clicked",
+ async ({ checkboxesToSelect, expectedMessage }) => {
const { wrapper } = setup();
+
+ askConfirmationMock.mockResolvedValue(true);
+
+ await selectCheckboxes(checkboxesToSelect, wrapper);
+
const removeButton = wrapper.findComponent({
- name: "v-btn",
- ref: "removeMember",
+ ref: "removeSelectedMembers",
});
+ await removeButton.trigger("click");
- await removeButton.vm.$emit("click");
expect(wrapper.emitted()).toHaveProperty("remove:members");
+
+ expect(askConfirmationMock).toHaveBeenCalledWith({
+ confirmActionLangKey: "common.actions.remove",
+ message: expectedMessage,
+ });
+ }
+ );
+
+ it("should keep selection if confirmation dialog is canceled", async () => {
+ const { wrapper } = setup();
+
+ askConfirmationMock.mockResolvedValue(false);
+
+ await selectCheckboxes([1], wrapper);
+
+ const removeButton = wrapper.getComponent({
+ ref: "removeSelectedMembers",
});
+ await removeButton.trigger("click");
+
+ const checkboxes = wrapper
+ .getComponent(VDataTable)
+ .findAll("input[type='checkbox']");
+
+ const checkedIndices = getCheckedIndices(checkboxes);
+
+ expect(checkedIndices).toEqual([1]);
+ });
+ });
+
+ describe("when no members are selected", () => {
+ it("should not render multi action menu when no members are selected", async () => {
+ const { wrapper } = setup();
+ const multiActionMenu = wrapper.find("[data-testid=multi-action-menu]");
+
+ expect(multiActionMenu.exists()).toBe(false);
});
- describe("multiple selection", () => {
- it("should render checkBoxes", async () => {
+ describe("when the remove button in the user row is clicked", () => {
+ const triggerMemberRemoval = async (
+ index: number,
+ wrapper: VueWrapper
+ ) => {
+ const dataTable = wrapper.getComponent(VDataTable);
+ const removeButton = dataTable.findComponent(
+ `[data-testid=remove-member-${index}]`
+ );
+
+ await removeButton.trigger("click");
+ };
+
+ it("should open confirmation dialog with remove message for single member ", async () => {
const { wrapper } = setup();
- const dataTable = wrapper.findComponent({ name: "v-data-table" });
- const checkBoxes = dataTable.findAll("tr input[type='checkbox']");
- expect(checkBoxes.length).toBeGreaterThan(0);
- });
+ askConfirmationMock.mockResolvedValue(true);
- describe("when checkboxes are clicked", () => {
- it("should set the selectedMembers", async () => {
- const { wrapper, wrapperVM } = setup();
- const dataTable = wrapper.findComponent({ name: "v-data-table" });
- expect(wrapperVM.selectedMemberList.length).toStrictEqual(0);
- dataTable.vm.$emit("update:modelValue", [
- mockMembers[0].userId,
- mockMembers[1].userId,
- ]);
-
- expect(wrapperVM.selectedMemberList).toStrictEqual([
- mockMembers[0].userId,
- mockMembers[1].userId,
- ]);
- });
+ await triggerMemberRemoval(0, wrapper);
- describe("bulk remove button", () => {
- it("should be visible", async () => {
- const { wrapper } = setup();
- const dataTable = wrapper.findComponent({ name: "v-data-table" });
- const bulkRemoveButtonBefore = wrapper.findComponent({
- ref: "removeSelectedMembers",
- });
-
- expect(bulkRemoveButtonBefore.exists()).toBe(false);
- dataTable.vm.$emit("update:modelValue", [
- mockMembers[0].userId,
- mockMembers[1].userId,
- ]);
- await flushPromises();
- const bulkRemoveButtonAfter = wrapper.findComponent({
- ref: "removeSelectedMembers",
- });
- expect(bulkRemoveButtonAfter.exists()).toBe(true);
- });
-
- describe("when the bulk remove button is clicked", () => {
- it("should emit the 'remove:members'", async () => {
- const { wrapper } = setup();
- const dataTable = wrapper.findComponent({ name: "v-data-table" });
- dataTable.vm.$emit("update:modelValue", [
- mockMembers[0].userId,
- mockMembers[1].userId,
- ]);
- await flushPromises();
- const bulkRemoveButton = wrapper.findComponent({
- ref: "removeSelectedMembers",
- });
- await bulkRemoveButton.vm.$emit("click");
- expect(wrapper.emitted()).toHaveProperty("remove:members");
- });
- });
+ expect(askConfirmationMock).toHaveBeenCalledWith({
+ confirmActionLangKey: "common.actions.remove",
+ message: "pages.rooms.members.remove.confirmation",
});
+ });
- describe("when reset button is clicked", () => {
- it("should reset the selected members", async () => {
- const { wrapper, wrapperVM } = setup();
- const dataTable = wrapper.findComponent({ name: "v-data-table" });
- dataTable.vm.$emit("update:modelValue", [
- mockMembers[0].userId,
- mockMembers[1].userId,
- ]);
- await flushPromises();
- expect(wrapperVM.selectedMemberList).toStrictEqual([
- mockMembers[0].userId,
- mockMembers[1].userId,
- ]);
- const resetButton = wrapper.findComponent({
- ref: "resetSelectedMembers",
- });
- resetButton.vm.$emit("click");
- expect(wrapperVM.selectedMemberList).toStrictEqual([]);
- });
- });
+ it("should call remove:members event after confirmation", async () => {
+ const { wrapper, mockMembers } = setup();
+
+ askConfirmationMock.mockResolvedValue(true);
+
+ await triggerMemberRemoval(0, wrapper);
+
+ expect(wrapper.emitted()).toHaveProperty("remove:members");
+
+ const removeEvents = wrapper.emitted("remove:members");
+ expect(removeEvents).toHaveLength(1);
+ expect(removeEvents![0]).toEqual([[mockMembers[0].userId]]);
+ });
+
+ it("should not call remove:members event when dialog is cancelled", async () => {
+ const { wrapper } = setup();
+
+ askConfirmationMock.mockResolvedValue(false);
+
+ await triggerMemberRemoval(0, wrapper);
+
+ expect(wrapper.emitted()).not.toHaveProperty("remove:members");
});
});
});
- describe("Search component", () => {
+ describe("when searching for members", () => {
it("should render the search component", () => {
- const { wrapper, wrapperVM } = setup();
- const search = wrapper.findComponent({ name: "v-text-field" });
+ const { wrapper } = setup();
- expect(search).toBeTruthy();
- expect(search.vm["label"]).toEqual("common.labels.search");
- expect(search.vm["prependInnerIcon"]).toEqual(mdiMagnify);
- expect(search.vm["vModel"]).toEqual(wrapperVM.search.value);
+ const search = wrapper.getComponent(VTextField);
+
+ expect(search.props("label")).toEqual("common.labels.search");
+ expect(search.props("prependInnerIcon")).toEqual(mdiMagnify);
});
it("should filter the members based on the search value", async () => {
- const { wrapper, wrapperVM } = setup();
- const search = wrapper.findComponent({ name: "v-text-field" });
+ const { wrapper, mockMembers } = setup();
+
+ const search = wrapper.getComponent(VTextField);
+ const searchValue = mockMembers[0].firstName;
+
+ await search.setValue(searchValue);
- await search.vm.$emit("update:modelValue", mockMembers[0].firstName);
- expect(wrapperVM.search).toBe(mockMembers[0].firstName);
- const dataTable = wrapper.findComponent({ name: "v-data-table" });
+ const dataTable = wrapper.getComponent(VDataTable);
+ const dataTableTextContent = dataTable.text();
- expect(dataTable.vm.search).toEqual(mockMembers[0].firstName);
+ expect(dataTable.props("search")).toEqual(searchValue);
+ expect(dataTableTextContent).toContain(mockMembers[0].firstName);
+ expect(dataTableTextContent).not.toContain(mockMembers[1].firstName);
+ expect(dataTableTextContent).not.toContain(mockMembers[2].firstName);
});
});
});
diff --git a/src/modules/feature/room/RoomMembers/MembersTable.vue b/src/modules/feature/room/RoomMembers/MembersTable.vue
index d227baafea..d8ba934427 100644
--- a/src/modules/feature/room/RoomMembers/MembersTable.vue
+++ b/src/modules/feature/room/RoomMembers/MembersTable.vue
@@ -2,10 +2,13 @@