plain.observer 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of plain.observer might be problematic. Click here for more details.

plain/observer/views.py CHANGED
@@ -1,23 +1,21 @@
1
- from functools import cached_property
2
-
3
1
  from plain.auth.views import AuthViewMixin
4
2
  from plain.htmx.views import HTMXViewMixin
5
- from plain.http import JsonResponse, Response, ResponseRedirect
3
+ from plain.http import JsonResponse, Response
6
4
  from plain.runtime import settings
7
- from plain.views import TemplateView
5
+ from plain.urls import reverse
6
+ from plain.views import DetailView, ListView
8
7
 
9
8
  from .core import Observer
10
9
  from .models import Trace
11
10
 
12
11
 
13
- class ObserverTracesView(AuthViewMixin, HTMXViewMixin, TemplateView):
12
+ class ObserverTracesView(AuthViewMixin, HTMXViewMixin, ListView):
14
13
  template_name = "observer/traces.html"
14
+ context_object_name = "traces"
15
15
  admin_required = True
16
16
 
17
- @cached_property
18
- def observer(self):
19
- """Get the Observer instance for this request."""
20
- return Observer(self.request)
17
+ def get_objects(self):
18
+ return Trace.objects.all()
21
19
 
22
20
  def check_auth(self):
23
21
  # Allow the view if we're in DEBUG
@@ -34,72 +32,108 @@ class ObserverTracesView(AuthViewMixin, HTMXViewMixin, TemplateView):
34
32
 
35
33
  def get_template_context(self):
36
34
  context = super().get_template_context()
37
- context["observer"] = self.observer
38
- context["traces"] = Trace.objects.all()
39
- if trace_id := self.request.query_params.get("trace_id"):
40
- context["trace"] = Trace.objects.filter(id=trace_id).first()
41
- else:
42
- context["trace"] = context["traces"].first()
35
+ context["observer"] = Observer(self.request)
43
36
  return context
44
37
 
45
- def get(self):
46
- # Check if JSON format is requested
47
- if self.request.query_params.get("format") == "json":
48
- if trace_id := self.request.query_params.get("trace_id"):
49
- if trace := Trace.objects.filter(id=trace_id).first():
50
- return JsonResponse(trace.as_dict())
51
- return JsonResponse({"error": "Trace not found"}, status=404)
52
-
53
- return super().get()
38
+ def htmx_put_mode(self):
39
+ """Set observer mode via HTMX PUT."""
40
+ mode = self.request.data.get("mode")
41
+ observer = Observer(self.request)
54
42
 
55
- def htmx_post_enable_summary(self):
56
- """Enable summary mode via HTMX."""
57
43
  response = Response(status_code=204)
58
44
  response.headers["HX-Refresh"] = "true"
59
- self.observer.enable_summary_mode(response)
60
- return response
61
45
 
62
- def htmx_post_enable_persist(self):
63
- """Enable full persist mode via HTMX."""
64
- response = Response(status_code=204)
65
- response.headers["HX-Refresh"] = "true"
66
- self.observer.enable_persist_mode(response)
67
- return response
46
+ if mode == "summary":
47
+ observer.enable_summary_mode(response)
48
+ elif mode == "persist":
49
+ observer.enable_persist_mode(response)
50
+ elif mode == "disable":
51
+ observer.disable(response)
52
+ else:
53
+ return Response("Invalid mode", status_code=400)
68
54
 
69
- def htmx_post_disable(self):
70
- """Disable observer via HTMX."""
71
- response = Response(status_code=204)
72
- response.headers["HX-Refresh"] = "true"
73
- self.observer.disable(response)
74
55
  return response
75
56
 
76
57
  def htmx_delete_traces(self):
77
58
  """Clear all traces via HTMX DELETE."""
78
- Trace.objects.all().delete()
59
+ Trace.objects.filter(share_id="").delete()
79
60
  response = Response(status_code=204)
80
61
  response.headers["HX-Refresh"] = "true"
81
62
  return response
82
63
 
83
- def htmx_delete_trace(self):
84
- """Delete a specific trace via HTMX DELETE."""
85
- trace_id = self.request.query_params.get("trace_id")
86
- Trace.objects.get(id=trace_id).delete()
64
+
65
+ class ObserverTraceDetailView(AuthViewMixin, HTMXViewMixin, DetailView):
66
+ """Detail view for a specific trace."""
67
+
68
+ template_name = "observer/trace_detail.html"
69
+ context_object_name = "trace"
70
+ admin_required = True
71
+
72
+ def get_object(self):
73
+ return Trace.objects.get_or_none(trace_id=self.url_kwargs.get("trace_id"))
74
+
75
+ def check_auth(self):
76
+ # Allow the view if we're in DEBUG
77
+ if settings.DEBUG:
78
+ return
79
+ super().check_auth()
80
+
81
+ def get(self):
82
+ """Return trace data as HTML or JSON based on content negotiation."""
83
+ if (
84
+ "application/json" in self.request.headers.get("Accept", "")
85
+ or self.request.query_params.get("format") == "json"
86
+ ):
87
+ return self.get_object().as_dict()
88
+
89
+ return super().get()
90
+
91
+ def get_template_names(self):
92
+ if self.is_htmx_request():
93
+ # Use a different template for HTMX requests
94
+ return ["observer/trace.html"]
95
+ return super().get_template_names()
96
+
97
+ def htmx_delete(self):
98
+ trace = self.get_object()
99
+ trace.delete()
100
+
101
+ # Redirect to traces list after deletion
87
102
  response = Response(status_code=204)
