Skip to content

Commit

Permalink
Merge pull request #224 from JVickery-TBS/feature/badges
Browse files Browse the repository at this point in the history
Frontend Status Badges
  • Loading branch information
duttonw authored Oct 25, 2024
2 parents 21fa4d4 + 80999e4 commit cf437f1
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 0 deletions.
14 changes: 14 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,20 @@ expect European (day-first) dates, you could add to ``postgresql.conf``:

datestyle=ISO,DMY

External Database credentials for datastore

``ckanext.xloader.jobs_db.uri = postgresql://ckan_default:pass@localhost/ckan_default``

API Key requires for xloader interaction CKAN 2.10 onwards, to generate ``TOKEN=ckan -c /etc/ckan/default/production.ini user token add $ACCOUNT xloader | tail -1 | tr -d '[:space:]')``

``ckanext.xloader.api_token = <your-CKAN-generated-API-Token>``

Badge notification on what xloader is doing

``ckanext.xloader.show_badges = True|False (default True)``

``ckanext.xloader.debug_badges = True|False (default False)``

------------------------
Developer installation
------------------------
Expand Down
16 changes: 16 additions & 0 deletions ckanext/xloader/config_declaration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,21 @@ groups:
that is not in ckanext.xloader.formats after a Resource is updated.
type: bool
required: false
- key: ckanext.xloader.show_badges
default: True
example: False
description: |
Controls whether or not the status badges display in the front end.
type: bool
required: false
- key: ckanext.xloader.debug_badges
default: False
example: True
description: |
Controls whether or not the status badges display all of the statuses. By default,
the badges will display "pending", "running", and "error". With debug_badges enabled,
they will also display "complete", "active", "inactive", and "unknown".
type: bool
required: false


103 changes: 103 additions & 0 deletions ckanext/xloader/helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import ckan.plugins.toolkit as toolkit
from ckanext.xloader.utils import XLoaderFormats
from markupsafe import Markup
from html import escape as html_escape


def xloader_status(resource_id):
Expand Down Expand Up @@ -42,3 +44,104 @@ def is_resource_supported_by_xloader(res_dict, check_access=True):
else:
is_supported_url_type = True
return (is_supported_format or is_datastore_active) and user_has_access and is_supported_url_type


def xloader_badge(resource):
# type: (dict) -> str
"""
Displays a custom badge for the status of Xloader and DataStore for the specified resource.
"""
if not toolkit.asbool(toolkit.config.get('ckanext.xloader.show_badges', True)):
return ''

if not XLoaderFormats.is_it_an_xloader_format(resource.get('format')):
# we only want to show badges for supported xloader formats
return ''

is_datastore_active = resource.get('datastore_active', False)

try:
xloader_job = toolkit.get_action("xloader_status")({'ignore_auth': True},
{"resource_id": resource.get('id')})
except toolkit.ObjectNotFound:
xloader_job = {}

if xloader_job.get('status') == 'complete':
# the xloader task is complete, show datastore active or inactive.
# xloader will delete the datastore table at the beggining of the job run.
# so this will only be true if the job is fully finished.
status = 'active' if is_datastore_active else 'inactive'
elif xloader_job.get('status') in ['submitting', 'pending', 'running', 'running_but_viewable', 'error']:
# the job is running or pending or errored
# show the xloader status
status = xloader_job.get('status')
if status == 'running_but_viewable':
# treat running_but_viewable the same as running
status = 'running'
elif status == 'submitting':
# treat submitting the same as pending
status = 'pending'
else:
# we do not know what the status is
status = 'unknown'

status_translations = {
# Default messages
'pending': toolkit._('Pending'),
'running': toolkit._('Running'),
'error': toolkit._('Error'),
# Debug messages
'complete': toolkit._('Complete'),
'active': toolkit._('Active'),
'inactive': toolkit._('Inactive'),
'unknown': toolkit._('Unknown'),
}

status_descriptions = {
# Default messages
'pending': toolkit._('Data awaiting load to DataStore'),
'running': toolkit._('Loading data into DataStore'),
'error': toolkit._('Failed to load data into DataStore'),
# Debug messages
'complete': toolkit._('Data loaded into DataStore'),
'active': toolkit._('Data available in DataStore'),
'inactive': toolkit._('Resource not active in DataStore'),
'unknown': toolkit._('DataStore status unknown'),
}
basic_statuses = ['pending', 'running', 'error']

if status not in basic_statuses and not toolkit.asbool(toolkit.config.get('ckanext.xloader.debug_badges', False)):
return ''

