From eecbf2258b1618e03ae6fe6ca236e2492520a12b Mon Sep 17 00:00:00 2001
From: jasonchung1871 <101672465+jasonchung1871@users.noreply.github.com>
Date: Fri, 23 Aug 2024 14:44:53 -0700
Subject: [PATCH 1/3] fixed SubmissionsTable (#1488)
fixed the issue with pagination and sort not working
---
.../src/components/forms/SubmissionsTable.vue | 50 ++++++++---------
.../components/forms/SubmissionsTable.spec.js | 54 +++++++++----------
2 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/app/frontend/src/components/forms/SubmissionsTable.vue b/app/frontend/src/components/forms/SubmissionsTable.vue
index 96b03b39e..4cc954038 100644
--- a/app/frontend/src/components/forms/SubmissionsTable.vue
+++ b/app/frontend/src/components/forms/SubmissionsTable.vue
@@ -41,9 +41,9 @@ const filterIgnore = ref([
},
]);
const forceTableRefresh = ref(0);
-const itemsPerPage = ref(10);
+const itemsPP = ref(10);
const loading = ref(true);
-const page = ref(1);
+const currentPage = ref(1);
const restoreItem = ref({});
const selectedSubmissions = ref([]);
const serverItems = ref([]);
@@ -52,7 +52,7 @@ const showDeleteDialog = ref(false);
const showRestoreDialog = ref(false);
const singleSubmissionDelete = ref(false);
const singleSubmissionRestore = ref(false);
-const sortBy = ref({});
+const sort = ref({});
const firstDataLoad = ref(true);
// When filtering, this data will not be preselected when clicking reset
const tableFilterIgnore = ref([
@@ -306,26 +306,26 @@ function onShowColumnDialog() {
showColumnsDialog.value = true;
}
-async function updateTableOptions({ pg, itemsPP, sort }) {
- if (pg) {
- page.value = pg;
+async function updateTableOptions({ page, itemsPerPage, sortBy }) {
+ if (page) {
+ currentPage.value = page;
}
- if (sort?.length > 0) {
- if (sort[0].key === 'date') {
- sortBy.value.column = 'createdAt';
- } else if (sort[0].key === 'submitter') {
- sortBy.value.column = 'createdBy';
- } else if (sort[0].key === 'status') {
- sortBy.value.column = 'formSubmissionStatusCode';
+ if (sortBy?.length > 0) {
+ if (sortBy[0].key === 'date') {
+ sort.value.column = 'createdAt';
+ } else if (sortBy[0].key === 'submitter') {
+ sort.value.column = 'createdBy';
+ } else if (sortBy[0].key === 'status') {
+ sort.value.column = 'formSubmissionStatusCode';
} else {
- sortBy.value.column = sort[0].key;
+ sort.value.column = sortBy[0].key;
}
- sortBy.value.order = sort[0].order;
+ sort.value.order = sortBy[0].order;
} else {
- sortBy.value = {};
+ sort.value = {};
}
- if (itemsPP) {
- itemsPerPage.value = itemsPP;
+ if (itemsPerPage) {
+ itemsPP.value = itemsPerPage;
}
if (!firstDataLoad.value) {
await refreshSubmissions();
@@ -336,11 +336,11 @@ async function updateTableOptions({ pg, itemsPP, sort }) {
async function getSubmissionData() {
let criteria = {
formId: properties.formId,
- itemsPerPage: itemsPerPage.value,
- page: page.value - 1,
+ itemsPerPage: itemsPP.value,
+ page: currentPage.value - 1,
filterformSubmissionStatusCode: true,
paginationEnabled: true,
- sortBy: sortBy.value,
+ sortBy: sort.value,
search: search.value,
searchEnabled: search.value.length > 0 ? true : false,
createdAt: Object.values({
@@ -539,11 +539,11 @@ defineExpose({
getSubmissionData,
handleSearch,
HEADERS,
- itemsPerPage,
+ itemsPP,
multiDeleteMessage,
multiRestoreMessage,
onShowColumnDialog,
- page,
+ currentPage,
restoreSub,
serverItems,
showColumnsDialog,
@@ -554,7 +554,7 @@ defineExpose({
singleRestoreMessage,
singleSubmissionDelete,
singleSubmissionRestore,
- sortBy,
+ sort,
updateFilter,
userColumns,
USER_PREFERENCES,
@@ -691,7 +691,7 @@ defineExpose({
hover
:items-length="totalSubmissions"
class="submissions-table"
- :items-per-page="itemsPerPage"
+ :items-per-page="itemsPP"
:headers="HEADERS"
item-value="submissionId"
:items="serverItems"
diff --git a/app/frontend/tests/unit/components/forms/SubmissionsTable.spec.js b/app/frontend/tests/unit/components/forms/SubmissionsTable.spec.js
index 5bf28ffac..03a4c867d 100644
--- a/app/frontend/tests/unit/components/forms/SubmissionsTable.spec.js
+++ b/app/frontend/tests/unit/components/forms/SubmissionsTable.spec.js
@@ -731,70 +731,70 @@ describe('SubmissionsTable.vue', () => {
// should refresh submissions
expect(getFormPreferencesForCurrentUserSpy).toBeCalledTimes(0);
expect(fetchSubmissionsSpy).toBeCalledTimes(0);
- expect(wrapper.vm.page).toEqual(1);
- expect(wrapper.vm.sortBy).toEqual({});
- expect(wrapper.vm.itemsPerPage).toEqual(10);
+ expect(wrapper.vm.currentPage).toEqual(1);
+ expect(wrapper.vm.sort).toEqual({});
+ expect(wrapper.vm.itemsPP).toEqual(10);
getFormPreferencesForCurrentUserSpy.mockReset();
fetchSubmissionsSpy.mockReset();
await wrapper.vm.updateTableOptions({
- pg: 5,
- itemsPP: 2,
- sort: [{ key: 'date', order: 'desc' }],
+ page: 5,
+ itemsPerPage: 2,
+ sortBy: [{ key: 'date', order: 'desc' }],
});
// should not refresh submissions
wrapper.vm.firstDataLoad = true;
expect(getFormPreferencesForCurrentUserSpy).toBeCalledTimes(0);
expect(fetchSubmissionsSpy).toBeCalledTimes(0);
- expect(wrapper.vm.page).toEqual(5);
- expect(wrapper.vm.sortBy).toEqual({ column: 'createdAt', order: 'desc' });
- expect(wrapper.vm.itemsPerPage).toEqual(2);
+ expect(wrapper.vm.currentPage).toEqual(5);
+ expect(wrapper.vm.sort).toEqual({ column: 'createdAt', order: 'desc' });
+ expect(wrapper.vm.itemsPP).toEqual(2);
await wrapper.vm.updateTableOptions({
- pg: 5,
- itemsPP: 2,
- sort: [{ key: 'submitter', order: 'desc' }],
+ page: 5,
+ itemsPerPage: 2,
+ sortBy: [{ key: 'submitter', order: 'desc' }],
});
// should not refresh submissions
wrapper.vm.firstDataLoad = true;
expect(getFormPreferencesForCurrentUserSpy).toBeCalledTimes(0);
expect(fetchSubmissionsSpy).toBeCalledTimes(0);
- expect(wrapper.vm.page).toEqual(5);
- expect(wrapper.vm.sortBy).toEqual({ column: 'createdBy', order: 'desc' });
- expect(wrapper.vm.itemsPerPage).toEqual(2);
+ expect(wrapper.vm.currentPage).toEqual(5);
+ expect(wrapper.vm.sort).toEqual({ column: 'createdBy', order: 'desc' });
+ expect(wrapper.vm.itemsPP).toEqual(2);
await wrapper.vm.updateTableOptions({
- pg: 5,
- itemsPP: 2,
- sort: [{ key: 'status', order: 'desc' }],
+ page: 5,
+ itemsPerPage: 2,
+ sortBy: [{ key: 'status', order: 'desc' }],
});
// should not refresh submissions
wrapper.vm.firstDataLoad = true;
expect(getFormPreferencesForCurrentUserSpy).toBeCalledTimes(0);
expect(fetchSubmissionsSpy).toBeCalledTimes(0);
- expect(wrapper.vm.page).toEqual(5);
- expect(wrapper.vm.sortBy).toEqual({
+ expect(wrapper.vm.currentPage).toEqual(5);
+ expect(wrapper.vm.sort).toEqual({
column: 'formSubmissionStatusCode',
order: 'desc',
});
- expect(wrapper.vm.itemsPerPage).toEqual(2);
+ expect(wrapper.vm.itemsPP).toEqual(2);
await wrapper.vm.updateTableOptions({
- pg: 5,
- itemsPP: 2,
- sort: [{ key: 'something', order: 'desc' }],
+ page: 5,
+ itemsPerPage: 2,
+ sortBy: [{ key: 'something', order: 'desc' }],
});
// should not refresh submissions
wrapper.vm.firstDataLoad = true;
expect(getFormPreferencesForCurrentUserSpy).toBeCalledTimes(0);
expect(fetchSubmissionsSpy).toBeCalledTimes(0);
- expect(wrapper.vm.page).toEqual(5);
- expect(wrapper.vm.sortBy).toEqual({
+ expect(wrapper.vm.currentPage).toEqual(5);
+ expect(wrapper.vm.sort).toEqual({
column: 'something',
order: 'desc',
});
- expect(wrapper.vm.itemsPerPage).toEqual(2);
+ expect(wrapper.vm.itemsPP).toEqual(2);
});
it('getSubmissionData will fetchSubmissions in different ways', async () => {
From eabf469acb3b14626528fc287884f9ddfed64780 Mon Sep 17 00:00:00 2001
From: Vijaivir Dhaliwal <91633223+vijaivir@users.noreply.github.com>
Date: Fri, 23 Aug 2024 15:48:06 -0700
Subject: [PATCH 2/3] Feat: CDOGS file size validation (#1485)
* added file size validation on cdogs template uploads
* updated test
* fix errors
* update test
---
.../src/components/forms/PrintOptions.vue | 35 ++++++++++++++---
.../forms/manage/DocumentTemplate.vue | 39 +++++++++++++++----
.../trans/chefs/ar/ar.json | 3 +-
.../trans/chefs/de/de.json | 3 +-
.../trans/chefs/en/en.json | 3 +-
.../trans/chefs/es/es.json | 3 +-
.../trans/chefs/fa/fa.json | 3 +-
.../trans/chefs/fr/fr.json | 3 +-
.../trans/chefs/hi/hi.json | 3 +-
.../trans/chefs/it/it.json | 3 +-
.../trans/chefs/ja/ja.json | 3 +-
.../trans/chefs/ko/ko.json | 3 +-
.../trans/chefs/pa/pa.json | 3 +-
.../trans/chefs/pt/pt.json | 3 +-
.../trans/chefs/ru/ru.json | 3 +-
.../trans/chefs/tl/tl.json | 3 +-
.../trans/chefs/uk/uk.json | 3 +-
.../trans/chefs/vi/vi.json | 3 +-
.../trans/chefs/zh/zh.json | 3 +-
.../trans/chefs/zhTW/zh-TW.json | 3 +-
.../components/forms/PrintOptions.spec.js | 12 +++---
.../forms/manage/DocumentTemplate.spec.js | 4 +-
22 files changed, 107 insertions(+), 37 deletions(-)
diff --git a/app/frontend/src/components/forms/PrintOptions.vue b/app/frontend/src/components/forms/PrintOptions.vue
index 99c7a3451..e6b0c4d46 100644
--- a/app/frontend/src/components/forms/PrintOptions.vue
+++ b/app/frontend/src/components/forms/PrintOptions.vue
@@ -1,7 +1,7 @@
@@ -446,6 +466,7 @@ defineExpose({
value="upload"
>
[
+ isValidSize.value || t('trans.documentTemplate.fileSizeError'),
isValidFile.value || t('trans.documentTemplate.invalidFileMessage'),
]);
@@ -83,6 +85,15 @@ function handleFileInput(event) {
if (event && event.length > 0) {
isFileInputEmpty.value = false;
uploadedFile = event[0];
+
+ // validate file size
+ if (uploadedFile.size > 25000000) {
+ isValidSize.value = false;
+ } else {
+ isValidSize.value = true;
+ }
+
+ // validate file extension
const fileExtension = event[0].name.split('.').pop();
if (validFileExtensions.includes(fileExtension)) {
isValidFile.value = true;
@@ -92,6 +103,7 @@ function handleFileInput(event) {
} else {
isFileInputEmpty.value = true;
isValidFile.value = true;
+ isValidSize.value = true;
}
}
@@ -120,12 +132,21 @@ async function handleFileUpload() {
...NotificationTypes.SUCCESS,
});
} catch (e) {
- notificationStore.addNotification({
- text: t('trans.documentTemplate.uploadError'),
- consoleError: t('trans.documentTemplate.uploadError', {
- error: e.message,
- }),
- });
+ if (e.response.status === 413) {
+ notificationStore.addNotification({
+ text: t('trans.documentTemplate.fileSizeError'),
+ consoleError: t('trans.documentTemplate.fileSizeError', {
+ error: e.message,
+ }),
+ });
+ } else {
+ notificationStore.addNotification({
+ text: t('trans.documentTemplate.uploadError'),
+ consoleError: t('trans.documentTemplate.uploadError', {
+ error: e.message,
+ }),
+ });
+ }
} finally {
loading.value = false;
}
@@ -196,6 +217,7 @@ defineExpose({
handleFileInput,
isFileInputEmpty,
isValidFile,
+ isValidSize,
uploadedFile,
});
@@ -322,7 +344,10 @@ defineExpose({
مفتاح الإدخال أو ، أو مسافة لإضافة عناوين بريد إلكتروني متعددة",
diff --git a/app/frontend/src/internationalization/trans/chefs/de/de.json b/app/frontend/src/internationalization/trans/chefs/de/de.json
index c35fa2d65..c2115567f 100644
--- a/app/frontend/src/internationalization/trans/chefs/de/de.json
+++ b/app/frontend/src/internationalization/trans/chefs/de/de.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Vorlage erfolgreich gelöscht.",
"deleteError": "Beim Löschen der Vorlage ist ein Fehler aufgetreten.",
"fetchError": "Beim Abrufen der Vorlage ist ein Fehler aufgetreten.",
- "info": "Laden Sie eine Vorlage hoch, um den Gemeinsamen Dokumenterstellungsdienst (CDOGS) zu verwenden"
+ "info": "Laden Sie eine Vorlage hoch, um den Gemeinsamen Dokumenterstellungsdienst (CDOGS) zu verwenden",
+ "fileSizeError": "Die Dateigröße muss weniger als 25 MB betragen."
},
"formSettings": {
"pressToAddMultiEmail": "Drücken Sie die Eingabetaste oder die Leertaste oder , um mehrere E-Mail-Adressen hinzuzufügen",
diff --git a/app/frontend/src/internationalization/trans/chefs/en/en.json b/app/frontend/src/internationalization/trans/chefs/en/en.json
index 8f52970a2..fe0991616 100644
--- a/app/frontend/src/internationalization/trans/chefs/en/en.json
+++ b/app/frontend/src/internationalization/trans/chefs/en/en.json
@@ -81,7 +81,8 @@
"deleteSuccess": "Template deleted successfully.",
"deleteError": "An error occurred while deleting the template.",
"fetchError": "An error occurred while fetching the template.",
- "info": "Upload a template to use the Common Document Generation Service (CDOGS)"
+ "info": "Upload a template to use the Common Document Generation Service (CDOGS)",
+ "fileSizeError": "File size must be less than 25MB."
},
"externalAPI": {
"info": "Configure External APIs for use in your form.",
diff --git a/app/frontend/src/internationalization/trans/chefs/es/es.json b/app/frontend/src/internationalization/trans/chefs/es/es.json
index aa005e6c0..22ddb28aa 100644
--- a/app/frontend/src/internationalization/trans/chefs/es/es.json
+++ b/app/frontend/src/internationalization/trans/chefs/es/es.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Plantilla eliminada exitosamente.",
"deleteError": "Ocurrió un error al eliminar la plantilla.",
"fetchError": "Ocurrió un error al obtener la plantilla.",
- "info": "Sube una plantilla para usar el Servicio de Generación de Documentos Comunes (CDOGS)"
+ "info": "Sube una plantilla para usar el Servicio de Generación de Documentos Comunes (CDOGS)",
+ "fileSizeError": "El tamaño del archivo debe ser menor de 25 MB."
},
"formSettings": {
"pressToAddMultiEmail": "Presiona enter o , o espacio para agregar varias direcciones de correo electrónico",
diff --git a/app/frontend/src/internationalization/trans/chefs/fa/fa.json b/app/frontend/src/internationalization/trans/chefs/fa/fa.json
index 29cd29556..be613f2e8 100644
--- a/app/frontend/src/internationalization/trans/chefs/fa/fa.json
+++ b/app/frontend/src/internationalization/trans/chefs/fa/fa.json
@@ -84,7 +84,8 @@
"deleteSuccess": "قالب با موفقیت حذف شد.",
"deleteError": "خطایی در هنگام حذف قالب رخ داد.",
"fetchError": "خطایی در هنگام دریافت قالب رخ داد.",
- "info": "قالبی را بارگذاری کنید تا از خدمات تولید سند مشترک (CDOGS) استفاده کنید"
+ "info": "قالبی را بارگذاری کنید تا از خدمات تولید سند مشترک (CDOGS) استفاده کنید",
+ "fileSizeError": "اندازه فایل باید کمتر از 25 مگابایت باشد."
},
"formSettings": {
"pressToAddMultiEmail": "برای افزودن چندین آدرس ایمیل، اینتر یا ، یا فاصله را فشار دهید",
diff --git a/app/frontend/src/internationalization/trans/chefs/fr/fr.json b/app/frontend/src/internationalization/trans/chefs/fr/fr.json
index 0d287188f..11a37d431 100644
--- a/app/frontend/src/internationalization/trans/chefs/fr/fr.json
+++ b/app/frontend/src/internationalization/trans/chefs/fr/fr.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Modèle supprimé avec succès.",
"deleteError": "Une erreur s'est produite lors de la suppression du modèle.",
"fetchError": "Une erreur s'est produite lors de la récupération du modèle.",
- "info": "Téléchargez un modèle pour utiliser le Service de Génération de Documents Communs (CDOGS)"
+ "info": "Téléchargez un modèle pour utiliser le Service de Génération de Documents Communs (CDOGS)",
+ "fileSizeError": "La taille du fichier doit être inférieure à 25 Mo."
},
"formSettings": {
"pressToAddMultiEmail": "Appuyez sur entrée ou , ou espace pour ajouter plusieurs adresses e-mail",
diff --git a/app/frontend/src/internationalization/trans/chefs/hi/hi.json b/app/frontend/src/internationalization/trans/chefs/hi/hi.json
index bf23ba611..bf2b7c9c8 100644
--- a/app/frontend/src/internationalization/trans/chefs/hi/hi.json
+++ b/app/frontend/src/internationalization/trans/chefs/hi/hi.json
@@ -84,7 +84,8 @@
"deleteSuccess": "टेम्पलेट सफलतापूर्वक हटाया गया।",
"deleteError": "टेम्पलेट हटाते समय एक त्रुटि हुई।",
"fetchError": "टेम्पलेट प्राप्त करते समय एक त्रुटि हुई।",
- "info": "कॉमन डॉक्युमेंट जनरेशन सर्विस (CDOGS) का उपयोग करने के लिए एक टेम्पलेट अपलोड करें"
+ "info": "कॉमन डॉक्युमेंट जनरेशन सर्विस (CDOGS) का उपयोग करने के लिए एक टेम्पलेट अपलोड करें",
+ "fileSizeError": "फ़ाइल का आकार 25MB से कम होना चाहिए।"
},
"formSettings": {
"pressToAddMultiEmail": "एकाधिक ईमेल पते जोड़ने के लिए एंटर या , या स्पेस दबाएँ",
diff --git a/app/frontend/src/internationalization/trans/chefs/it/it.json b/app/frontend/src/internationalization/trans/chefs/it/it.json
index d614f6798..077d2f0cb 100644
--- a/app/frontend/src/internationalization/trans/chefs/it/it.json
+++ b/app/frontend/src/internationalization/trans/chefs/it/it.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Template eliminato con successo.",
"deleteError": "Si è verificato un errore durante l'eliminazione del template.",
"fetchError": "Si è verificato un errore durante il recupero del template.",
- "info": "Carica un template per utilizzare il Servizio di Generazione Documenti Comuni (CDOGS)"
+ "info": "Carica un template per utilizzare il Servizio di Generazione Documenti Comuni (CDOGS)",
+ "fileSizeError": "La dimensione del file deve essere inferiore a 25 MB."
},
"formSettings": {
"pressToAddMultiEmail": "Premi invio o , o spazio per aggiungere più indirizzi email",
diff --git a/app/frontend/src/internationalization/trans/chefs/ja/ja.json b/app/frontend/src/internationalization/trans/chefs/ja/ja.json
index 4db0ec2c4..0d0326376 100644
--- a/app/frontend/src/internationalization/trans/chefs/ja/ja.json
+++ b/app/frontend/src/internationalization/trans/chefs/ja/ja.json
@@ -84,7 +84,8 @@
"deleteSuccess": "テンプレートが正常に削除されました。",
"deleteError": "テンプレートの削除中にエラーが発生しました。",
"fetchError": "テンプレートの取得中にエラーが発生しました。",
- "info": "共通ドキュメント生成サービス(CDOGS)を使用するためのテンプレートをアップロードしてください"
+ "info": "共通ドキュメント生成サービス(CDOGS)を使用するためのテンプレートをアップロードしてください",
+ "fileSizeError": "ファイルサイズは25MB以下でなければなりません。"
},
"formSettings": {
"pressToAddMultiEmail": "Enterまたは、またはスペースを押して複数の電子メール アドレスを追加します",
diff --git a/app/frontend/src/internationalization/trans/chefs/ko/ko.json b/app/frontend/src/internationalization/trans/chefs/ko/ko.json
index f59332df6..171bf2ed3 100644
--- a/app/frontend/src/internationalization/trans/chefs/ko/ko.json
+++ b/app/frontend/src/internationalization/trans/chefs/ko/ko.json
@@ -84,7 +84,8 @@
"deleteSuccess": "템플릿이 성공적으로 삭제되었습니다.",
"deleteError": "템플릿 삭제 중 오류가 발생했습니다.",
"fetchError": "템플릿 가져오기 중 오류가 발생했습니다.",
- "info": "공통 문서 생성 서비스(CDOGS)를 사용하기 위해 템플릿을 업로드하십시오"
+ "info": "공통 문서 생성 서비스(CDOGS)를 사용하기 위해 템플릿을 업로드하십시오",
+ "fileSizeError": "파일 크기는 25MB 이하여야 합니다."
},
"formSettings": {
"pressToAddMultiEmail": "여러 이메일 주소를 추가하려면 enter 또는 , 또는 space를 누르십시오.",
diff --git a/app/frontend/src/internationalization/trans/chefs/pa/pa.json b/app/frontend/src/internationalization/trans/chefs/pa/pa.json
index 1c04cf1c7..4175c49ef 100644
--- a/app/frontend/src/internationalization/trans/chefs/pa/pa.json
+++ b/app/frontend/src/internationalization/trans/chefs/pa/pa.json
@@ -84,7 +84,8 @@
"deleteSuccess": "ਟੈਂਪਲੇਟ ਸਫਲਤਾਪੂਰਵਕ ਮਿਟਾਈ ਗਈ।",
"deleteError": "ਟੈਂਪਲੇਟ ਮਿਟਾਉਣ ਸਮੇਂ ਇੱਕ ਗਲਤੀ ਆਈ।",
"fetchError": "ਟੈਂਪਲੇਟ ਲਿਆਉਣ ਸਮੇਂ ਇੱਕ ਗਲਤੀ ਆਈ।",
- "info": "ਕੌਮਨ ਦਸਤਾਵੇਜ਼ ਜਨਰੇਸ਼ਨ ਸਰਵਿਸ (CDOGS) ਵਰਤਣ ਲਈ ਇੱਕ ਟੈਂਪਲੇਟ ਅੱਪਲੋਡ ਕਰੋ"
+ "info": "ਕੌਮਨ ਦਸਤਾਵੇਜ਼ ਜਨਰੇਸ਼ਨ ਸਰਵਿਸ (CDOGS) ਵਰਤਣ ਲਈ ਇੱਕ ਟੈਂਪਲੇਟ ਅੱਪਲੋਡ ਕਰੋ",
+ "fileSizeError": "ਫਾਈਲ ਦਾ ਆਕਾਰ 25MB ਤੋਂ ਘੱਟ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।"
},
"formSettings": {
"pressToAddMultiEmail": "ਕਈ ਈਮੇਲ ਪਤੇ ਜੋੜਨ ਲਈ ਐਂਟਰ ਜਾਂ ਸਪੇਸ ਦਬਾਓ",
diff --git a/app/frontend/src/internationalization/trans/chefs/pt/pt.json b/app/frontend/src/internationalization/trans/chefs/pt/pt.json
index b3a4e6528..2855f8a04 100644
--- a/app/frontend/src/internationalization/trans/chefs/pt/pt.json
+++ b/app/frontend/src/internationalization/trans/chefs/pt/pt.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Modelo excluído com sucesso.",
"deleteError": "Ocorreu um erro ao excluir o modelo.",
"fetchError": "Ocorreu um erro ao buscar o modelo.",
- "info": "Carregue um modelo para usar o Serviço de Geração de Documentos Comuns (CDOGS)"
+ "info": "Carregue um modelo para usar o Serviço de Geração de Documentos Comuns (CDOGS)",
+ "fileSizeError": "O tamanho do arquivo deve ser menor que 25 MB."
},
"formSettings": {
"pressToAddMultiEmail": "Pressione enter ou , ou espaço para adicionar vários endereços de e-mail",
diff --git a/app/frontend/src/internationalization/trans/chefs/ru/ru.json b/app/frontend/src/internationalization/trans/chefs/ru/ru.json
index 8af28b6fc..e54aaebbe 100644
--- a/app/frontend/src/internationalization/trans/chefs/ru/ru.json
+++ b/app/frontend/src/internationalization/trans/chefs/ru/ru.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Шаблон успешно удален.",
"deleteError": "Произошла ошибка при удалении шаблона.",
"fetchError": "Произошла ошибка при получении шаблона.",
- "info": "Загрузите шаблон для использования Общей службы генерации документов (CDOGS)"
+ "info": "Загрузите шаблон для использования Общей службы генерации документов (CDOGS)",
+ "fileSizeError": "Размер файла должен быть менее 25 МБ."
},
"formSettings": {
"pressToAddMultiEmail": "Нажмите Enter или пробел , чтобы добавить несколько адресов электронной почты.",
diff --git a/app/frontend/src/internationalization/trans/chefs/tl/tl.json b/app/frontend/src/internationalization/trans/chefs/tl/tl.json
index bccdaa983..a6df3828c 100644
--- a/app/frontend/src/internationalization/trans/chefs/tl/tl.json
+++ b/app/frontend/src/internationalization/trans/chefs/tl/tl.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Matagumpay na natanggal ang template.",
"deleteError": "Nagkaroon ng error habang tinatanggal ang template.",
"fetchError": "Nagkaroon ng error habang kinukuha ang template.",
- "info": "Mag-upload ng template upang gamitin ang Common Document Generation Service (CDOGS)"
+ "info": "Mag-upload ng template upang gamitin ang Common Document Generation Service (CDOGS)",
+ "fileSizeError": "Ang laki ng file ay dapat mas mababa sa 25MB."
},
"formSettings": {
"pressToAddMultiEmail": "Pindutin ang enter o , o space para magdagdag ng maraming email address",
diff --git a/app/frontend/src/internationalization/trans/chefs/uk/uk.json b/app/frontend/src/internationalization/trans/chefs/uk/uk.json
index e915db0de..1ba0d44f5 100644
--- a/app/frontend/src/internationalization/trans/chefs/uk/uk.json
+++ b/app/frontend/src/internationalization/trans/chefs/uk/uk.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Шаблон успішно видалено.",
"deleteError": "Під час видалення шаблону сталася помилка.",
"fetchError": "Під час отримання шаблону сталася помилка.",
- "info": "Завантажте шаблон, щоб використовувати Спільний сервіс генерації документів (CDOGS)"
+ "info": "Завантажте шаблон, щоб використовувати Спільний сервіс генерації документів (CDOGS)",
+ "fileSizeError": "Розмір файлу має бути менше 25 МБ."
},
"formSettings": {
"pressToAddMultiEmail": "Щоб додати кілька електронних адрес, натисніть enter або , або пробіл",
diff --git a/app/frontend/src/internationalization/trans/chefs/vi/vi.json b/app/frontend/src/internationalization/trans/chefs/vi/vi.json
index 09b45483a..430c073ad 100644
--- a/app/frontend/src/internationalization/trans/chefs/vi/vi.json
+++ b/app/frontend/src/internationalization/trans/chefs/vi/vi.json
@@ -84,7 +84,8 @@
"deleteSuccess": "Xóa mẫu thành công.",
"deleteError": "Có lỗi xảy ra khi xóa mẫu.",
"fetchError": "Có lỗi xảy ra khi lấy mẫu.",
- "info": "Tải lên một mẫu để sử dụng Dịch vụ Tạo Tài liệu Chung (CDOGS)"
+ "info": "Tải lên một mẫu để sử dụng Dịch vụ Tạo Tài liệu Chung (CDOGS)",
+ "fileSizeError": "Kích thước tệp phải nhỏ hơn 25MB."
},
"formSettings": {
"pressToAddMultiEmail": "Nhấn enter hoặc , hoặc dấu cách để thêm nhiều địa chỉ email",
diff --git a/app/frontend/src/internationalization/trans/chefs/zh/zh.json b/app/frontend/src/internationalization/trans/chefs/zh/zh.json
index a093b928c..531af0a66 100644
--- a/app/frontend/src/internationalization/trans/chefs/zh/zh.json
+++ b/app/frontend/src/internationalization/trans/chefs/zh/zh.json
@@ -84,7 +84,8 @@
"deleteSuccess": "模板删除成功。",
"deleteError": "删除模板时发生错误。",
"fetchError": "获取模板时发生错误。",
- "info": "上传模板以使用公共文档生成服务(CDOGS)"
+ "info": "上传模板以使用公共文档生成服务(CDOGS)",
+ "fileSizeError": "文件大小必须小于25MB。"
},
"formSettings": {
"pressToAddMultiEmail": "按Enter或,或空格键添加多个电子邮件地址",
diff --git a/app/frontend/src/internationalization/trans/chefs/zhTW/zh-TW.json b/app/frontend/src/internationalization/trans/chefs/zhTW/zh-TW.json
index a0020fd7b..3761d8d46 100644
--- a/app/frontend/src/internationalization/trans/chefs/zhTW/zh-TW.json
+++ b/app/frontend/src/internationalization/trans/chefs/zhTW/zh-TW.json
@@ -84,7 +84,8 @@
"deleteSuccess": "範本成功刪除。",
"deleteError": "刪除範本時發生錯誤。",
"fetchError": "獲取範本時發生錯誤。",
- "info": "上傳範本以使用公共文檔生成服務(CDOGS)"
+ "info": "上傳範本以使用公共文檔生成服務(CDOGS)",
+ "fileSizeError": "檔案大小必須小於25MB。"
},
"formSettings": {
"pressToAddMultiEmail": "按Enter或,或空格鍵添加多個電子郵件地址",
diff --git a/app/frontend/tests/unit/components/forms/PrintOptions.spec.js b/app/frontend/tests/unit/components/forms/PrintOptions.spec.js
index ff04aec26..5214dfbfd 100644
--- a/app/frontend/tests/unit/components/forms/PrintOptions.spec.js
+++ b/app/frontend/tests/unit/components/forms/PrintOptions.spec.js
@@ -275,7 +275,7 @@ describe('PrintOptions.vue', () => {
expect(addNotificationSpy).toHaveBeenCalledTimes(1);
});
- it('validateFileExtension should remove the file extension from uploadExportFileTypes when the file input is cleared', async () => {
+ it('validateFile should remove the file extension from uploadExportFileTypes when the file input is cleared', async () => {
let submission = undefined;
formStore.form = {
id: 0,
@@ -302,11 +302,11 @@ describe('PrintOptions.vue', () => {
};
// Since this isn't in uploadExportFileTypes then it should be removed from uploadExportFileTypes
wrapper.vm.uploadExportFileTypes = ['pdf', 'txt'];
- wrapper.vm.validateFileExtension([]);
+ wrapper.vm.validateFile([]);
expect(wrapper.vm.uploadExportFileTypes).toEqual(['pdf']);
});
- it('validateFileExtension should set the output filename and set isValidFile to true if the file extension is valid', async () => {
+ it('validateFile should set the output filename and set isValidFile to true if the file extension is valid', async () => {
let submission = undefined;
formStore.form = {
id: 0,
@@ -332,7 +332,7 @@ describe('PrintOptions.vue', () => {
files: [],
};
wrapper.vm.uploadExportFileTypes = ['pdf'];
- wrapper.vm.validateFileExtension([
+ wrapper.vm.validateFile([
{
name: 'filename.txt',
},
@@ -341,7 +341,7 @@ describe('PrintOptions.vue', () => {
expect(wrapper.vm.isValidFile).toBeTruthy();
});
- it('validateFileExtension should set the output filename and set isValidFile to false if the file extension is invalid', async () => {
+ it('validateFile should set the output filename and set isValidFile to false if the file extension is invalid', async () => {
let submission = undefined;
formStore.form = {
id: 0,
@@ -367,7 +367,7 @@ describe('PrintOptions.vue', () => {
files: [],
};
wrapper.vm.uploadExportFileTypes = ['pdf'];
- wrapper.vm.validateFileExtension([
+ wrapper.vm.validateFile([
{
name: 'filename.zip',
},
diff --git a/app/frontend/tests/unit/components/forms/manage/DocumentTemplate.spec.js b/app/frontend/tests/unit/components/forms/manage/DocumentTemplate.spec.js
index e9514c10b..1207bcd6f 100644
--- a/app/frontend/tests/unit/components/forms/manage/DocumentTemplate.spec.js
+++ b/app/frontend/tests/unit/components/forms/manage/DocumentTemplate.spec.js
@@ -338,7 +338,9 @@ describe('DocumentTemplate.vue', () => {
'documentTemplateCreate'
);
documentTemplateCreateSpy.mockImplementation(() => {
- throw new Error('Error');
+ const error = new Error('Error');
+ error.response = { status: 500 };
+ throw error;
});
const wrapper = mount(DocumentTemplate, {
global: {
From a3bbe41286fe1a75f8eecb9137e944dac3dda02b Mon Sep 17 00:00:00 2001
From: jasonchung1871 <101672465+jasonchung1871@users.noreply.github.com>
Date: Mon, 26 Aug 2024 21:41:52 -0700
Subject: [PATCH 3/3] refactor: Forms 1124 composition api infolinks (#1473)
* Update GeneralLayout and FormComponentsProactiveHelp
GeneralLayout has been updated to the composition API with almost full coverage, did not add coverage for the HTML
FormComponentsProactiveHelp was updated to the composition API but no coverage was added, it was just confusing deciphering what was happening in the file so it was refactored.
* Update ProactiveHelpDialog
ProactiveHelpDialog updated to the composition API and test coverage has been added excluding FileReader testing and vue watch changes.
* Update ProactiveHelpDialog.vue
awaiting addFCProactiveHelp
* Update ProactiveHelpPreviewDialog
ProactiveHelpPreviewDialog is updated to the composition API and should have coverage excluding the watch variable
---
.../admin/FormComponentsProactiveHelp.vue | 224 ++++---------
.../components/infolinks/GeneralLayout.vue | 302 +++++++++---------
.../infolinks/ProactiveHelpDialog.vue | 265 ++++++++-------
.../infolinks/ProactiveHelpPreviewDialog.vue | 57 ++--
app/frontend/src/utils/constants.js | 65 ++++
.../admin/FormComponentsProactiveHelp.spec.js | 25 +-
.../infolinks/GeneralLayout.spec.js | 297 +++++++++++++++--
.../infolinks/ProactiveHelpDialog.spec.js | 212 +++++++++++-
.../ProactiveHelpPreviewDialog.spec.js | 45 ++-
9 files changed, 963 insertions(+), 529 deletions(-)
diff --git a/app/frontend/src/components/admin/FormComponentsProactiveHelp.vue b/app/frontend/src/components/admin/FormComponentsProactiveHelp.vue
index 844c89b78..e424f2922 100644
--- a/app/frontend/src/components/admin/FormComponentsProactiveHelp.vue
+++ b/app/frontend/src/components/admin/FormComponentsProactiveHelp.vue
@@ -1,172 +1,80 @@
-
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/app/frontend/src/components/infolinks/GeneralLayout.vue b/app/frontend/src/components/infolinks/GeneralLayout.vue
index 10284a5f4..002279cd9 100644
--- a/app/frontend/src/components/infolinks/GeneralLayout.vue
+++ b/app/frontend/src/components/infolinks/GeneralLayout.vue
@@ -1,138 +1,144 @@
-
@@ -143,7 +149,7 @@ export default {
hide-default-header
hide-default-footer
disable-pagination
- :items="layoutList"
+ :items="formComponentNames"
:loading="loading"
:loading-text="$t('trans.generalLayout.loadingText')"
:lang="locale"
@@ -164,7 +170,7 @@ export default {
size="small"
variant="text"
:title="$t('trans.generalLayout.edit')"
- @click="onOpenDialog(item.componentName)"
+ @click="onOpenEditDialog(item.componentName)"
>
@@ -195,55 +201,45 @@ export default {
-
-
- {{
- publish[index]
- ? $t('trans.generalLayout.published')
- : $t('trans.generalLayout.unpublished')
- }}
-
+
+ {{
+ publish[index]
+ ? $t('trans.generalLayout.published')
+ : $t('trans.generalLayout.unpublished')
+ }}
+
+
diff --git a/app/frontend/src/components/infolinks/ProactiveHelpDialog.vue b/app/frontend/src/components/infolinks/ProactiveHelpDialog.vue
index 99b54a85b..3aff3a9d8 100644
--- a/app/frontend/src/components/infolinks/ProactiveHelpDialog.vue
+++ b/app/frontend/src/components/infolinks/ProactiveHelpDialog.vue
@@ -1,131 +1,154 @@
-
@@ -173,7 +196,7 @@ export default {
>
{{ $t('trans.proactiveHelpDialog.componentName') }}
-
+
diff --git a/app/frontend/src/components/infolinks/ProactiveHelpPreviewDialog.vue b/app/frontend/src/components/infolinks/ProactiveHelpPreviewDialog.vue
index dc66afe6d..ded3203ff 100644
--- a/app/frontend/src/components/infolinks/ProactiveHelpPreviewDialog.vue
+++ b/app/frontend/src/components/infolinks/ProactiveHelpPreviewDialog.vue
@@ -1,40 +1,31 @@
-
diff --git a/app/frontend/src/utils/constants.js b/app/frontend/src/utils/constants.js
index 83efe0333..f55b8e7e5 100755
--- a/app/frontend/src/utils/constants.js
+++ b/app/frontend/src/utils/constants.js
@@ -172,3 +172,68 @@ export const ExportLargeData = Object.freeze({
MAX_RECORDS: 300, // Maximum number of submissions after that we gonna upload the export to Cloud and send user a download link via email
MAX_FIELDS: 30, // Maximum number of fields in a form after that we gonna upload the export to Cloud and send user a download link via email
});
+
+/** Constants for the form components proactive help */
+export const FormComponentProactiveHelpValues = Object.freeze({
+ 'Basic Layout': [
+ 'Text/Images',
+ 'Columns - 2',
+ 'Columns - 3',
+ 'Columns - 4',
+ 'Tabs',
+ 'Panel',
+ ],
+ 'Basic Fields': [
+ 'Text Field',
+ 'Multi-line Text',
+ 'Select List',
+ 'Checkbox',
+ 'Checkbox Group',
+ 'Radio Group',
+ 'Number',
+ 'Phone Number',
+ 'Email',
+ 'Date / Time',
+ 'Day',
+ ],
+ 'Advanced Layout': [
+ 'HTML Element',
+ 'Content',
+ 'Columns',
+ 'Field Set',
+ 'Panel',
+ 'Table',
+ 'Tabs',
+ 'Well',
+ ],
+ 'Advanced Fields': [
+ 'Text Field',
+ 'Email',
+ 'Text Area',
+ 'Url',
+ 'Number',
+ 'Phone Number',
+ 'Tags',
+ 'Address',
+ 'Password',
+ 'Date / Time',
+ 'Checkbox',
+ 'Day',
+ 'Time',
+ 'Select Boxes',
+ 'Select',
+ 'Currency',
+ 'Radio',
+ 'Survey',
+ 'Signature',
+ ],
+ 'Advanced Data': [
+ 'Hidden',
+ 'Container',
+ 'Data Map',
+ 'Data Grid',
+ 'Edit Grid',
+ 'Tree',
+ ],
+ 'BC Government': ['File Upload', 'Business Name Search', 'BC Address'],
+});
diff --git a/app/frontend/tests/unit/components/admin/FormComponentsProactiveHelp.spec.js b/app/frontend/tests/unit/components/admin/FormComponentsProactiveHelp.spec.js
index 8a6c095e9..fefcc1482 100644
--- a/app/frontend/tests/unit/components/admin/FormComponentsProactiveHelp.spec.js
+++ b/app/frontend/tests/unit/components/admin/FormComponentsProactiveHelp.spec.js
@@ -1,23 +1,25 @@
-import { mount } from '@vue/test-utils';
+import { flushPromises, mount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
import { expect, vi } from 'vitest';
import FormComponentsProactiveHelp from '~/components/admin/FormComponentsProactiveHelp.vue';
+import { useAdminStore } from '~/store/admin';
+import { FormComponentProactiveHelpValues } from '~/utils/constants';
describe('Dashboard.vue', () => {
const pinia = createTestingPinia();
setActivePinia(pinia);
- const extractGroupComponentsSpy = vi.spyOn(
- FormComponentsProactiveHelp.methods,
- 'extractGroupComponents'
- );
+ const adminStore = useAdminStore(pinia);
+ const listFCProactiveHelpSpy = vi.spyOn(adminStore, 'listFCProactiveHelp');
+ listFCProactiveHelpSpy.mockImplementation(() => {});
beforeEach(() => {
- extractGroupComponentsSpy.mockReset();
+ adminStore.$reset();
+ listFCProactiveHelpSpy.mockReset();
});
afterAll(() => {
- extractGroupComponentsSpy.mockRestore();
+ listFCProactiveHelpSpy.mockRestore();
});
it('renders', async () => {
@@ -30,7 +32,12 @@ describe('Dashboard.vue', () => {
},
});
- wrapper.vm.onExpansionPanelClick('Basic Layout');
- expect(extractGroupComponentsSpy).toHaveBeenCalledTimes(1);
+ await flushPromises();
+
+ expect(listFCProactiveHelpSpy).toHaveBeenCalledTimes(1);
+
+ for (let [title] of Object.entries(FormComponentProactiveHelpValues)) {
+ expect(wrapper.html()).toContain(title);
+ }
});
});
diff --git a/app/frontend/tests/unit/components/infolinks/GeneralLayout.spec.js b/app/frontend/tests/unit/components/infolinks/GeneralLayout.spec.js
index 1b4112791..8f7dad40f 100644
--- a/app/frontend/tests/unit/components/infolinks/GeneralLayout.spec.js
+++ b/app/frontend/tests/unit/components/infolinks/GeneralLayout.spec.js
@@ -1,17 +1,20 @@
// @vitest-environment happy-dom
// happy-dom is required to access window.location
-import { mount } from '@vue/test-utils';
+import { flushPromises, mount, shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
import { createRouter, createWebHistory } from 'vue-router';
-import { expect, vi } from 'vitest';
+import { beforeEach, expect, vi } from 'vitest';
import getRouter from '~/router';
import GeneralLayout from '~/components/infolinks/GeneralLayout.vue';
+import { useAdminStore } from '~/store/admin';
+import { faL } from '@fortawesome/free-solid-svg-icons';
describe('GeneralLayout.vue', () => {
const pinia = createTestingPinia();
+ const adminStore = useAdminStore(pinia);
const router = createRouter({
history: createWebHistory(),
routes: getRouter().getRoutes(),
@@ -19,18 +22,29 @@ describe('GeneralLayout.vue', () => {
setActivePinia(pinia);
- it('onOpenDialog()', async () => {
- const getComponentSpy = vi.spyOn(GeneralLayout.methods, 'getComponent');
- const onDialogSpy = vi.spyOn(GeneralLayout.methods, 'onDialog');
+ beforeEach(() => {
+ adminStore.$reset();
+ });
+
+ it('renders', async () => {
const wrapper = mount(GeneralLayout, {
props: {
- componentsList: [
- { componentName: 'content', status: true },
- { componentName: 'textfiled', status: false },
+ formComponentData: [
+ {
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ },
],
- layoutList: [
- { componentName: 'content' },
- { componentName: 'textfiled' },
+ formComponentNames: [
+ { componentName: 'Text/Images' },
+ { componentName: 'Columns - 2' },
],
groupName: '',
},
@@ -42,21 +56,32 @@ describe('GeneralLayout.vue', () => {
},
},
});
- //wrapper.vm.onOpenDialog('Text Field');
- //expect(getComponentSpy).toHaveBeenCalledTimes(1);
- //expect(onDialogSpy).toHaveBeenCalledTimes(1);
+
+ await flushPromises();
+
+ expect(wrapper.html()).toContain('Text/Images');
+ expect(wrapper.html()).toContain('Columns - 2');
});
- it('onPreviewDialog()', async () => {
- const wrapper = mount(GeneralLayout, {
+ it('toggleProactiveHelpDialog should toggle the boolean for showProactiveHelpDialog', async () => {
+ const wrapper = shallowMount(GeneralLayout, {
props: {
- componentsList: [
- { componentName: 'content', status: true },
- { componentName: 'textfiled', status: false },
+ formComponentData: [
+ {
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ },
],
- layoutList: [
- { componentName: 'content' },
- { componentName: 'textfiled' },
+ formComponentNames: [
+ { componentName: 'Text/Images' },
+ { componentName: 'Columns - 2' },
],
groupName: '',
},
@@ -68,20 +93,102 @@ describe('GeneralLayout.vue', () => {
},
},
});
- //wrapper.vm.onPreviewDialog();
- //expect(wrapper.vm.showPreviewDialog).toBe(true);
+
+ expect(wrapper.vm.showEditProactiveHelpDialog).toBeFalsy();
+ wrapper.vm.toggleEditProactiveHelpDialog();
+ expect(wrapper.vm.showEditProactiveHelpDialog).toBeTruthy();
});
- it('onDialog()', async () => {
- const wrapper = mount(GeneralLayout, {
+ it('togglePreviewDialog should toggle the boolean for showPreviewDialog', async () => {
+ const wrapper = shallowMount(GeneralLayout, {
+ props: {
+ formComponentData: [
+ {
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ },
+ ],
+ formComponentNames: [
+ { componentName: 'Text/Images' },
+ { componentName: 'Columns - 2' },
+ ],
+ groupName: '',
+ },
+ global: {
+ plugins: [router, pinia],
+ stubs: {
+ ProactiveHelpDialog: true,
+ ProactiveHelpPreviewDialog: true,
+ },
+ },
+ });
+
+ expect(wrapper.vm.showPreviewDialog).toBeFalsy();
+ wrapper.vm.togglePreviewDialog();
+ expect(wrapper.vm.showPreviewDialog).toBeTruthy();
+ });
+
+ it('isPreviewEnabled takes a component name and returns true if an admin has previously set data for a form component proactive help and false otherwise', async () => {
+ const wrapper = shallowMount(GeneralLayout, {
+ props: {
+ formComponentData: [
+ {
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ },
+ ],
+ formComponentNames: [
+ { componentName: 'Text/Images' },
+ { componentName: 'Columns - 2' },
+ ],
+ groupName: '',
+ },
+ global: {
+ plugins: [router, pinia],
+ stubs: {
+ ProactiveHelpDialog: true,
+ ProactiveHelpPreviewDialog: true,
+ },
+ },
+ });
+
+ expect(wrapper.vm.isPreviewEnabled('Text/Images')).toBeFalsy();
+ expect(wrapper.vm.isPreviewEnabled('Columns - 2')).toBeTruthy();
+ });
+
+ it('onOpenEditDialog should set the component data and toggle the boolean for showProactiveHelpDialog', async () => {
+ const wrapper = shallowMount(GeneralLayout, {
props: {
- componentsList: [
- { componentName: 'content', status: true },
- { componentName: 'textfiled', status: false },
+ formComponentData: [
+ {
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ },
],
- layoutList: [
- { componentName: 'content' },
- { componentName: 'textfiled' },
+ formComponentNames: [
+ { componentName: 'Text/Images' },
+ { componentName: 'Columns - 2' },
],
groupName: '',
},
@@ -93,7 +200,129 @@ describe('GeneralLayout.vue', () => {
},
},
});
- //wrapper.vm.onDialog();
- //expect(wrapper.vm.showDialog).toBe(true);
+
+ expect(wrapper.vm.showEditProactiveHelpDialog).toBeFalsy();
+ expect(wrapper.vm.component).toEqual({});
+ wrapper.vm.onOpenEditDialog('Text/Images');
+ expect(wrapper.vm.component).toEqual({
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ });
+ expect(wrapper.vm.showEditProactiveHelpDialog).toBeTruthy();
+ });
+
+ it('onOpenPreviewDialog should get the image URL, set the component data and toggle the boolean for showPreviewDialog', async () => {
+ const wrapper = shallowMount(GeneralLayout, {
+ props: {
+ formComponentData: [
+ {
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ },
+ ],
+ formComponentNames: [
+ { componentName: 'Text/Images' },
+ { componentName: 'Columns - 2' },
+ ],
+ groupName: '',
+ },
+ global: {
+ plugins: [router, pinia],
+ stubs: {
+ ProactiveHelpDialog: true,
+ ProactiveHelpPreviewDialog: true,
+ },
+ },
+ });
+
+ const getFCProactiveHelpImageUrlSpy = vi.spyOn(
+ adminStore,
+ 'getFCProactiveHelpImageUrl'
+ );
+ getFCProactiveHelpImageUrlSpy.mockImplementation(() => {});
+
+ expect(wrapper.vm.showPreviewDialog).toBeFalsy();
+ expect(wrapper.vm.component).toEqual({});
+ await wrapper.vm.onOpenPreviewDialog('Text/Images');
+ expect(getFCProactiveHelpImageUrlSpy).toBeCalledTimes(1);
+ expect(getFCProactiveHelpImageUrlSpy).toBeCalledWith('123-456');
+ expect(wrapper.vm.component).toEqual({
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ });
+ expect(wrapper.vm.showPreviewDialog).toBeTruthy();
+ });
+
+ it('onSwitchChange will set the published status for a component based on the switch value', async () => {
+ const wrapper = shallowMount(GeneralLayout, {
+ props: {
+ formComponentData: [
+ {
+ componentName: 'Text/Images',
+ description:
+ 'See Also: Content component and HTML Element component in the "advanced layout" section',
+ externalLink: 'http://link.com',
+ groupName: 'Basic Layout',
+ id: '123-456',
+ imageName: 'image.jpeg',
+ isLinkEnabled: true,
+ status: true,
+ },
+ ],
+ formComponentNames: [
+ { componentName: 'Text/Images' },
+ { componentName: 'Columns - 2' },
+ ],
+ groupName: '',
+ },
+ global: {
+ plugins: [router, pinia],
+ stubs: {
+ ProactiveHelpDialog: true,
+ ProactiveHelpPreviewDialog: true,
+ },
+ },
+ });
+
+ const updateFCProactiveHelpStatusSpy = vi.spyOn(
+ adminStore,
+ 'updateFCProactiveHelpStatus'
+ );
+ updateFCProactiveHelpStatusSpy.mockImplementation(() => {});
+ await wrapper.vm.onSwitchChange('Text/Images', 0);
+ expect(updateFCProactiveHelpStatusSpy).toBeCalledTimes(1);
+ expect(updateFCProactiveHelpStatusSpy).toBeCalledWith({
+ componentId: '123-456',
+ publishStatus: true,
+ });
+ wrapper.vm.publish[0] = false;
+ updateFCProactiveHelpStatusSpy.mockReset();
+ await wrapper.vm.onSwitchChange('Text/Images', 0);
+ expect(updateFCProactiveHelpStatusSpy).toBeCalledTimes(1);
+ expect(updateFCProactiveHelpStatusSpy).toBeCalledWith({
+ componentId: '123-456',
+ publishStatus: false,
+ });
});
});
diff --git a/app/frontend/tests/unit/components/infolinks/ProactiveHelpDialog.spec.js b/app/frontend/tests/unit/components/infolinks/ProactiveHelpDialog.spec.js
index d64797a30..15b24e2f0 100644
--- a/app/frontend/tests/unit/components/infolinks/ProactiveHelpDialog.spec.js
+++ b/app/frontend/tests/unit/components/infolinks/ProactiveHelpDialog.spec.js
@@ -1,18 +1,55 @@
// @vitest-environment happy-dom
// happy-dom is required to access window.location
-import { mount } from '@vue/test-utils';
+import { flushPromises, mount, shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
import { createRouter, createWebHistory } from 'vue-router';
import { expect, vi } from 'vitest';
-import { nextTick } from 'vue';
import getRouter from '~/router';
import ProactiveHelpDialog from '~/components/infolinks/ProactiveHelpDialog.vue';
+import { useAdminStore } from '~/store/admin';
+
+const STUBS = {
+ VRow: {
+ template: '
',
+ },
+ VCol: {
+ template: '
',
+ },
+ VDialog: {
+ template: '
',
+ },
+ VCard: {
+ template: '
',
+ },
+ VContainer: {
+ template: '
',
+ },
+ VTextField: {
+ template: '
',
+ },
+ VCheckbox: {
+ template: '
',
+ },
+ VTextArea: {
+ template: '
',
+ },
+ VIcon: {
+ template: '
',
+ },
+ VFileInput: {
+ template: '
',
+ },
+ VBtn: {
+ template: '
',
+ },
+};
describe('ProactiveHelpDialog.vue', () => {
const pinia = createTestingPinia();
+ const adminStore = useAdminStore(pinia);
const router = createRouter({
history: createWebHistory(),
routes: getRouter().getRoutes(),
@@ -20,8 +57,176 @@ describe('ProactiveHelpDialog.vue', () => {
setActivePinia(pinia);
- it('resetDialog', async () => {
+ it('renders', async () => {
const wrapper = mount(ProactiveHelpDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump text',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ componentName: 'content',
+ groupName: 'test',
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ stubs: STUBS,
+ },
+ });
+
+ await flushPromises();
+
+ expect(wrapper.html()).toContain('content');
+ });
+
+ it('rules should return largeImgTxt if it fails', () => {
+ const wrapper = shallowMount(ProactiveHelpDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump text',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ groupName: 'test',
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ },
+ });
+
+ expect(wrapper.vm.rules[0]([{ size: 5000000 }])).toEqual(
+ 'trans.proactiveHelpDialog.largeImgTxt'
+ );
+ });
+
+ it('onCloseDialog should call resetDialog and emit close-dialog', () => {
+ const wrapper = shallowMount(ProactiveHelpDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump text',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ groupName: 'test',
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ },
+ });
+
+ wrapper.vm.onCloseDialog();
+ expect(wrapper.emitted()).toHaveProperty('close-dialog');
+ });
+
+ it('validateLinkUrl should return true and set linkError to true if isLinkEnabled and moreHelpInfoLink is blank otherwise false', () => {
+ const wrapper = shallowMount(ProactiveHelpDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump text',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ groupName: 'test',
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ },
+ });
+
+ expect(wrapper.vm.validateLinkUrl()).toBeFalsy();
+ expect(wrapper.vm.linkError).toBeFalsy();
+ wrapper.vm.isLinkEnabled = true;
+ wrapper.vm.moreHelpInfoLink = '';
+ expect(wrapper.vm.validateLinkUrl()).toBeTruthy();
+ expect(wrapper.vm.linkError).toBeTruthy();
+ });
+
+ it('selectImage will set imageSizeError to true if the image size is too large', async () => {
+ const wrapper = shallowMount(ProactiveHelpDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump text',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ groupName: 'test',
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ },
+ });
+
+ wrapper.vm.files = [{ size: 50000000 }];
+ await wrapper.vm.selectImage();
+ expect(wrapper.vm.imageSizeError).toBeTruthy();
+ });
+
+ it('selectImage will set imageSizeError to true if the image size is too large', async () => {
+ const wrapper = shallowMount(ProactiveHelpDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump text',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ groupName: 'test',
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ },
+ });
+
+ window.FileReader = function () {
+ this.readAsDataURL = vi.fn();
+ this.onerror = null;
+ };
+
+ wrapper.vm.files = [{ size: 1 }];
+
+ await wrapper.vm.selectImage();
+ expect(wrapper.vm.imageSizeError).toBeFalsy();
+ });
+
+ it('submit will call addFCProactiveHelp then emit close-dialog', async () => {
+ const wrapper = shallowMount(ProactiveHelpDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump text',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ groupName: 'test',
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ },
+ });
+
+ const addFCProactiveHelpSpy = vi.spyOn(adminStore, 'addFCProactiveHelp');
+ addFCProactiveHelpSpy.mockImplementation(() => {});
+
+ await wrapper.vm.submit();
+
+ expect(addFCProactiveHelpSpy).toBeCalledTimes(1);
+ expect(wrapper.emitted()).toHaveProperty('close-dialog');
+ });
+
+ it('resetDialog', async () => {
+ const wrapper = shallowMount(ProactiveHelpDialog, {
props: {
component: {
componentName: 'content',
@@ -38,7 +243,6 @@ describe('ProactiveHelpDialog.vue', () => {
});
wrapper.vm.resetDialog();
- await nextTick();
expect(wrapper.vm.description).toBe('');
});
});
diff --git a/app/frontend/tests/unit/components/infolinks/ProactiveHelpPreviewDialog.spec.js b/app/frontend/tests/unit/components/infolinks/ProactiveHelpPreviewDialog.spec.js
index 1eb4add91..c82038574 100644
--- a/app/frontend/tests/unit/components/infolinks/ProactiveHelpPreviewDialog.spec.js
+++ b/app/frontend/tests/unit/components/infolinks/ProactiveHelpPreviewDialog.spec.js
@@ -1,16 +1,13 @@
-import { mount } from '@vue/test-utils';
+import { mount, shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
import { createRouter, createWebHistory } from 'vue-router';
-import { beforeEach, expect, vi } from 'vitest';
+import { expect } from 'vitest';
-import { rbacService } from '~/services';
import getRouter from '~/router';
import ProactiveHelpPreviewDialog from '~/components/infolinks/ProactiveHelpPreviewDialog.vue';
-import { useFormStore } from '~/store/form';
describe('ProactiveHelpPreviewDialog.vue', () => {
- const getSubmissionUsersSpy = vi.spyOn(rbacService, 'getSubmissionUsers');
const pinia = createTestingPinia();
const router = createRouter({
history: createWebHistory(),
@@ -18,20 +15,8 @@ describe('ProactiveHelpPreviewDialog.vue', () => {
});
setActivePinia(pinia);
- const formStore = useFormStore(pinia);
-
- beforeEach(() => {
- getSubmissionUsersSpy.mockReset();
- formStore.$reset();
- });
-
- afterAll(() => {
- getSubmissionUsersSpy.mockRestore();
- });
it('renders', () => {
- formStore.form.name = 'myForm';
- getSubmissionUsersSpy.mockImplementation(() => ({ data: [] }));
const wrapper = mount(ProactiveHelpPreviewDialog, {
props: {
component: {
@@ -55,4 +40,30 @@ describe('ProactiveHelpPreviewDialog.vue', () => {
expect(wrapper.text()).toContain('content').toContain('dump description');
});
+
+ it('onCloseDialog should emit close-dialog', () => {
+ const wrapper = shallowMount(ProactiveHelpPreviewDialog, {
+ props: {
+ component: {
+ componentName: 'content',
+ description: 'dump description',
+ imageUrl: 'https://dumpurl.com',
+ moreHelpInfoLink: 'https://dumpurl.com',
+ },
+ showDialog: true,
+ },
+ global: {
+ plugins: [router, pinia],
+ stubs: {
+ VDialog: {
+ name: 'VDialog',
+ template: '
',
+ },
+ },
+ },
+ });
+
+ wrapper.vm.onCloseDialog();
+ expect(wrapper.emitted()).toHaveProperty('close-dialog');
+ });
});