|
677 | 677 | return; |
678 | 678 | } |
679 | 679 | |
680 | | - // Prepare data |
681 | | - const hours = @json($jobsByHour->pluck('hour')); |
682 | | - const totals = @json($jobsByHour->pluck('count')); |
683 | | - const failures = @json($jobsByHour->pluck('failed_count')); |
| 680 | + // Prepare data - ensure we get proper arrays |
| 681 | + const jobsData = @json($jobsByHour->toArray()); |
684 | 682 | |
685 | | - // Ensure we have data |
686 | | - if (!hours || hours.length === 0) { |
| 683 | + if (!jobsData || jobsData.length === 0) { |
| 684 | + if (ctx && ctx.parentElement) { |
| 685 | + ctx.parentElement.innerHTML = '<div class="p-4 text-gray-500 text-center">No data available for the selected time period.</div>'; |
| 686 | + } |
| 687 | + return; |
| 688 | + } |
| 689 | + |
| 690 | + // Extract arrays from data |
| 691 | + const hours = jobsData.map(item => item.hour); |
| 692 | + const totals = jobsData.map(item => parseInt(item.count) || 0); |
| 693 | + const failures = jobsData.map(item => parseInt(item.failed_count) || 0); |
| 694 | + |
| 695 | + // Ensure arrays are valid and same length |
| 696 | + if (hours.length === 0 || totals.length === 0 || hours.length !== totals.length) { |
| 697 | + if (ctx && ctx.parentElement) { |
| 698 | + ctx.parentElement.innerHTML = '<div class="p-4 text-gray-500 text-center">No data available for the selected time period.</div>'; |
| 699 | + } |
687 | 700 | return; |
688 | 701 | } |
689 | 702 | |
|
721 | 734 | return; |
722 | 735 | } |
723 | 736 | |
| 737 | + // For single data point, create a small time range to show as a line |
| 738 | + // This ensures the chart always shows as a line chart with filled area |
| 739 | + let chartLabels = labels; |
| 740 | + let chartSuccessRates = successRates; |
| 741 | + let chartTotals = totals; |
| 742 | + let chartFailures = failures; |
| 743 | + |
| 744 | + if (labels.length === 1) { |
| 745 | + // Create a second point 1 hour later to form a line segment |
| 746 | + try { |
| 747 | + const singleDate = new Date(hours[0].replace(' ', 'T')); |
| 748 | + const nextHour = new Date(singleDate.getTime() + 60 * 60 * 1000); |
| 749 | + const nextLabel = nextHour.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: '2-digit' }); |
| 750 | + |
| 751 | + chartLabels = [labels[0], nextLabel]; |
| 752 | + chartSuccessRates = [successRates[0], successRates[0]]; |
| 753 | + chartTotals = [totals[0], totals[0]]; |
| 754 | + chartFailures = [failures[0], failures[0]]; |
| 755 | + } catch (e) { |
| 756 | + // Fallback: just duplicate if date parsing fails |
| 757 | + chartLabels = [labels[0], labels[0]]; |
| 758 | + chartSuccessRates = [successRates[0], successRates[0]]; |
| 759 | + chartTotals = [totals[0], totals[0]]; |
| 760 | + chartFailures = [failures[0], failures[0]]; |
| 761 | + } |
| 762 | + } |
| 763 | + |
724 | 764 | try { |
725 | | - // Ensure single data points are visible with larger point radius |
726 | | - const pointRadius = labels.length === 1 ? 8 : 3; |
727 | | - const pointHoverRadius = labels.length === 1 ? 10 : 5; |
| 765 | + // Point radius - smaller for single point (since we duplicate it) |
| 766 | + const pointRadius = 4; |
| 767 | + const pointHoverRadius = 6; |
728 | 768 | |
729 | 769 | const chart = new Chart(ctx, { |
730 | 770 | type: 'line', |
731 | 771 | data: { |
732 | | - labels: labels, |
| 772 | + labels: chartLabels, |
733 | 773 | datasets: [ |
734 | 774 | { |
735 | 775 | label: 'Success Rate (%)', |
736 | | - data: successRates, |
| 776 | + data: chartSuccessRates, |
737 | 777 | borderColor: 'rgb(34, 197, 94)', |
738 | 778 | backgroundColor: 'rgba(34, 197, 94, 0.1)', |
| 779 | + borderWidth: 2, |
739 | 780 | tension: 0.4, |
740 | 781 | fill: true, |
741 | 782 | yAxisID: 'y', |
742 | 783 | pointRadius: pointRadius, |
743 | 784 | pointHoverRadius: pointHoverRadius, |
744 | | - pointBackgroundColor: function(context) { |
745 | | - return context.dataset.borderColor; |
746 | | - }, |
| 785 | + pointBackgroundColor: 'rgb(34, 197, 94)', |
747 | 786 | pointBorderColor: '#fff', |
748 | 787 | pointBorderWidth: 2, |
| 788 | + // Ensure line is visible even with single point |
| 789 | + spanGaps: false, |
| 790 | + showLine: true, |
749 | 791 | }, |
750 | 792 | { |
751 | 793 | label: 'Total Jobs', |
752 | | - data: totals, |
| 794 | + data: chartTotals, |
753 | 795 | borderColor: 'rgb(99, 102, 241)', |
754 | 796 | backgroundColor: 'rgba(99, 102, 241, 0.1)', |
| 797 | + borderWidth: 2, |
755 | 798 | tension: 0.4, |
756 | 799 | fill: true, |
757 | 800 | yAxisID: 'y1', |
758 | 801 | pointRadius: pointRadius, |
759 | 802 | pointHoverRadius: pointHoverRadius, |
760 | | - pointBackgroundColor: function(context) { |
761 | | - return context.dataset.borderColor; |
762 | | - }, |
| 803 | + pointBackgroundColor: 'rgb(99, 102, 241)', |
763 | 804 | pointBorderColor: '#fff', |
764 | 805 | pointBorderWidth: 2, |
| 806 | + spanGaps: false, |
| 807 | + showLine: true, |
765 | 808 | }, |
766 | 809 | { |
767 | 810 | label: 'Failed Jobs', |
768 | | - data: failures, |
| 811 | + data: chartFailures, |
769 | 812 | borderColor: 'rgb(239, 68, 68)', |
770 | 813 | backgroundColor: 'rgba(239, 68, 68, 0.1)', |
| 814 | + borderWidth: 2, |
771 | 815 | tension: 0.4, |
772 | 816 | fill: true, |
773 | 817 | yAxisID: 'y1', |
774 | 818 | pointRadius: pointRadius, |
775 | 819 | pointHoverRadius: pointHoverRadius, |
776 | | - pointBackgroundColor: function(context) { |
777 | | - return context.dataset.borderColor; |
778 | | - }, |
| 820 | + pointBackgroundColor: 'rgb(239, 68, 68)', |
779 | 821 | pointBorderColor: '#fff', |
780 | 822 | pointBorderWidth: 2, |
| 823 | + spanGaps: false, |
| 824 | + showLine: true, |
781 | 825 | } |
782 | 826 | ] |
783 | 827 | }, |
784 | 828 | options: { |
785 | 829 | responsive: true, |
786 | 830 | maintainAspectRatio: false, |
| 831 | + animation: { |
| 832 | + duration: 750, |
| 833 | + }, |
787 | 834 | interaction: { |
788 | 835 | mode: 'index', |
789 | 836 | intersect: false, |
790 | 837 | }, |
| 838 | + elements: { |
| 839 | + line: { |
| 840 | + borderJoinStyle: 'round', |
| 841 | + borderCapStyle: 'round', |
| 842 | + }, |
| 843 | + point: { |
| 844 | + hoverRadius: 8, |
| 845 | + } |
| 846 | + }, |
791 | 847 | plugins: { |
792 | 848 | legend: { |
793 | 849 | display: true, |
|
0 commit comments