last_updated = toolkit.h.render_datetime(xloader_job.get('last_updated'), with_hours=True) \
if xloader_job.get('last_updated') else toolkit._('Last Updated Not Available')

try:
toolkit.check_access('resource_update', {'user': toolkit.g.user}, {'id': resource.get('id')})
pusher_url = toolkit.h.url_for('xloader.resource_data',
id=resource.get('package_id'),
resource_id=resource.get('id'))

return Markup(u'''
<a href="{pusher_url}" class="loader-badge" title="{title}: {status_description}" >
<span class="prefix">{prefix}</span>
<span class="status {status}">{status_display}</span>
</a>'''.format(
pusher_url=pusher_url,
prefix=toolkit._('datastore'),
status=status,
status_display=html_escape(status_translations[status], quote=True),
status_description=html_escape(status_descriptions[status], quote=True),
title=html_escape(last_updated, quote=True)))
except toolkit.NotAuthorized:
return Markup(u'''
<span class="loader-badge" title="{title}: {status_description}">
<span class="prefix">{prefix}</span>
<span class="status {status}">{status_display}</span>
</span>
'''.format(
prefix=toolkit._('datastore'),
status=status,
status_display=html_escape(status_translations[status], quote=True),
status_description=html_escape(status_descriptions[status], quote=True),
title=html_escape(last_updated, quote=True)))
2 changes: 2 additions & 0 deletions ckanext/xloader/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def get_blueprint(self):

def update_config(self, config):
toolkit.add_template_directory(config, 'templates')
toolkit.add_resource(u'webassets', 'ckanext-xloader')

# IConfigurable

Expand Down Expand Up @@ -206,6 +207,7 @@ def get_helpers(self):
"xloader_status": xloader_helpers.xloader_status,
"xloader_status_description": xloader_helpers.xloader_status_description,
"is_resource_supported_by_xloader": xloader_helpers.is_resource_supported_by_xloader,
"xloader_badge": xloader_helpers.xloader_badge,
}


Expand Down
12 changes: 12 additions & 0 deletions ckanext/xloader/templates/package/resource_read.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
{% ckan_extends %}


{% block resource_read_url %}
{% set badge = h.xloader_badge(res) %}
{% if badge %}
{{ badge }}<br/><br/>
{% asset 'ckanext-xloader/main-css' %}
{% endif %}
{{ super() }}
{% endblock %}

{% block action_manage_inner %}
{{ super() }}
{% if h.is_resource_supported_by_xloader(res) %}
Expand All @@ -13,3 +23,5 @@
{% endif %}
{{ super() }}
{% endblock %}


7 changes: 7 additions & 0 deletions ckanext/xloader/templates/package/snippets/resource_info.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% ckan_extends %}

{% block resource_info %}
{{ super() }}
{{ h.xloader_badge(res) }}
{% asset 'ckanext-xloader/main-css' %}
{% endblock %}
8 changes: 8 additions & 0 deletions ckanext/xloader/templates/package/snippets/resource_item.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,11 @@
{% endif %}
{{ super() }}
{% endblock %}

{% block resource_item_title %}
{{ super() }}
{{ h.xloader_badge(res) }}
{% asset 'ckanext-xloader/main-css' %}
{% endblock %}


60 changes: 60 additions & 0 deletions ckanext/xloader/webassets/css/xloader.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
.loader-badge {
margin-left: 10px;
background: #555;
color: #fff;
border-radius: 3px;
display: inline-block;
font-size: 14px;
vertical-align: middle;
font-weight: 400;
line-height: 1.2;
}

a.loader-badge {
text-decoration: none;
}

.loader-badge:hover,
.loader-badge:focus {
color: #fff;
}

.prefix,
.status {
display: inline-block;
padding: 2px 6px;
}

.loader-badge .status {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}

.loader-badge .status.active {
background: #97C50F;
}

.loader-badge .status.complete {
background: #1081C2;
}

.loader-badge .status.error {
background: #D9634D;
}

.loader-badge .status.inactive {
background: #F27E3F;
}

.loader-badge .status.pending {
background: #9B9B9B;
}

.loader-badge .status.running {
background: #D8B124;
}

.loader-badge .status.unknown {
background: #9D9D9D;
}

4 changes: 4 additions & 0 deletions ckanext/xloader/webassets/webassets.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
main-css:
output: ckanext-xloader/%(version)s_xloader.css
contents:
- css/xloader.css

0 comments on commit cf437f1

Please sign in to comment.