PluginProbe
Hostinger Tools / 3.0.61
Hostinger Tools v3.0.61
3.0.77 3.0.76 3.0.75 3.0.74 3.0.73 3.0.72 3.0.71 3.0.70 3.0.69 3.0.68 3.0.67 3.0.66 1.8.1 1.8.2 1.8.3 1.9.1 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.4 All 108 releases
hostinger / vue-frontend / src / views / HostingerTools.vue

HostingerTools.vue in Hostinger Tools 3.0.61, at vue-frontend/src/views/HostingerTools.vue

486 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <script lang="ts" setup>
2 import { storeToRefs } from "pinia";
3 import { computed, ref } from "vue";
4
5 import Button from "@/components/Button/Button.vue";
6 import SectionCard from "@/components/HostingerTools/SectionCard.vue";
7 import ToolVersionCard from "@/components/HostingerTools/ToolVersionCard.vue";
8 import Icon from "@/components/Icon/Icon.vue";
9 import { useModal } from "@/composables";
10 import { useGeneralStoreData, useSettingsStore } from "@/stores";
11 import {
12 ModalName,
13 SectionItem,
14 ToggleableSettingsData
15 } from "@/types";
16 import { SECTION_ID } from "@/types/models/components/sectionCardModels";
17 import {
18 getAssetSource,
19 getBaseUrl,
20 isNewerVerison,
21 kebabToCamel,
22 translate
23 } from "@/utils/helpers";
24 import {toast} from "vue3-toastify";
25
26 const { fetchSettingsData, updateSettingsData, regenerateByPassCode } =
27 useSettingsStore();
28
29 const { settingsData } = storeToRefs(useSettingsStore());
30 const {
31 siteUrl,
32 llmstxtFileUrl,
33 llmstxtFileUserGenerated
34 } = useGeneralStoreData();
35
36 const WORDPRESS_UPDATE_LINK = getBaseUrl(location.href) + "update-core.php";
37
38 const isPageLoading = ref(false);
39
40 const HOSTINGER_FREE_DOMAINS = /hostingersite\.com|hostinger\.dev/;
41
42 const llmMasterToggle = ref(false);
43
44 const isLLMSSectionDisabled = computed(
45 () => isFreeDomain.value || !isHostingerPlatform.value
46 );
47
48 const maintenanceSection = computed(() => [
49 {
50 id: SECTION_ID.MAINTENANCE_MODE,
51 title: translate("hostinger_tools_maintenance_mode"),
52 description: translate("hostinger_tools_disable_public_access"),
53 isVisible: true,
54 toggleValue: settingsData.value?.maintenanceMode
55 },
56 {
57 id: SECTION_ID.BYPASS_LINK,
58 title: translate("hostinger_tools_bypass_link"),
59 description: translate("hostinger_tools_skip_link_maintenance_mode"),
60 isVisible: true,
61 sideButton: {
62 text: translate("hostinger_tools_reset_link"),
63 onClick: () => {
64 openModal(
65 ModalName.ByPassLinkResetModal,
66 {
67 data: {
68 onConfirm: () => regenerateByPassCode()
69 }
70 },
71 { isLG: true }
72 );
73 }
74 },
75 copyLink: settingsData.value?.bypassCode
76 ? `${siteUrl}/?bypass_code=${settingsData.value.bypassCode}`
77 : undefined
78 }
79 ]);
80
81 const securitySection = computed(() =>
82 [
83 {
84 id: SECTION_ID.DISABLE_XML_RPC,
85 title: translate("hostinger_tools_disable_xml_rpc"),
86 description: translate("hostinger_tools_xml_rpc_description"),
87 isVisible: true,
88 toggleValue: settingsData.value?.disableXmlRpc
89 },
90 {
91 id: SECTION_ID.DISABLE_AUTHENTICATION_PASSWORD,
92 title: translate("hostinger_tools_disable_authentication_password"),
93 description: translate(
94 "hostinger_tools_authentication_password_description"
95 ),
96 isVisible: true,
97 toggleValue: settingsData.value?.disableAuthenticationPassword
98 }
99 ].filter((item) => item.isVisible)
100 );
101
102 const redirectsSection = computed(() => {
103 const allItems = [
104 {
105 id: SECTION_ID.FORCE_HTTPS,
106 title: translate("hostinger_tools_force_https"),
107 description: translate("hostinger_tools_force_https_description"),
108 isVisible: true,
109 toggleValue: settingsData.value?.forceHttps
110 },
111 {
112 id: SECTION_ID.FORCE_WWW,
113 title: translate("hostinger_tools_force_www"),
114 description: !settingsData.value?.isEligibleWwwRedirect
115 ? translate(
116 "hostinger_tools_force_www_description_not_available"
117 )
118 : translate("hostinger_tools_force_www_description"),
119 isVisible: !!settingsData.value?.isEligibleWwwRedirect,
120 toggleValue: settingsData.value?.forceWww
121 }
122 ];
123
124 return allItems.filter((item) => item.isVisible);
125 });
126
127 const llmsSection = computed(() => {
128 const allItems = [
129 {
130 id: SECTION_ID.ENABLE_LLMS_TXT,
131 title: translate("hostinger_tools_enable_llms_txt"),
132 description: translate("hostinger_tools_llms_txt_description"),
133 isVisible: true,
134 toggleValue: settingsData.value?.enableLlmsTxt,
135 learnMoreLink: "https://www.hostinger.com/support/how-to-enable-llms-txt-on-your-website/",
136 sideButtons: [
137 {
138 id: "hostinger_tools_llms_txt_llmstxt",
139 text: translate("hostinger_tools_llms_txt_llmstxt"),
140 isDisabled: !settingsData.value?.enableLlmsTxt,
141 to:
142 settingsData.value?.enableLlmsTxt &&
143 llmMasterToggle.value
144 ? llmstxtFileUrl
145 : undefined,
146 variant: "outline" as const
147 },
148 {
149 id: "hostinger_tools_llms_txt_check_validity",
150 text: translate("hostinger_tools_llms_txt_check_validity"),
151 isDisabled: !settingsData.value?.enableLlmsTxt,
152 to:
153 settingsData.value?.enableLlmsTxt &&
154 llmMasterToggle.value
155 ? `https://llmstxtvalidator.org/?url=${llmstxtFileUrl}`
156 : undefined,
157 variant: "outline" as const
158 }
159 ]
160 },
161 {
162 id: SECTION_ID.OPTIN_MCP,
163 title: translate("hostinger_tools_optin_mcp"),
164 description: translate("hostinger_tools_optin_mcp_description"),
165 isVisible: true,
166 toggleValue: settingsData.value?.optinMcp,
167 learnMoreLink:
168 "https://support.hostinger.com/en/articles/11729400-ai-agent-access-smart-ai-discovery",
169 sideButtons: [{
170 id: "hostinger_tools_optin_mcp_copy_agent_url",
171 text: translate("hostinger_tools_copy_agent_url"),
172 isDisabled: !settingsData.value?.optinMcp,
173 onClick: copyAgentUrl,
174 variant: "outline" as const
175 }],
176 }
177 ];
178
179 return allItems.filter((item) => item.isVisible);
180 });
181
182 const llmsSectionHeaderToggle = computed(() => {
183 const visibleItems = llmsSection.value.filter((item) => item.isVisible);
184 if (visibleItems.length <= 1) return undefined;
185
186 return {
187 value: llmMasterToggle.value,
188 onToggle: async (value: boolean) => {
189 llmMasterToggle.value = value;
190
191 if (!settingsData.value) return;
192
193 const updatedSettings = {
194 ...settingsData.value,
195 enableLlmsTxt: value,
196 optinMcp: value
197 };
198
199 const success = await updateSettingsData(updatedSettings);
200
201 if (success && settingsData.value) {
202 settingsData.value.enableLlmsTxt = value;
203 settingsData.value.optinMcp = value;
204 }
205 }
206 };
207 });
208
209 const { openModal } = useModal();
210
211 const isWordPressUpdateDisplayed = computed(() => {
212 if (!settingsData.value) {
213 return false;
214 }
215
216 return isNewerVerison({
217 currentVersion: settingsData.value.currentWpVersion,
218 newVersion: settingsData.value.newestWpVersion
219 });
220 });
221
222 const isPhpUpdateDisplayed = computed(() => {
223 if (!settingsData.value) {
224 return false;
225 }
226
227 return isNewerVerison({
228 currentVersion: settingsData.value.phpVersion,
229 newVersion: "8.2" // Hardcoded for now
230 });
231 });
232
233 const isHostingerPlatform = computed(
234 () => parseInt(hostinger_tools_data.hplatform) > 0
235 );
236
237 const isFreeDomain = computed(() =>
238 HOSTINGER_FREE_DOMAINS.test(String(siteUrl))
239 );
240
241 const createUpdateButton = (onClick: () => void) => ({
242 text: translate("hostinger_tools_update"),
243 onClick
244 });
245
246 const resellerLocale = computed(() => {
247 const { pluginUrl } = useGeneralStoreData();
248
249 return pluginUrl.match(/^[^/]+/)?.[0] || "hostinger.com";
250 });
251
252 const connectDomainUrl = computed(() => {
253 if (!isHostingerPlatform.value) return undefined;
254
255 const domain = location.host;
256
257 return `https://auth.${resellerLocale.value}/login?section=website-dashboard&domain=${domain}`;
258 });
259
260 const phpVersionCard = computed(() => ({
261 title: translate("hostinger_tools_php_version"),
262 toolImageSrc: getAssetSource("images/icons/icon-php.svg"),
263 version: settingsData.value?.phpVersion,
264 actionButton:
265 isHostingerPlatform.value && isPhpUpdateDisplayed.value
266 ? createUpdateButton(() => {
267 window.open(
268 `https://auth.${resellerLocale.value}/login?r=/section/php-configuration/domain/${location.host}`,
269 "_blank"
270 );
271 })
272 : undefined
273 }));
274
275 const wordPressVersionCard = computed(() => ({
276 title: translate("hostinger_tools_wordpress_version"),
277 toolImageSrc: getAssetSource("images/icons/icon-wordpress-light.svg"),
278 version: settingsData.value?.currentWpVersion,
279 actionButton: isWordPressUpdateDisplayed.value
280 ? createUpdateButton(() => {
281 window.location.href = WORDPRESS_UPDATE_LINK;
282 })
283 : undefined
284 }));
285
286 const onSaveSection = (value: boolean, item: SectionItem) => {
287 const isTurnedOn = value === false;
288
289 if (item.id === SECTION_ID.DISABLE_XML_RPC && isTurnedOn) {
290 openModal(
291 ModalName.XmlSecurityModal,
292 {
293 data: {
294 onConfirm: () => {
295 onUpdateSettings(value, item);
296 }
297 }
298 },
299 { isLG: true }
300 );
301
302 return;
303 }
304
305 onUpdateSettings(value, item);
306 };
307
308 const onSaveLLmsSection = async (isEnabled: boolean, item: SectionItem) => {
309 const updateSetting = async () => {
310 await onUpdateSettings(isEnabled, item);
311
312 // Update the master toggle state based on current settings
313 llmMasterToggle.value = !!(
314 settingsData.value?.enableLlmsTxt || settingsData.value?.optinMcp
315 );
316 };
317
318 if (
319 llmstxtFileUserGenerated &&
320 isEnabled &&
321 item.id === SECTION_ID.ENABLE_LLMS_TXT
322 ) {
323 openModal(
324 ModalName.EnableLlmsTxtModal,
325 {
326 data: {
327 onConfirm: () => {
328 updateSetting();
329 }
330 }
331 },
332 { isLG: true }
333 );
334
335 return;
336 }
337
338 await updateSetting();
339 };
340
341 const onUpdateSettings = async (value: boolean, item: SectionItem) => {
342 if (!settingsData.value) return;
343
344 const id = kebabToCamel(item.id) as keyof ToggleableSettingsData;
345
346 const updatedSettings = {
347 ...settingsData.value,
348 [id]: value
349 };
350
351 const success = await updateSettingsData(updatedSettings);
352
353 if (success && settingsData.value) {
354 settingsData.value[id] = value;
355 }
356 };
357
358 const copyAgentUrl = () => {
359 const domain = location.host;
360 const agentUrl = `websites-agents.hostinger.com/${domain}/mcp`;
361 navigator.clipboard.writeText(agentUrl);
362 toast.success(translate("hostinger_tools_copied_successfully"));
363 };
364
365 (async () => {
366 isPageLoading.value = true;
367 await fetchSettingsData();
368 isPageLoading.value = false;
369
370 llmMasterToggle.value = !!(
371 settingsData.value?.enableLlmsTxt || settingsData.value?.optinMcp
372 );
373 })();
374 </script>
375
376 <template>
377 <div v-if="settingsData">
378 <div class="hostinger-tools__tool-version-cards">
379 <ToolVersionCard
380 :is-loading="isPageLoading"
381 v-bind="wordPressVersionCard"
382 class="h-mr-16"
383 />
384 <ToolVersionCard
385 :is-loading="isPageLoading"
386 v-bind="phpVersionCard"
387 />
388 </div>
389 <div>
390 <SectionCard
391 :is-loading="isPageLoading"
392 :title="translate('hostinger_tools_llms')"
393 :section-items="llmsSection"
394 :is-disabled="isLLMSSectionDisabled"
395 :header-toggle="llmsSectionHeaderToggle"
396 :warning="
397 !isLLMSSectionDisabled && llmstxtFileUserGenerated
398 ? translate(
399 'hostinger_tools_llms_txt_external_file_found',
400 )
401 : ''
402 "
403 @save-section="onSaveLLmsSection"
404 >
405 <template
406 v-if="isLLMSSectionDisabled"
407 #snackbar
408 >
409 <div
410 class="hostinger-notice d-flex align-items-center w-100 h-mb-16"
411 >
412 <Icon
413 name="icon-info"
414 color="gray-dark"
415 />
416 <p class="text-body-3">
417 {{
418 translate(
419 "hostinger_tools_free_domain_llm_unavailable",
420 )
421 }}
422 </p>
423 <Button
424 v-if="connectDomainUrl"
425 size="small"
426 variant="text"
427 color="primary"
428 class="h-ml-8"
429 :to="connectDomainUrl"
430 target="_blank"
431 >
432 {{
433 translate("hostinger_tools_connect_domain_cta")
434 }}
435 </Button>
436 </div>
437 </template>
438 </SectionCard>
439
440 <SectionCard
441 :is-loading="isPageLoading"
442 :title="translate('hostinger_tools_maintenance')"
443 :section-items="maintenanceSection"
444 @save-section="onSaveSection"
445 />
446
447 <SectionCard
448 :is-loading="isPageLoading"
449 :title="translate('hostinger_tools_security')"
450 :section-items="securitySection"
451 @save-section="onSaveSection"
452 />
453
454 <SectionCard
455 :is-loading="isPageLoading"
456 :title="translate('hostinger_tools_redirects')"
457 :section-items="redirectsSection"
458 @save-section="onSaveSection"
459 />
460 </div>
461 </div>
462 </template>
463
464 <style lang="scss">
465 .hostinger-tools {
466 &__tool-version-cards {
467 display: flex;
468 width: 100%;
469
470 @media (max-width: 590px) {
471 flex-direction: column;
472 }
473 }
474 }
475
476 .hostinger-notice {
477 background: var(--gray-light);
478 color: var(--gray-dark);
479 border: 1px solid var(--gray-border);
480 border-radius: 12px;
481 padding: 12px 16px;
482 font-size: var(--font-size-sm);
483 gap: 1em;
484 }
485 </style>
486