Skip to content
Snippets Groups Projects

Draft: Experimental: Use Django tags to create UI components

Closed Jayesh requested to merge jayeshv/swh-web:exp-tags into master
Files
9
@@ -166,3 +166,219 @@ def static_path_exists(path: str) -> bool:
Whether the path exists.
"""
return bool(find(path))
# Experimental code
import logging # noqa: E402
import urllib.parse # noqa: E402
from gql import Client, gql # noqa: E402
from gql.transport.aiohttp import AIOHTTPTransport # noqa: E402
from gql.transport.aiohttp import log as requests_logger # noqa: E402
from gql.transport.exceptions import TransportQueryError # noqa: E402
transport = AIOHTTPTransport(url="https://archive.softwareheritage.org/graphql/")
client = Client(transport=transport, fetch_schema_from_transport=True)
requests_logger.setLevel(logging.WARNING) # logs are too verbose otherwise
@register.filter
def graphql_key_value(data, key):
# read the data using a dynamic key from a graphql response (nested dict)
# key is a string with '.' used for nesting
for each_key in key.split("."):
# TODO handle keyerror here
data = data[each_key]
return data
@register.simple_tag
def next_page_url(original, cursor_name, cursor_val):
# FIXME, find a simpler/better way to do this in templates itself
# merge dicts, old cursor will be updated
return urllib.parse.urlencode({**original.dict(), cursor_name: cursor_val})
def single_item_response(
node_path, query=None, data=None, query_args={}, extra_template_args={}
):
if not data and not query:
raise AttributeError("Provide either data or a query to fetch data")
errors = None
if data: # preference is for data
# data is used to support multiple item widgets with a single query
# TODO, validate data add add errors, if any
pass
else:
# execute the query to fetch data
try:
data = client.execute(query, variable_values=query_args)
except TransportQueryError as e:
errors = [e]
return {
"data": data,
"errors": errors,
"node_path": node_path, # Path to read the node object from data
"extra_template_args": extra_template_args, # Any extra vars needed in the template
}
def paginated_response(
context,
edges_path,
page_info_path,
cursor_name,
first=10,
query=None,
data=None,
identifier=None,
query_args={},
extra_template_args={},
):
if not data and not query:
raise AttributeError("Provide either data or a query to fetch data")
errors = None
cursor_name = cursor_name or "next_page_cursor"
request = context["request"]
after = request.GET.get(cursor_name)
if data:
# data is used to support multiple paginated widgets with a single query
# TODO, validate data add add errors, if any
pass
try:
data = client.execute(
query, variable_values={"first": first, "after": after, **query_args}
)
except TransportQueryError as e:
errors = [e]
# cursor_name is included to support multiple paginated widgets in a single page
# make cursor_name unique to support multiple paginated widgets of the same
# type in a single page
return {
"data": data,
"errors": errors,
"edges_path": edges_path, # Path to read edges from data
"page_info_path": page_info_path, # Path to read the pageInfo from data
"cursor_name": cursor_name, # To construct the next URL
"current_params": request.GET, # To construct the next URL
"identifier": identifier, # To support page fragments in the next URL
"extra_template_args": extra_template_args, # Any extra vars needed in the template
}
@register.inclusion_tag("widgets/revision.html", takes_context=True)
def revision_widget(context, swhid):
query = gql(
"""
query getRevision($swhid: SWHID!) {
revision(swhid: $swhid) {
swhid
type
date {
date
}
directory {
swhid
}
message {
text
}
author {
name {
text
}
}
}
}
"""
)
return single_item_response(
node_path="revision", query=query, query_args={"swhid": swhid}
)
@register.inclusion_tag("widgets/directory.html", takes_context=True)
def dir_widget(context, swhid, cursor_name, first=5, identifier=None):
query = gql(
"""
query getDirectory($swhid: SWHID!, $first: Int, $after: String) {
directory(swhid: $swhid) {
swhid
entries(first: $first, after: $after) {
totalCount
edges {
node {
name {
text
}
target {
swhid
type
}
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
"""
)
return paginated_response(
context=context,
query=query,
edges_path="directory.entries.edges",
page_info_path="directory.entries.pageInfo",
cursor_name=cursor_name,
first=first,
identifier=identifier,
query_args={
"swhid": swhid,
},
)
@register.inclusion_tag("widgets/search.html", takes_context=True)
def search_widget(context, search_term, cursor_name, first=5, identifier=None):
query = gql(
"""
query getOrigins($query: String!, $first: Int!, $after: String) {
originSearch(query: $query, first: $first, after: $after) {
edges {
node {
url
node {
latestVisit {
date
type
}
}
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
"""
)
return paginated_response(
context=context,
query=query,
edges_path="originSearch.edges",
page_info_path="originSearch.pageInfo",
cursor_name=cursor_name,
first=first,
identifier=identifier,
query_args={
"query": search_term,
},
extra_template_args={
"search_term": search_term,
},
)
Loading