Add stat comparison
This commit is contained in:
		
							parent
							
								
									1691eb4550
								
							
						
					
					
						commit
						2a0e5ea6bf
					
				| @ -59,6 +59,13 @@ class Service(models.Model): | |||||||
|         if end_time is None: |         if end_time is None: | ||||||
|             end_time = timezone.now() |             end_time = timezone.now() | ||||||
| 
 | 
 | ||||||
|  |         main_data = self.get_relative_stats(start_time, end_time) | ||||||
|  |         comparison_data = self.get_relative_stats(start_time - (end_time - start_time), start_time) | ||||||
|  |         main_data["compare"] = comparison_data | ||||||
|  | 
 | ||||||
|  |         return main_data | ||||||
|  | 
 | ||||||
|  |     def get_relative_stats(self, start_time, end_time): | ||||||
|         Session = apps.get_model("analytics", "Session") |         Session = apps.get_model("analytics", "Session") | ||||||
|         Hit = apps.get_model("analytics", "Hit") |         Hit = apps.get_model("analytics", "Hit") | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,17 +12,24 @@ | |||||||
|         <div class="grid grid-cols-2 md:grid-cols-4 gap-6"> |         <div class="grid grid-cols-2 md:grid-cols-4 gap-6"> | ||||||
|             <div> |             <div> | ||||||
|                 <p>Sessions</p> |                 <p>Sessions</p> | ||||||
|                 <p class="label">{{stats.session_count|intcomma}}</p> |                 <p class="label"> | ||||||
|  |                     {{stats.session_count|intcomma}} | ||||||
|  |                     {% compare stats.compare.session_count stats.session_count "UP" %} | ||||||
|  |                 </p> | ||||||
|             </div> |             </div> | ||||||
|             <div> |             <div> | ||||||
|                 <p>Hits</p> |                 <p>Hits</p> | ||||||
|                 <p class="label">{{stats.hit_count|intcomma}}</p> |                 <p class="label"> | ||||||
|  |                     {{stats.hit_count|intcomma}} | ||||||
|  |                     {% compare stats.compare.hit_count stats.hit_count "UP" %} | ||||||
|  |                 </p> | ||||||
|             </div> |             </div> | ||||||
|             <div> |             <div> | ||||||
|                 <p>Bounce Rate</p> |                 <p>Bounce Rate</p> | ||||||
|                 <p class="label"> |                 <p class="label"> | ||||||
|                     {% if stats.bounce_rate_pct != None %} |                     {% if stats.bounce_rate_pct != None %} | ||||||
|                     {{stats.bounce_rate_pct|floatformat:"-1"}}% |                     {{stats.bounce_rate_pct|floatformat:"-1"}}% | ||||||
|  |                     {% compare stats.compare.bounce_rate_pct stats.bounce_rate_pct "DOWN" %} | ||||||
|                     {% else %} |                     {% else %} | ||||||
|                     ? |                     ? | ||||||
|                     {% endif %} |                     {% endif %} | ||||||
| @ -33,6 +40,7 @@ | |||||||
|                 <p class="label"> |                 <p class="label"> | ||||||
|                     {% if stats.avg_session_duration != None %} |                     {% if stats.avg_session_duration != None %} | ||||||
|                     {{stats.avg_session_duration|naturaldelta}} |                     {{stats.avg_session_duration|naturaldelta}} | ||||||
|  |                     {% compare stats.compare.avg_session_duration stats.avg_session_duration "UP" %} | ||||||
|                     {% else %} |                     {% else %} | ||||||
|                     ? |                     ? | ||||||
|                     {% endif %} |                     {% endif %} | ||||||
|  | |||||||
| @ -0,0 +1,7 @@ | |||||||
|  | {% load helpers %} | ||||||
|  | 
 | ||||||
|  | <span | ||||||
|  |     class="{{classes}} {% relative_stat_tone start end good good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %}" | ||||||
|  |     title="Compared against equal period prior"> | ||||||
|  |     {% percent_change_display start end %} | ||||||
|  | </span> | ||||||
| @ -12,16 +12,23 @@ | |||||||
| 
 | 
 | ||||||
