Skip to content

Commit

Permalink
[#4] Custom sidebar and statistic
Browse files Browse the repository at this point in the history
  • Loading branch information
dedenbangkit committed Nov 12, 2024
1 parent bdd857c commit acdbca2
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/ckanext-agra-theme/ckanext/agra_theme/plugin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,58 @@
from os import environ
from werkzeug.wrappers import Response, Request
from flask import Blueprint, render_template, abort
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit
import logging

file_size_blueprint = Blueprint("file_size", __name__)


@file_size_blueprint.route("/dataset/<dataset_id>/file_size")
def file_size(dataset_id):
# Set up the context for accessing CKAN actions
context = {"user": toolkit.g.user}

try:
# Retrieve the dataset and its resources using CKAN actions
dataset = toolkit.get_action("package_show")(
context, {"id": dataset_id}
)
resources = dataset["resources"]
except toolkit.ObjectNotFound:
abort(404, description="Dataset not found")

# Prepare a list to store resource file sizes
resource_sizes = []
for resource in resources:
size = resource.get("size")

# If the size is None, try to retrieve it from the URL
if not size:
url = resource.get("url")
try:
response = requests.head(url, allow_redirects=True)
size = response.headers.get("Content-Length")
except requests.RequestException:
size = None

# Append to list with resource name and size
resource_sizes.append(
{"name": resource.get("name"), "size": size if size else "Unknown"}
)

# Render a template with the resource size data
return toolkit.render("file_size.html", {"resource_sizes": resource_sizes})


class AgraThemePlugin(plugins.SingletonPlugin):
plugins.implements(plugins.IConfigurer)
plugins.implements(plugins.IMiddleware, inherit=True)
plugins.implements(plugins.IBlueprint)
plugins.implements(plugins.IRoutes, inherit=True)

def get_blueprint(self):
return file_size_blueprint

def make_middleware(self, app, config):
# Wrap the CKAN app with our custom middleware
Expand Down
25 changes: 25 additions & 0 deletions src/ckanext-agra-theme/ckanext/agra_theme/public/base/css/agra.css
Original file line number Diff line number Diff line change
Expand Up @@ -10258,6 +10258,7 @@ h4 small {
border-radius: 4px;
}
.masthead {
z-index: 7;
margin-bottom: initial;
padding: 5px;
color: #fff;
Expand Down Expand Up @@ -11264,3 +11265,27 @@ iframe {
margin-top: -3px;
margin-right: 8px;
}

.facet-category {
border-bottom: 1px solid #f2f2f2;
}
.facet-category .facet-title,
.facet-category .facet-items {
padding: 5px 10px;
}
.facet-category .group-hierarchy label,
.facet-category .facet-items label {
display: block;
font-weight: normal;
}
.facet-category .group-hierarchy label::after,
.facet-category .facet-items label::after {
content: "";
}
.facet-category .facet-title {
background: #f6f6f6;
}
.facet-category .group-hierarchy {
list-style: none;
padding: 5px 10px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const checkboxes = document.querySelectorAll('.filters input[type="checkbox"]');

function get_query() {
var url = window.location.search;
var query = url.substr(1);
if (query === "") {
return {};
}
var result = {};

query.split("&").forEach(function (part) {
var item = part.split("=");
var key = item[0];
var value = item[1];
if (result[key]) {
result[key].push(value);
} else {
result[key] = [value];
}
});

return result;
}

// Loop through each checkbox and add an event listener
checkboxes.forEach((checkbox) => {
checkbox.addEventListener("change", (event) => {
var queryList = get_query();
const name = event.target.name;
const value = event.target.value;

if (event.target.checked) {
// Add the value to the query list for the checked key
if (queryList[name]) {
queryList[name].push(value);
} else {
queryList[name] = [value];
}
} else {
// Remove the unchecked value from the query list
queryList[name] = queryList[name].filter((v) => v !== value);
if (queryList[name].length === 0) {
delete queryList[name];
}
}

// Create a new URL by flattening the array for each key
var newUrl =
"?" +
Object.entries(queryList)
.flatMap(([key, values]) => values.map((val) => `${key}=${val}`))
.join("&");

// Push the new URL to the history
window.history.pushState({}, "", newUrl);
// Reload the page
window.location.reload();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,6 @@
{# make sure there are no calls to `asset` tag after this point #}
{{ h.render_assets('style') }}
{{ h.render_assets('script') }}
<script src="/base/javascript/filters.js" type="text/javascript"></script>
</body>
</html>
14 changes: 14 additions & 0 deletions src/ckanext-agra-theme/ckanext/agra_theme/templates/file_size.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<h1>File Sizes for Resources in Dataset</h1>

<table>
<tr>
<th>Resource Name</th>
<th>File Size (bytes)</th>
</tr>
{% for resource in resource_sizes %}
<tr>
<td>{{ resource.name }}</td>
<td>{{ resource.size }}</td>
</tr>
{% endfor %}
</table>
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
{% block search %} {% snippet 'home/snippets/search.html',
search_facets=search_facets %} {% endblock %}
</div>
<div class="col-md-12">
{% block stats %} {% snippet 'home/snippets/stats.html' %} {%
endblock %}
</div>
{% endif %}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{% extends "page.html" %}
{% import 'macros/form.html' as form %}

{% block subtitle %}{{ _(dataset_type.title()) }}{% endblock %}

{% block breadcrumb_content %}
<li class="active">{{ h.nav_link(_(dataset_type.title() + 's'), named_route='%s.search' % dataset_type, highlight_actions = 'new index') }}</li>
{% endblock %}

{% block primary_content %}
<section class="module">
<div class="module-content">
{% block page_primary_action %}
{% if h.check_access('package_create') %}
<div class="page_primary_action">
{{ h.snippet ('snippets/add_dataset.html', dataset_type=dataset_type) }}
</div>
{% endif %}
{% endblock %}
{% block form %}
{% set facets = {
'fields': fields_grouped,
'search': search_facets,
'titles': facet_titles,
'translated_fields': translated_fields,
'remove_field': remove_field }
%}
{% set sorting = [
(_('Relevance'), 'score desc, metadata_modified desc'),
(_('Name Ascending'), 'title_string asc'),
(_('Name Descending'), 'title_string desc'),
(_('Last Modified'), 'metadata_modified desc'),
(_('Popular'), 'views_recent desc') if g.tracking_enabled else (false, false) ]
%}
{% snippet 'snippets/search_form.html', form_id='dataset-search-form', type=dataset_type, query=q, sorting=sorting, sorting_selected=sort_by_selected, count=page.item_count, placeholder=_('Search ' + dataset_type + 's') + '...', facets=facets, show_empty=request.params, error=query_error, fields=fields %}
{% endblock %}
{% block package_search_results_list %}
{{ h.snippet('snippets/package_list.html', packages=page.items) }}
{% endblock %}
</div>

{% block page_pagination %}
{{ page.pager(q=q) }}
{% endblock %}
</section>

{% block package_search_results_api %}
<section class="module">
<div class="module-content">
{% block package_search_results_api_inner %}
<small>
{% set api_link = h.link_to(_('API'), h.url_for(controller='api', action='get_api', ver=3)) %}
{% set api_doc_link = h.link_to(_('API Docs'), 'http://docs.ckan.org/en/{0}/api/'.format(g.ckan_doc_version)) %}
{% if g.dumps_url -%}
{% set dump_link = h.link_to(_('full {format} dump').format(format=g.dumps_format), g.dumps_url) %}
{% trans %}
You can also access this registry using the {{ api_link }} (see {{ api_doc_link }}) or download a {{ dump_link }}.
{% endtrans %}
{% else %}
{% trans %}
You can also access this registry using the {{ api_link }} (see {{ api_doc_link}}).
{% endtrans %}
{%- endif %}
</small>
{% endblock %}
</div>
</section>
{% endblock %}
{% endblock %}


{% block secondary_content %}
<div class="filters">
<div>
{% for facet, title in facet_titles.items() %}
<div class="facet-category">
<div class="facet-title">{{ title }}</div>
<div class="facet-items">
{% for item in search_facets[facet]['items'] %}
<label>
<input type="checkbox" name="{{ facet }}" value="{{ item['name'] }}" {% if item['active'] %}checked{% endif %}>
{{ item['display_name'] }} [{{ item['count'] }}]
</label>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<!-- Example for Hierarchical Groups -->
{% if search_facets.get('groups') %}
<div class="facet-category">
<div class="facet-title">{{ facet_titles.get('groups', 'Groups') }}</div>
<ul class="group-hierarchy">
{% for group in search_facets['groups']['items'] %}
<li>
<label>
<input type="checkbox" name="groups" value="{{ group['id'] }}" {% if group['active'] %}checked{% endif %}>
{{ group['display_name'] }}
</label>
{% if group.get('children') %}
<ul>
{% for child in group['children'] %}
<li>
<label>
<input type="checkbox" name="groups" value="{{ child['id'] }}" {% if child['active'] %}checked{% endif %}>
{{ child['display_name'] }}
</label>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
<a class="close no-text hide-filters"><i class="fa fa-times-circle"></i><span class="text">close</span></a>
</div>
{% endblock %}

{% block t_content %}
<div class="filters">
<div>
{% for facet in facet_titles %}
{{ h.snippet('snippets/facet_list.html', title=facet_titles[facet], name=facet, search_facets=search_facets) }}
{% endfor %}
</div>
<a class="close no-text hide-filters"><i class="fa fa-times-circle"></i><span class="text">close</span></a>
</div>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<div class="box stats">
<div class="inner">
<ul>
{% block stats_group %}
<li>
<a href="{{ h.url_for('dataset.search') }}">
<strong>{{ h.SI_number_span(stats.dataset_count) }}</strong>
{{ _('dataset') if stats.dataset_count == 1 else _('datasets') }}
</a>
</li>
<li>
<a href="{{ h.url_for(controller='organization', action='index') }}">
<strong>{{ h.SI_number_span(stats.organization_count) }}</strong>
{{ _('organization') if stats.organization_count == 1 else
_('organizations') }}
</a>
</li>
<li>
<a href="{{ h.url_for(controller='group', action='index') }}">
<strong>{{ h.SI_number_span(stats.group_count) }}</strong>
{{ _('group') if stats.group_count == 1 else _('groups') }}
</a>
</li>
{% endblock %}
</ul>
</div>
</div>

0 comments on commit acdbca2

Please sign in to comment.