88
- response.headers["HX-Refresh"] = "true"
103
+ response.headers["HX-Redirect"] = reverse("observer:traces")
89
104
  return response
90
105
 
91
- def post(self):
92
- """A standard, non-htmx post used by the button html (where htmx may not be available)."""
106
+ def htmx_post_share(self):
107
+ trace = self.get_object()
108
+ trace.generate_share_id()
109
+ return super().get()
93
110
 
94
- observe_action = self.request.data["observe_action"]
111
+ def htmx_delete_share(self):
112
+ trace = self.get_object()
113
+ trace.remove_share_id()
114
+ return super().get()
95
115
 
96
- response = ResponseRedirect(self.request.data.get("redirect_url", "."))
97
116
 
98
- if observe_action == "summary":
99
- self.observer.enable_summary_mode(response) # Default to summary mode
100
- elif observe_action == "persist":
101
- self.observer.enable_persist_mode(response)
102
- elif observe_action == "disable":
103
- self.observer.disable(response)
117
+ class ObserverTraceSharedView(DetailView):
118
+ """Public view for shared trace data."""
104
119
 
105
- return response
120
+ template_name = "observer/trace_share.html"
121
+ context_object_name = "trace"
122
+
123
+ def get_object(self):
124
+ return Trace.objects.get_or_none(share_id=self.url_kwargs["share_id"])
125
+
126
+ def get_template_context(self):
127
+ context = super().get_template_context()
128
+ context["is_share_view"] = True
129
+ return context
130
+
131
+ def get(self):
132
+ """Return trace data as HTML or JSON based on content negotiation."""
133
+ if (
134
+ "application/json" in self.request.headers.get("Accept", "")
135
+ or self.request.query_params.get("format") == "json"
136
+ ):
137
+ return JsonResponse(self.get_object().as_dict())
138
+
139
+ return super().get()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.observer
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: On-page telemetry and observability tools for Plain.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-Expression: BSD-3-Clause
@@ -0,0 +1,25 @@
1
+ plain/observer/CHANGELOG.md,sha256=hpdLGk-BRxA-2gHzygAp0XrFvvM43IhJg8TT4AjWoIo,2055
2
+ plain/observer/README.md,sha256=5wM48-iE8i7xOjIK8KCgZ-Vmp2xpDtX73UnE5QeNnd4,31
3
+ plain/observer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ plain/observer/admin.py,sha256=sFg5YUAnw-zZJv3_xnMRtI9hFOLI6w77GEV4zhALhQo,2537
5
+ plain/observer/cli.py,sha256=-huHPj4xkrq4xemDo8XzoNtmE53g0YWuVLW66Gr1d88,20935
6
+ plain/observer/config.py,sha256=FuJi1jiDSvOTcmP-6Ea4OlGZt5cRf4iTp1e0dgpJ45E,1494
7
+ plain/observer/core.py,sha256=D9vX0GP8JBB8-NFAKrOwPSHl_wdZo1h0A5C6xKsJVjA,2245
8
+ plain/observer/default_settings.py,sha256=JN2jT2wfa6f80EqU0p4Ox_47xyxL-Ym5-_pftY7xj2U,197
9
+ plain/observer/models.py,sha256=uVmytQHCYilMfULGJHk63l48APOHqEcbcRtYoE7L_RU,13072
10
+ plain/observer/otel.py,sha256=nr4BYQb6rWF7uXsOVmBWV-8z5jLTPbDnYi6VSdVvUnE,14585
11
+ plain/observer/urls.py,sha256=oLJoDjB7YMUx8z-MGql_xXSXkfacVKFp-aHNXaKzs38,376
12
+ plain/observer/views.py,sha256=9TRvjfBk62nxlfZXXk-LsMXqnCxL_FIrQH4eUFIUN9A,4226
13
+ plain/observer/migrations/0001_initial.py,sha256=I-4DNr_WK2Gx428Ql3pG3-W8C0xvk0FVTZnd5swIAQ4,3376
14
+ plain/observer/migrations/0002_trace_share_created_at_trace_share_id_trace_summary_and_more.py,sha256=lgFqdn66zq7AoCvkC3MIvLXiE_Omup5EEMDSe1jpKOg,1765
15
+ plain/observer/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ plain/observer/templates/observer/trace.html,sha256=42yuvqAH7poRMFbueXT-MeSIClmUaLSHohG9LF0sepk,27098
17
+ plain/observer/templates/observer/trace_detail.html,sha256=86-YGCpg9gy31Pd2vDHB3LYRkJile-DsGD1Enjx9s5Y,943
18
+ plain/observer/templates/observer/trace_share.html,sha256=HrYLti5BpX96-6Bm_37OObFvAJSYbZ3GZD-MwCi9hgA,525
19
+ plain/observer/templates/observer/traces.html,sha256=cFnlIuCf6XJEpHRD2_yfVmPDGZfiqMq6Cg-iMlT3CWY,22184
20
+ plain/observer/templates/toolbar/observer.html,sha256=uaDKiWR7EYqC1kEXE-uHDlE7nfFEMR_zmOgvlKwQHJ4,1365
21
+ plain/observer/templates/toolbar/observer_button.html,sha256=xsHJSuOjW6ddnxlPlPKek22WrWnuVYGIcBfFdkb76pk,1199
22
+ plain_observer-0.2.0.dist-info/METADATA,sha256=8ZtRPghSC480Xb44R7nWlM3KWAfwWUH1vbt3v1CTWrg,429
23
+ plain_observer-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
+ plain_observer-0.2.0.dist-info/licenses/LICENSE,sha256=YZdq6Pz8ivjs97eSVLRmoGDI1hjEikX6N49DfM0DWio,1500
25
+ plain_observer-0.2.0.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- {% extends "admin/detail.html" %}
2
-
3
- {% block content %}
4
-
5
- {{ super() }}
6
-
7
- <div class="mt-20">
8
- {% include "observer/_trace_detail.html" %}
9
- </div>
10
- {% endblock %}
@@ -1,23 +0,0 @@
1
- plain/observer/CHANGELOG.md,sha256=W6argwh8IJ2-RswC9yw96AtyVwrGk93-hCpnu1IW_Ao,972
2
- plain/observer/README.md,sha256=5wM48-iE8i7xOjIK8KCgZ-Vmp2xpDtX73UnE5QeNnd4,31
3
- plain/observer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- plain/observer/admin.py,sha256=d5ekU48GiiQ70K8ulSd0v_7P1v12U8rIQ8LbiNgKv0Y,2874
5
- plain/observer/cli.py,sha256=JBJzOYl3V973WQbtj8AEde6zxfWdEZx-u3g7c15-4lU,544
6
- plain/observer/config.py,sha256=FuJi1jiDSvOTcmP-6Ea4OlGZt5cRf4iTp1e0dgpJ45E,1494
7
- plain/observer/core.py,sha256=D9vX0GP8JBB8-NFAKrOwPSHl_wdZo1h0A5C6xKsJVjA,2245
8
- plain/observer/default_settings.py,sha256=JN2jT2wfa6f80EqU0p4Ox_47xyxL-Ym5-_pftY7xj2U,197
9
- plain/observer/models.py,sha256=cD72rht7Bb-8YARYvylBc9W0garebWgFsH_vfx1ubT8,11999
10
- plain/observer/otel.py,sha256=8hqSd_l_OIo9Ip4Vx6FNXOzGhCv7vlgdemZEnCR2IOg,14181
11
- plain/observer/urls.py,sha256=LcsKBWRqt8gs385tV9z-j6kSewzWsOWftadi59QqIIE,194
12
- plain/observer/views.py,sha256=TrwatLFf9M67ax4EhF_P1Q3X_o3hzsAEr4Po48peiQM,3673
13
- plain/observer/migrations/0001_initial.py,sha256=I-4DNr_WK2Gx428Ql3pG3-W8C0xvk0FVTZnd5swIAQ4,3376
14
- plain/observer/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- plain/observer/templates/admin/observer/trace_detail.html,sha256=qW03sNNKGivPVQMI8rFtSCXGTOH_qw_nmXhpIZIu4zo,161
16
- plain/observer/templates/observer/_trace_detail.html,sha256=q98IdA28m7vlel2ND090MoFE5Kmw8_yLExJd57-MUus,21631
17
- plain/observer/templates/observer/traces.html,sha256=dJPp2pcFDJOLmHihH5-qnVAgAJEYGCBy6Fn1OreaWjw,20700
18
- plain/observer/templates/toolbar/observer.html,sha256=uaDKiWR7EYqC1kEXE-uHDlE7nfFEMR_zmOgvlKwQHJ4,1365
19
- plain/observer/templates/toolbar/observer_button.html,sha256=BXzka5LyvhQPBLFBY_QSNQOfdFtbIN3SUF3ZjSVGSjw,2565
20
- plain_observer-0.1.0.dist-info/METADATA,sha256=5ajnIee8v9s4MWHBXisSbWB-va_1zTiOf8DfmN_Rras,429
21
- plain_observer-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
- plain_observer-0.1.0.dist-info/licenses/LICENSE,sha256=YZdq6Pz8ivjs97eSVLRmoGDI1hjEikX6N49DfM0DWio,1500
23
- plain_observer-0.1.0.dist-info/RECORD,,