| {% block service_content %} | {% block service_content %} | ||||||
| <div class="grid grid-cols-2 gap-6 md:flex justify-between mb-6 card ~neutral !high px-6" id="stats"> | <div class="grid grid-cols-2 gap-6 md:flex justify-between mb-6 card ~neutral !high px-6" id="stats"> | ||||||
|  |     {% with classes="text-sm font-semibold" good_classes="text-green-400" bad_classes="text-red-400" neutral_classes="text-gray-400" %} | ||||||
|     <article class=""> |     <article class=""> | ||||||
|         <p class="label text-gray-400">Sessions</p> |         <p class="label text-gray-400">Sessions</p> | ||||||
|         <p class="heading"> |         <p class="heading"> | ||||||
|             {{stats.session_count|intcomma}} |             {{stats.session_count|intcomma}} | ||||||
|  |             <div> | ||||||
|  |                 {% compare stats.compare.session_count stats.session_count "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} | ||||||
|  |             </div> | ||||||
|         </p> |         </p> | ||||||
|     </article> |     </article> | ||||||
|     <article class=""> |     <article class=""> | ||||||
|         <p class="label text-gray-400">Hits</p> |         <p class="label text-gray-400">Hits</p> | ||||||
|         <p class="heading"> |         <p class="heading"> | ||||||
|             {{stats.hit_count|intcomma}} |             {{stats.hit_count|intcomma}} | ||||||
|  |             <div> | ||||||
|  |                 {% compare stats.compare.hit_count stats.hit_count "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} | ||||||
|  |             </div> | ||||||
|         </p> |         </p> | ||||||
|     </article> |     </article> | ||||||
|     <article class=""> |     <article class=""> | ||||||
| @ -29,6 +36,9 @@ | |||||||
|         <p class="heading"> |         <p class="heading"> | ||||||
|             {% if stats.avg_load_time %} |             {% if stats.avg_load_time %} | ||||||
|             {{stats.avg_load_time|floatformat:"0"}}ms |             {{stats.avg_load_time|floatformat:"0"}}ms | ||||||
|  |             <div> | ||||||
|  |                 {% compare stats.compare.avg_load_time stats.avg_load_time "DOWN" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} | ||||||
|  |             </div> | ||||||
|             {% else %} |             {% else %} | ||||||
|             ? |             ? | ||||||
|             {% endif %} |             {% endif %} | ||||||
| @ -39,6 +49,9 @@ | |||||||
|         <p class="heading"> |         <p class="heading"> | ||||||
|             {% if stats.bounce_rate_pct %} |             {% if stats.bounce_rate_pct %} | ||||||
|             {{stats.bounce_rate_pct|floatformat:"-1"}}% |             {{stats.bounce_rate_pct|floatformat:"-1"}}% | ||||||
|  |             <div> | ||||||
|  |                 {% compare stats.compare.bounce_rate_pct stats.bounce_rate_pct "DOWN" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} | ||||||
|  |             </div> | ||||||
|             {% else %} |             {% else %} | ||||||
|             ? |             ? | ||||||
|             {% endif %} |             {% endif %} | ||||||
| @ -49,6 +62,9 @@ | |||||||
|         <p class="heading"> |         <p class="heading"> | ||||||
|             {% if stats.avg_session_duration %} |             {% if stats.avg_session_duration %} | ||||||
|             {{stats.avg_session_duration|naturaldelta}} |             {{stats.avg_session_duration|naturaldelta}} | ||||||
|  |             <div> | ||||||
|  |                 {% compare stats.compare.avg_session_duration stats.avg_session_duration "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} | ||||||
|  |             </div> | ||||||
|             {% else %} |             {% else %} | ||||||
|             ? |             ? | ||||||
|             {% endif %} |             {% endif %} | ||||||
| @ -59,11 +75,15 @@ | |||||||
|         <p class="heading"> |         <p class="heading"> | ||||||
|             {% if stats.avg_hits_per_session %} |             {% if stats.avg_hits_per_session %} | ||||||
|             {{stats.avg_hits_per_session|floatformat:"-1"}} |             {{stats.avg_hits_per_session|floatformat:"-1"}} | ||||||
|  |             <div> | ||||||
|  |                 {% compare stats.compare.avg_hits_per_session stats.avg_hits_per_session "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} | ||||||
|  |             </div> | ||||||
|             {% else %} |             {% else %} | ||||||
|             ? |             ? | ||||||
|             {% endif %} |             {% endif %} | ||||||
|         </p> |         </p> | ||||||
|     </article> |     </article> | ||||||
|  |     {% endwith %} | ||||||
| </div> | </div> | ||||||
| <div class="card ~neutral !low py-0 mb-6"> | <div class="card ~neutral !low py-0 mb-6"> | ||||||
|     {% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data %} |     {% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data %} | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ def flag_emoji(isocode): | |||||||
|     except: |     except: | ||||||
|         return "" |         return "" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def country_name(isocode): | def country_name(isocode): | ||||||
|     try: |     try: | ||||||
| @ -37,6 +38,72 @@ def country_name(isocode): | |||||||
|     except: |     except: | ||||||
|         return "Unknown" |         return "Unknown" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | @register.simple_tag | ||||||
|  | def relative_stat_tone( | ||||||
|  |     start, | ||||||
|  |     end, | ||||||
|  |     good="UP", | ||||||
|  |     good_classes=None, | ||||||
|  |     bad_classes=None, | ||||||
|  |     neutral_classes=None, | ||||||
|  | ): | ||||||
|  |     good_classes = good_classes or "~positive" | ||||||
|  |     bad_classes = bad_classes or "~critical" | ||||||
|  |     neutral_classes = neutral_classes or "~neutral" | ||||||
|  |      | ||||||
|  |     if start == None or end == None or start == end: | ||||||
|  |         return neutral_classes | ||||||
|  |     if good == "UP": | ||||||
|  |         return good_classes if start <= end else bad_classes | ||||||
|  |     elif good == "DOWN": | ||||||
|  |         return bad_classes if start <= end else good_classes | ||||||
|  |     else: | ||||||
|  |         return neutral_classes | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @register.simple_tag | ||||||
|  | def percent_change_display(start, end): | ||||||
|  |     if start == None or end == None: | ||||||
|  |         return SafeString("Δ n/a") | ||||||
|  |     if start == end: | ||||||
|  |         direction = "" | ||||||
|  |     else: | ||||||
|  |         direction = "↑ " if end > start else "↓ " | ||||||
|  | 
 | ||||||
|  |     if start == 0 and end != 0: | ||||||
|  |         pct_change = "100%" | ||||||
|  |     else: | ||||||
|  |         change = int(round(100 * abs(end - start) / start)) | ||||||
|  |         if change > 999: | ||||||
|  |             return "> 999%" | ||||||
|  |         else: | ||||||
|  |             pct_change = str(change) + "%" | ||||||
|  | 
 | ||||||
|  |     return SafeString(direction + pct_change) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @register.inclusion_tag("dashboard/includes/stat_comparison.html") | ||||||
|  | def compare( | ||||||
|  |     start, | ||||||
|  |     end, | ||||||
|  |     good, | ||||||
|  |     classes="badge", | ||||||
|  |     good_classes=None, | ||||||
|  |     bad_classes=None, | ||||||
|  |     neutral_classes=None, | ||||||
|  | ): | ||||||
|  |     return { | ||||||
|  |         "start": start, | ||||||
|  |         "end": end, | ||||||
|  |         "good": good, | ||||||
|  |         "classes": classes, | ||||||
|  |         "good_classes": good_classes, | ||||||
|  |         "bad_classes": bad_classes, | ||||||
|  |         "neutral_classes": neutral_classes, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @register.filter | @register.filter | ||||||
| def startswith(text, starts): | def startswith(text, starts): | ||||||
|     if isinstance(text, str): |     if isinstance(text, str): | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user