mirror of
https://github.com/django-components/django-components.git
synced 2025-11-25 16:39:11 +00:00
Deployed c66bd212 to 0.142.3 with MkDocs 1.6.1 and mike 2.1.3
This commit is contained in:
parent
b1b1e8e855
commit
c949bd5afa
458 changed files with 47021 additions and 3 deletions
64
0.142.3/examples/analytics/component.py
Normal file
64
0.142.3/examples/analytics/component.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
from typing import Dict, List, NamedTuple
|
||||
|
||||
from django_components import Component, register, types
|
||||
|
||||
DESCRIPTION = "Track component errors or success rates to send them to Sentry or other services."
|
||||
|
||||
# A mock analytics service
|
||||
analytics_events: List[Dict] = []
|
||||
error_rate = {
|
||||
"error": 0,
|
||||
"success": 0,
|
||||
}
|
||||
|
||||
|
||||
@register("api_widget")
|
||||
class ApiWidget(Component):
|
||||
class Kwargs(NamedTuple):
|
||||
simulate_error: bool = False
|
||||
|
||||
def get_template_data(self, args, kwargs: Kwargs, slots, context):
|
||||
if kwargs.simulate_error:
|
||||
raise ConnectionError("API call failed")
|
||||
return {"data": "Mock API response data"}
|
||||
|
||||
template: types.django_html = """
|
||||
<div class="p-4 border rounded-lg bg-gray-50">
|
||||
<h4 class="font-bold text-gray-800">API Widget</h4>
|
||||
<p class="text-gray-600">Data: {{ data }}</p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
@register("sentry_error_tracker")
|
||||
class SentryErrorTracker(Component):
|
||||
def on_render_after(self, context, template, result, error):
|
||||
if error:
|
||||
event = {
|
||||
"type": "error",
|
||||
"component": self.registered_name,
|
||||
"error": error,
|
||||
}
|
||||
analytics_events.append(event)
|
||||
print(f"SENTRY: Captured error in component {self.registered_name}: {error}")
|
||||
|
||||
template: types.django_html = """
|
||||
{% load component_tags %}
|
||||
{% slot "default" / %}
|
||||
"""
|
||||
|
||||
|
||||
@register("success_rate_tracker")
|
||||
class SuccessRateTracker(Component):
|
||||
def on_render_after(self, context, template, result, error):
|
||||
# Track error
|
||||
if error:
|
||||
error_rate["error"] += 1
|
||||
# Track success
|
||||
else:
|
||||
error_rate["success"] += 1
|
||||
|
||||
template: types.django_html = """
|
||||
{% load component_tags %}
|
||||
{% slot "default" / %}
|
||||
"""
|
||||
BIN
0.142.3/examples/analytics/images/analytics.png
Normal file
BIN
0.142.3/examples/analytics/images/analytics.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
322
0.142.3/examples/analytics/index.html
Normal file
322
0.142.3/examples/analytics/index.html
Normal file
File diff suppressed because one or more lines are too long
117
0.142.3/examples/analytics/page.py
Normal file
117
0.142.3/examples/analytics/page.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
from django_components import Component, register, types
|
||||
|
||||
from .component import analytics_events, error_rate
|
||||
|
||||
|
||||
class AnalyticsPage(Component):
|
||||
class Media:
|
||||
js = ("https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,container-queries",)
|
||||
|
||||
template: types.django_html = """
|
||||
{% load component_tags %}
|
||||
<html>
|
||||
<head>
|
||||
<title>Analytics Example</title>
|
||||
</head>
|
||||
<body class="bg-gray-100 p-8">
|
||||
<div class="max-w-4xl mx-auto bg-white p-6 rounded-lg shadow-md">
|
||||
<h1 class="text-2xl font-bold mb-4">
|
||||
Component Analytics
|
||||
</h1>
|
||||
<p class="text-gray-600 mb-6">
|
||||
Track component errors or success rates to send them
|
||||
to Sentry or other services.
|
||||
</p>
|
||||
|
||||
{# NOTE: Intentionally hidden so we focus on the events tracking #}
|
||||
<div style="display: none;">
|
||||
{% component "template_with_errors" / %}
|
||||
</div>
|
||||
|
||||
{% component "captured_events" / %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
class View:
|
||||
def get(self, request: HttpRequest) -> HttpResponse:
|
||||
# Clear events on each page load
|
||||
analytics_events.clear()
|
||||
error_rate["error"] = 0
|
||||
error_rate["success"] = 0
|
||||
|
||||
return AnalyticsPage.render_to_response(request=request)
|
||||
|
||||
|
||||
@register("template_with_errors")
|
||||
class TemplateWithErrors(Component):
|
||||
template: types.django_html = """
|
||||
<div class="mb-8">
|
||||
<h2 class="text-xl font-semibold mb-2">
|
||||
Sentry Error Tracking
|
||||
</h2>
|
||||
<p class="text-sm text-gray-500 mb-2">
|
||||
This component only logs events when an error occurs.
|
||||
</p>
|
||||
{% component "error_fallback" %}
|
||||
{% component "sentry_error_tracker" %}
|
||||
{% component "api_widget" simulate_error=True / %}
|
||||
{% endcomponent %}
|
||||
{% endcomponent %}
|
||||
{% component "sentry_error_tracker" %}
|
||||
{% component "api_widget" simulate_error=False / %}
|
||||
{% endcomponent %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold mb-2">
|
||||
Success Rate Analytics
|
||||
</h2>
|
||||
<p class="text-sm text-gray-500 mb-2">
|
||||
This component logs both successful and failed renders.
|
||||
</p>
|
||||
{% component "error_fallback" %}
|
||||
{% component "success_rate_tracker" %}
|
||||
{% component "api_widget" simulate_error=True / %}
|
||||
{% endcomponent %}
|
||||
{% endcomponent %}
|
||||
{% component "success_rate_tracker" %}
|
||||
{% component "api_widget" simulate_error=False / %}
|
||||
{% endcomponent %}
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: Since this runs after `template_with_errors`,
|
||||
# the `analytics_events` will be populated.
|
||||
@register("captured_events")
|
||||
class CapturedEvents(Component):
|
||||
def get_template_data(self, args, kwargs, slots, context):
|
||||
return {"events": analytics_events, "error_rate": error_rate}
|
||||
|
||||
template: types.django_html = """
|
||||
<div class="mt-8 p-4 border rounded-lg bg-gray-50">
|
||||
<h3 class="text-lg font-semibold mb-2">
|
||||
Captured Analytics Events
|
||||
</h3>
|
||||
<pre class="text-sm text-gray-700 whitespace-pre-wrap">
|
||||
{% for event in events %}
|
||||
{{ event }}
|
||||
{% endfor %}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="mt-8 p-4 border rounded-lg bg-gray-50">
|
||||
<h3 class="text-lg font-semibold mb-2">
|
||||
Error Rate
|
||||
</h3>
|
||||
<pre class="text-sm text-gray-700 whitespace-pre-wrap">
|
||||
{{ error_rate }}
|
||||
</pre>
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ error_rate.error }} errors out of {{ error_rate.success }} calls.
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
71
0.142.3/examples/analytics/test_example_analytics.py
Normal file
71
0.142.3/examples/analytics/test_example_analytics.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import pytest
|
||||
from django.template import Context, Template
|
||||
|
||||
from django_components import registry, types
|
||||
from django_components.testing import djc_test
|
||||
|
||||
|
||||
# Imported lazily, so we import components only once settings are set
|
||||
def _create_components():
|
||||
from docs.examples.analytics.component import ( # noqa: PLC0415
|
||||
ApiWidget,
|
||||
SentryErrorTracker,
|
||||
SuccessRateTracker,
|
||||
analytics_events,
|
||||
error_rate,
|
||||
)
|
||||
|
||||
registry.register("api_widget", ApiWidget)
|
||||
registry.register("sentry_error_tracker", SentryErrorTracker)
|
||||
registry.register("success_rate_tracker", SuccessRateTracker)
|
||||
analytics_events.clear()
|
||||
error_rate["error"] = 0
|
||||
error_rate["success"] = 0
|
||||
return analytics_events, error_rate
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@djc_test
|
||||
class TestAnalytics:
|
||||
def test_sentry_tracker_logs_only_errors(self):
|
||||
analytics_events, error_rate = _create_components()
|
||||
template_str: types.django_html = """
|
||||
{% load component_tags %}
|
||||
{% component "error_fallback" %}
|
||||
{% component "sentry_error_tracker" %}
|
||||
{% component "api_widget" simulate_error=True / %}
|
||||
{% endcomponent %}
|
||||
{% endcomponent %}
|
||||
{% component "sentry_error_tracker" %}
|
||||
{% component "api_widget" simulate_error=False / %}
|
||||
{% endcomponent %}
|
||||
"""
|
||||
template = Template(template_str)
|
||||
template.render(Context({}))
|
||||
|
||||
assert error_rate["error"] == 0
|
||||
assert error_rate["success"] == 0
|
||||
assert len(analytics_events) == 1
|
||||
assert analytics_events[0]["type"] == "error"
|
||||
assert analytics_events[0]["component"] == "sentry_error_tracker"
|
||||
assert analytics_events[0]["error"] is not None
|
||||
|
||||
def test_success_rate_tracker_logs_all(self):
|
||||
analytics_events, error_rate = _create_components()
|
||||
template_str: types.django_html = """
|
||||
{% load component_tags %}
|
||||
{% component "error_fallback" %}
|
||||
{% component "success_rate_tracker" %}
|
||||
{% component "api_widget" simulate_error=True / %}
|
||||
{% endcomponent %}
|
||||
{% endcomponent %}
|
||||
{% component "success_rate_tracker" %}
|
||||
{% component "api_widget" simulate_error=False / %}
|
||||
{% endcomponent %}
|
||||
"""
|
||||
template = Template(template_str)
|
||||
template.render(Context({}))
|
||||
|
||||
assert len(analytics_events) == 0
|
||||
assert error_rate["error"] == 1
|
||||
assert error_rate["success"] == 1
|
||||
Loading…
Add table
Add a link
Reference in a new issue