Add plugin platform with modular backend and frontend registry.
Split graph/import/meta into Django apps, add API v1 with OpenAPI and pytest, and introduce plugin registry with the tags reference plugin on both FE and BE. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class GraphConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'graph'
|
||||
@@ -0,0 +1,66 @@
|
||||
from contacts.models import Contact, Relation, NetworkMap, NetworkMapMembership
|
||||
|
||||
|
||||
def node_from_contact(contact):
|
||||
return {
|
||||
'id': contact.id,
|
||||
'label': contact.name,
|
||||
'title': '\n'.join(filter(None, [contact.organization, contact.position, contact.email])),
|
||||
'group': contact.organization or 'default',
|
||||
}
|
||||
|
||||
|
||||
def node_from_membership(membership):
|
||||
contact = membership.contact
|
||||
return {
|
||||
**node_from_contact(contact),
|
||||
'life_sphere': membership.life_sphere,
|
||||
'network_circle': membership.network_circle,
|
||||
'importance': membership.importance,
|
||||
'map_angle': membership.map_angle,
|
||||
'map_radius_ratio': membership.map_radius_ratio,
|
||||
'membership_id': membership.id,
|
||||
}
|
||||
|
||||
|
||||
def edge_from_relation(relation):
|
||||
return {
|
||||
'id': relation.id,
|
||||
'from': relation.source_id,
|
||||
'to': relation.target_id,
|
||||
'label': relation.get_relation_type_display(),
|
||||
'title': relation.description or relation.get_relation_type_display(),
|
||||
'relation_type': relation.relation_type,
|
||||
'interaction_intensity': relation.interaction_intensity,
|
||||
}
|
||||
|
||||
|
||||
def build_full_graph():
|
||||
contacts = Contact.objects.all()
|
||||
nodes = [node_from_contact(c) for c in contacts]
|
||||
relations = Relation.objects.select_related('source', 'target').all()
|
||||
edges = [edge_from_relation(r) for r in relations]
|
||||
return {'nodes': nodes, 'edges': edges}
|
||||
|
||||
|
||||
def build_network_map_graph(map_id=None):
|
||||
if not map_id:
|
||||
default_map = NetworkMap.objects.order_by('id').first()
|
||||
if not default_map:
|
||||
return {'nodes': [], 'edges': []}
|
||||
map_id = default_map.id
|
||||
|
||||
memberships = list(
|
||||
NetworkMapMembership.objects.filter(map_id=map_id)
|
||||
.select_related('contact')
|
||||
.order_by('contact__name')
|
||||
)
|
||||
allowed_ids = {m.contact_id for m in memberships}
|
||||
nodes = [node_from_membership(m) for m in memberships]
|
||||
relations = Relation.objects.select_related('source', 'target').all()
|
||||
edges = [
|
||||
edge_from_relation(r)
|
||||
for r in relations
|
||||
if r.source_id in allowed_ids and r.target_id in allowed_ids
|
||||
]
|
||||
return {'nodes': nodes, 'edges': edges}
|
||||
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('graph/', views.graph_data, name='graph-data'),
|
||||
path('network-map-graph/', views.network_map_graph, name='network-map-graph'),
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
from rest_framework.decorators import api_view
|
||||
from rest_framework.response import Response
|
||||
|
||||
from .services import build_full_graph, build_network_map_graph
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
def graph_data(request):
|
||||
return Response(build_full_graph())
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
def network_map_graph(request):
|
||||
map_id = request.query_params.get('map_id')
|
||||
return Response(build_network_map_graph(map_id))
|
||||
Reference in New Issue
Block a user