44 :buttons =" [
55 {
66 label: 'Translate',
7- onclick: (dialog) => { runTranslation(); dialog.hide(); } ,
7+ onclick: async (dialog) => { await runTranslation(); dialog.hide(); } ,
88 options: {
99 disabled: noneChecked
1010 }
1919 ]"
2020 >
2121 <template #trigger >
22- <button
23- v-if =" checkboxes.length > 0"
24- class =" flex gap-1 items-center py-1 px-3 text-sm font-medium text-lightListViewButtonText focus:outline-none bg-lightListViewButtonBackground rounded-default border border-lightListViewButtonBorder hover:bg-lightListViewButtonBackgroundHover hover:text-lightListViewButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightListViewButtonFocusRing dark:focus:ring-darkListViewButtonFocusRing dark:bg-darkListViewButtonBackground dark:text-darkListViewButtonText dark:border-darkListViewButtonBorder dark:hover:text-darkListViewButtonTextHover dark:hover:bg-darkListViewButtonBackgroundHover"
25- >
26- <IconLanguageOutline class =" w-5 h-5" />
27- {{ t('Translate Selected') }} {{ `(${checkboxes.length})` }}
28- <div class =" text-white bg-gradient-to-r from-purple-500 via-purple-600 to-purple-700 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-purple-300 dark:focus:ring-purple-800
29- font-medium rounded-sm text-xs px-1 ml-1 text-center " >
30- AI
22+ <button class =" flex items-center justify-center w-full" >
23+ <IconLanguageOutline class =" text-gray-500 dark:text-gray-400 w-5 h-5" />
24+ <div class =" flex items-end justify-start gap-2 cursor-pointer" >
25+ <p class =" text-justify max-h-[18px] truncate max-w-[60vw] md:max-w-none" >{{ t('Translate filtered') }}</p >
26+ <div class =" flex items-center justify-center text-white bg-gradient-to-r h-[18px] from-purple-500 via-purple-600 to-purple-700 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-purple-300 dark:focus:ring-purple-800 font-medium rounded-md text-sm px-1 text-center" >
27+ {{t('AI')}}
28+ </div >
3129 </div >
3230 </button >
3331 </template >
3432
3533 <div class =" af-i18n-translations-selector grid grid-cols-2 gap-1 w-full" >
34+ <div v-if =" isLoading" class =" top-0 left-0 z-10 absolute bg-black/30 w-full h-full rounded-lg flex items-center justify-center" >
35+ <Spinner class =" w-10 h-10" />
36+ </div >
3637 <Button @click =" selectAll" :disabled =" allChecked" >{{ t('Select All') }}</Button >
3738 <Button @click =" uncheckAll" :disabled =" noneChecked" >{{ t('Uncheck All') }}</Button >
3839 <div class =" col-span-2 grid grid-cols-3 gap-1 mt-4" >
5253<script setup lang="ts">
5354 import { IconLanguageOutline } from ' @iconify-prerendered/vue-flowbite' ;
5455 import { useI18n } from ' vue-i18n' ;
55- import { Dialog , Button , Checkbox } from ' @/afcl' ;
56- import { computed , onMounted , ref , watch } from ' vue' ;
56+ import { Dialog , Button , Checkbox , Spinner } from ' @/afcl' ;
57+ import { computed , onMounted , ref , onUnmounted } from ' vue' ;
5758 import { callAdminForthApi } from ' @/utils' ;
5859 import { useAdminforth } from ' @/adminforth' ;
5960 import { getCountryCodeFromLangCode } from ' ./langCommon' ;
6061 import { getName , overwrite } from ' country-list' ;
6162 import ISO6391 from ' iso-639-1' ;
6263 import ' flag-icon-css/css/flag-icons.min.css' ;
64+ import websocket from ' @/websocket' ;
65+ import { useFiltersStore } from ' @/stores/filters' ;
66+
67+ const filtersStore = useFiltersStore ();
6368
6469 const { t } = useI18n ();
6570 const adminforth = useAdminforth ();
8085 }>();
8186
8287 const checkedLanguages = ref <Record <string , boolean >>({});
88+ const isLoading = ref (false );
8389 const allChecked = computed (() => Object .values (checkedLanguages .value ).every (Boolean ));
8490 const noneChecked = computed (() => Object .values (checkedLanguages .value ).every (value => ! value ));
8591
8692 onMounted (() => {
93+ websocket .subscribe (' /translation_progress' , (data ) => {
94+ adminforth .list .refresh ();
95+ });
8796 for (const lang of props .meta .supportedLanguages ) {
8897 checkedLanguages .value [lang ] = true ;
8998 }
9099 });
100+
101+ onUnmounted ( () => {
102+ websocket .unsubscribe (' /translation_progress' );
103+ } )
91104
92105 function selectAll() {
93106 for (const lang of props .meta .supportedLanguages ) {
106119 }
107120
108121 async function runTranslation() {
122+ isLoading .value = true ;
123+ const listOfIds = await getListOfIds ();
109124 try {
110125 const res = await callAdminForthApi ({
111126 path: ` /plugin/${props .meta .pluginInstanceId }/translate-selected-to-languages ` ,
112127 method: ' POST' ,
113128 body: {
114- selectedIds: props . checkboxes ,
129+ selectedIds: listOfIds ,
115130 selectedLanguages: Object .keys (checkedLanguages .value ).filter (lang => checkedLanguages .value [lang ]),
116131 },
117132 silentError: true ,
118133 });
119- adminforth .list .refresh ();
120134 props .clearCheckboxes ();
121135 if (res .ok ) {
122- adminforth .alert ({ message: res .successMessage , variant: ' success' });
136+ adminforth .alert ({ message: ` Running translation job ` , variant: ' success' });
137+ console .log (' Received record IDs for filtered selector:' , res );
138+ const jobId = res .jobId ;
139+ if (jobId ) {
140+ console .log (' Opening job info popup for jobId:' , jobId );
141+ // @ts-ignore
142+ window .OpenJobInfoPopup (jobId );
143+ }
123144 } else {
124145 adminforth .alert ({ message: res .errorMessage || t (' Failed to translate selected items. Please, try again.' ), variant: ' danger' });
125146 }
126147 } catch (e ) {
127148 console .error (' Failed to translate selected items:' , e );
128149 adminforth .alert ({ message: t (' Failed to translate selected items. Please, try again.' ), variant: ' danger' });
129150 }
151+ isLoading .value = false ;
152+ }
153+
154+ async function getListOfIds() {
155+ const filters = filtersStore .getFilters ();
156+ let res;
157+ try {
158+ res = await callAdminForthApi ({
159+ path: ` /plugin/${props .meta .pluginInstanceId }/get_filtered_ids ` ,
160+ method: ' POST' ,
161+ body: { filters },
162+ silentError: true ,
163+ });
164+ } catch (e ) {
165+ console .error (' Failed to get records for filtered selector:' , e );
166+ return [];
167+ }
168+ if (! res ?.ok || ! res ?.recordIds ) {
169+ console .error (' Failed to get records for filtered selector, response error:' , res );
170+ return [];
171+ }
172+ return res .recordIds ;
130173 }
174+
131175
132176 </script >
0 commit comments