PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.17
Yatra – Travel Booking & Tour Operator Software v3.0.17
3.0.17 3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 All 85 releases
← All changes | resources/js/components/Tools.tsx +87 -19 3.0.9 → 3.0.17 View file →
@@ -520,9 +520,9 @@
520 520
521 521 // Handle actual export after data type selection - uses background job
522 522 const handleExport = async () => {
523 523 if (selectedExportData.length === 0) {
524 - alert("Please select at least one data type to export.");
524 + showToast(__("Please select at least one data type to export.", "yatra"), "error");
525 525 return;
526 526 }
527 527
528 528 setIsExporting(true);
@@ -537,9 +537,9 @@
537 537 const jobId = data.job_id;
538 538 pollJobStatus(jobId, "export");
539 539 } catch (error) {
540 540 console.error("Export error:", error);
541 - alert("Export failed. Please try again.");
541 + showToast(__("Export failed. Please try again.", "yatra"), "error");
542 542 setIsExporting(false);
543 543 }
544 544 };
545 545
@@ -578,10 +578,17 @@
578 578 setIsImporting(false);
579 579 }
580 580
581 581 if (jobData.status === "failed") {
582 - alert(
583 - `${type === "export" ? "Export" : "Import"} failed: ${jobData.error || "Unknown error"}`,
582 + showToast(
583 + (type === "export"
584 + ? __("Export failed: %s", "yatra")
585 + : __("Import failed: %s", "yatra")
586 + ).replace(
587 + "%s",
588 + jobData.error || __("Unknown error", "yatra"),
589 + ),
590 + "error",
584 591 );
585 592 }
586 593 }
587 594 }
@@ -620,9 +627,9 @@
620 627 // Clear the job after download and deletion
621 628 setExportJob(null);
622 629 } catch (error) {
623 630 console.error("Download error:", error);
624 - alert("Download failed. Please try again.");
631 + showToast(__("Download failed. Please try again.", "yatra"), "error");
625 632 }
626 633 };
627 634
628 635 // Show delete confirmation modal
@@ -646,9 +653,9 @@
646 653 // Immediately clear the export job from state to remove it from UI
647 654 setExportJob(null);
648 655 } catch (error) {
649 656 console.error("Delete error:", error);
650 - alert("Failed to delete export file.");
657 + showToast(__("Failed to delete export file.", "yatra"), "error");
651 658 }
652 659 };
653 660
654 661 // Load logs when logs tab becomes active
@@ -660,9 +667,9 @@
660 667
661 668 // Handle file processing (for both input and drop) - uses background job
662 669 const processFile = async (file: File) => {
663 670 if (selectedImportData.length === 0) {
664 - alert("Please select at least one data type to import.");
671 + showToast(__("Please select at least one data type to import.", "yatra"), "error");
665 672 return;
666 673 }
667 674
668 675 setIsImporting(true);
@@ -679,9 +686,9 @@
679 686 pollJobStatus(jobId, "import");
680 687 setSelectedImportData([]);
681 688 } catch (error) {
682 689 console.error("Import error:", error);
683 - alert("Import failed. Please check the file format and try again.");
690 + showToast(__("Import failed. Please check the file format and try again.", "yatra"), "error");
684 691 setIsImporting(false);
685 692 }
686 693 };
687 694
@@ -715,9 +722,9 @@
715 722 (file) => file.type === "application/json" || file.name.endsWith(".json"),
716 723 );
717 724
718 725 if (!jsonFile) {
719 - alert("Please drop a valid JSON file.");
726 + showToast(__("Please drop a valid JSON file.", "yatra"), "error");
720 727 return;
721 728 }
722 729
723 730 setPendingImportFile(jsonFile);
@@ -1509,9 +1516,9 @@
1509 1516 <div className="mt-4 p-4 bg-green-50 dark:bg-green-900/20 rounded-lg">
1510 1517 <div className="flex items-center gap-2 mb-2">
1511 1518 <CheckCircle className="w-5 h-5 text-green-600 dark:text-green-400" />
1512 1519 <span className="text-sm font-medium text-green-700 dark:text-green-400">
1513 - Import completed successfully!
1520 + {__("Import completed successfully!", "yatra")}
1514 1521 </span>
1515 1522 <button
1516 1523 onClick={async () => {
1517 1524 if (!importJob) return;
@@ -1531,19 +1538,61 @@
1531 1538 <XCircle className="w-4 h-4" />
1532 1539 </button>
1533 1540 </div>
1534 1541
1535 - <div className="text-sm text-green-700 dark:text-green-400 mb-2">
1536 - Total: <strong>{importJob.processed_records}</strong>{" "}
1537 - records imported
1538 - </div>
1542 + {(() => {
1543 + // "0 imported" on its own reads as a failed import. A
1544 + // re-import is supposed to bring in nothing: the rows are
1545 + // already here and get skipped, which is the feature
1546 + // working. Say so, rather than leaving a column of zeroes
1547 + // and a red failure count to speak for themselves.
1548 + const totals = Object.values(
1549 + importJob.import_stats || {},
1550 + ).reduce(
1551 + (acc: any, s: any) => ({
1552 + imported: acc.imported + (s.imported || 0),
1553 + skipped: acc.skipped + (s.skipped || 0),
1554 + failed: acc.failed + (s.failed || 0),
1555 + }),
1556 + { imported: 0, skipped: 0, failed: 0 },
1557 + ) as { imported: number; skipped: number; failed: number };
1539 1558
1559 + return (
1560 + <div className="text-sm text-green-700 dark:text-green-400 mb-2">
1561 + <strong>{totals.imported}</strong>{" "}
1562 + {__("imported", "yatra")}
1563 + {totals.skipped > 0 && (
1564 + <>
1565 + {", "}
1566 + <strong>{totals.skipped}</strong>{" "}
1567 + {__("already here", "yatra")}
1568 + </>
1569 + )}
1570 + {totals.failed > 0 && (
1571 + <>
1572 + {", "}
1573 + <strong>{totals.failed}</strong>{" "}
1574 + {__("could not be linked", "yatra")}
1575 + </>
1576 + )}
1577 + {totals.imported === 0 && totals.skipped > 0 && (
1578 + <div className="text-xs mt-1">
1579 + {__(
1580 + "Everything in this file was already on the site, so nothing was duplicated.",
1581 + "yatra",
1582 + )}
1583 + </div>
1584 + )}
1585 + </div>
1586 + );
1587 + })()}
1588 +
1540 1589 {/* Detailed statistics by data type */}
1541 1590 {importJob.import_stats &&
1542 1591 Object.keys(importJob.import_stats).length > 0 && (
1543 1592 <div className="mt-2 border-t border-green-200 dark:border-green-800 pt-2">
1544 1593 <div className="text-xs font-medium text-green-700 dark:text-green-400 mb-2">
1545 - Import Details:
1594 + {__("Import Details:", "yatra")}
1546 1595 </div>
1547 1596 <div className="grid grid-cols-1 gap-1">
1548 1597 {Object.entries(importJob.import_stats).map(
1549 1598 ([dataType, stats]: [string, any]) => {
@@ -1560,9 +1609,9 @@
1560 1609 >
1561 1610 <div className="flex items-center gap-1">
1562 1611 <Icon className="w-3 h-3 text-green-600 dark:text-green-400" />
1563 1612 <span className="capitalize">
1564 - {dataType.replace("_", " ")}:
1613 + {dataType.replace(/_/g, " ")}:
1565 1614 </span>
1566 1615 </div>
1567 1616 <div>
1568 1617 <span className="text-green-700 dark:text-green-400">
@@ -1567,11 +1616,30 @@
1567 1616 <div>
1568 1617 <span className="text-green-700 dark:text-green-400">
1569 1618 {stats.imported}
1570 1619 </span>
1620 + {stats.skipped > 0 && (
1621 + <span
1622 + className="text-gray-500 dark:text-gray-400 ml-1"
1623 + title={__(
1624 + "Already present on this site, so not imported again",
1625 + "yatra",
1626 + )}
1627 + >
1628 + ({stats.skipped}{" "}
1629 + {__("already here", "yatra")})
1630 + </span>
1631 + )}
1571 1632 {stats.failed > 0 && (
1572 - <span className="text-red-600 dark:text-red-400 ml-1">
1573 - ({stats.failed} failed)
1633 + <span
1634 + className="text-amber-600 dark:text-amber-400 ml-1"
1635 + title={__(
1636 + "These rows point at a record the export file does not contain — usually something deleted on the original site — so there was nothing to attach them to.",
1637 + "yatra",
1638 + )}
1639 + >
1640 + ({stats.failed}{" "}
1641 + {__("not linked", "yatra")})
1574 1642 </span>
1575 1643 )}
1576 1644 </div>
1577 1645 </div>
@@ -1856,9 +1924,9 @@
1856 1924 className="flex items-center justify-between"
1857 1925 >
1858 1926 <div>
1859 1927 <span className="font-medium capitalize">
1860 - {key.replace("_", " ")}
1928 + {key.replace(/_/g, " ")}
1861 1929 </span>
1862 1930 <div className="text-sm text-gray-600 dark:text-gray-400">
1863 1931 Required: {req.required} | Current: {req.current}
1864 1932 </div>