Skip to content

Commit 1549cdd

Browse files
a5durclaude
andauthored
Tool & Extension readpage fixes (#169)
* Add GitHub repository stats section to tool details page and remove source URL button * Fix additional_info template to conditionally display site statistics * Add Recent Activity section to extension and tool read pages; remove 'Datasets in Extension' section - Added a GitHub Recent Activity sidebar section to read_extension.html and read_tool.html - Fetches the 5 most recent commits via GET /repos/{owner}/{repo}/commits?per_page=5 - Displays commit message (truncated, linked to GitHub), author name, relative timestamp, and author's GitHub profile picture - Avatar falls back to github.com/ghost.png for unmatched git authors - Results cached in localStorage for 30 minutes to reduce API calls - Gracefully handles rate limit errors and empty responses - Moved the 'View on GitHub' button from the Repository Stats section to the bottom of the Recent Activity section (links to /commits) - Removed the 'Datasets in Extension' section from extension_info.html snippet as it was not relevant Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Extract GitHub stats/activity sidebar into shared snippet; switch to Events API - Created snippets/github_sidebar.html as a single source of truth for all GitHub sidebar logic (Repository Stats + Recent Activity). Both read_extension.html and read_tool.html now include this snippet, passing github_url as the only parameter — eliminating duplicated CSS, JS, and HTML. - Switched Recent Activity from the commits endpoint to the Events API (GET /repos/{owner}/events?per_page=5) to display richer activity: issues opened/closed, PRs, pushes, watches, forks, releases, etc. Each event shows: actor avatar, relative timestamp, human-readable action, and a linked detail line (e.g. "Issue #457: pyproject.toml"). - Shared JS helpers (timeAgo, extractRepo, fromCache, toCache) are defined once and reused by both the stats and activity blocks within the snippet. - Description-source label styles (.ckanext-{extension,tool}-description-source) remain in their respective templates as they are type-specific. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7da57eb commit 1549cdd

6 files changed

Lines changed: 331 additions & 133 deletions

File tree

ckanext/pose_theme/custom_themes/pose_theme/templates/extension/snippets/extension_info.html

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,5 @@ <h1 class="heading">{{ pkg.title or pkg.name }}</h1>
3535
</div>
3636
</section>
3737

38-
<section class="module module-narrow">
39-
<h3 class="module-heading"><i class="fa fa-sitemap icon-medium icon-sitemap"></i> {{ _('Datasets in Extension') }}</h2>
40-
{% if packages %}
41-
<ul class="nav nav-simple">
42-
{% for package in packages %}
43-
{% set truncate_title = truncate_title or 80 %}
44-
{% set title = package.title or package.name %}
45-
<li class="nav-item">{{ h.link_to(title|truncate(truncate_title), h.url_for('dataset.read', id=package.name)) }}</li>
46-
{% endfor %}
47-
</ul>
48-
{% else %}
49-
<p class="module-content empty">{{_('There are no Datasets in this Extension')}}</p>
50-
{% endif %}
51-
</section>
5238
{% endif %}
5339
{% endblock %}

ckanext/pose_theme/custom_themes/pose_theme/templates/scheming/package/additional_info.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,23 @@
2121
'sotm_month',
2222
] -%}
2323

24-
{% set org = h.get_organization(pkg_dict.owner_org) %}
24+
{% set org = h.get_organization(pkg_dict.owner_org) %}
2525
{% block package_additional_info %}
2626
{% if h.check_access('package_update',{'id':pkg_dict.id}) %}
2727

2828
{% endif %}
2929
{%- set always_show_fields = ['contributors', 'ckan_version', 'extension_type'] -%}
30+
{%- set site_stat_fields = ['num_datasets', 'num_organizations', 'num_groups'] -%}
31+
{%- set all_site_stats_zero = (
32+
pkg_dict.get('num_datasets', '0') | string in ['0', '', 'None', 'none'] and
33+
pkg_dict.get('num_organizations', '0') | string in ['0', '', 'None', 'none'] and
34+
pkg_dict.get('num_groups', '0') | string in ['0', '', 'None', 'none']
35+
) -%}
3036
{%- for field in schema.dataset_fields -%}
3137
{%- set field_value = pkg_dict.get(field.field_name) -%}
3238
{%- if field.field_name not in exclude_fields
3339
and field.display_snippet is not none
40+
and not (field.field_name in site_stat_fields and all_site_stats_zero)
3441
and (field.field_name in always_show_fields
3542
or (field_value is not none
3643
and field_value != ''

ckanext/pose_theme/custom_themes/pose_theme/templates/scheming/package/read_extension.html

Lines changed: 5 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
{% block links -%}
1616
{{ super() }}
17-
17+
1818
{% endblock -%}
1919

2020
{% block head_extras -%}
@@ -142,119 +142,13 @@ <h1>
142142
{% endblock %}
143143

144144
{% if pkg.url and 'github.com' in pkg.url %}
145-
{% block package_github_stats %}
146-
<section class="module module-narrow module-github-stats">
147-
<h3 class="module-heading">
148-
<i class="fab fa-github icon-medium"></i> {{ _('Repository Stats') }}
149-
</h3>
150-
<div class="module-content" id="github-stats-content" data-github-url="{{ pkg.url }}">
151-
<p class="github-stats-loading text-muted">
152-
<i class="fa fa-spinner fa-spin"></i> {{ _('Loading stats…') }}
153-
</p>
154-
</div>
155-
</section>
156145
<style>
157-
.module-github-stats .github-stats-list {
158-
list-style: none;
159-
padding: 0;
160-
margin: 0 0 12px 0;
161-
}
162-
.module-github-stats .github-stats-list li {
163-
padding: 5px 0;
164-
border-bottom: 1px solid #f0f0f0;
165-
font-size: 13px;
166-
display: flex;
167-
align-items: center;
168-
gap: 8px;
169-
}
170-
.module-github-stats .github-stats-list li:last-child {
171-
border-bottom: none;
172-
}
173-
.module-github-stats .github-stats-list .stat-value {
174-
font-weight: bold;
175-
margin-left: auto;
176-
}
177-
.module-github-stats .github-stats-list i {
178-
width: 16px;
179-
text-align: center;
180-
color: #555;
181-
}
182-
.ckanext-extension-description-source {
183-
margin-top: 8px;
184-
}
185-
.ckanext-extension-description-source .label {
186-
font-size: 11px;
187-
font-weight: normal;
188-
letter-spacing: 0.02em;
189-
padding: 3px 7px;
190-
}
191-
.module-github-stats .github-stats-error {
192-
color: #999;
193-
font-size: 13px;
194-
}
146+
.ckanext-extension-description-source { margin-top: 8px; }
147+
.ckanext-extension-description-source .label { font-size: 11px; font-weight: normal; letter-spacing: 0.02em; padding: 3px 7px; }
195148
</style>
196-
<script>
197-
(function () {
198-
var CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
199-
var container = document.getElementById('github-stats-content');
200-
if (!container) return;
201-
var ghUrl = container.getAttribute('data-github-url') || '';
202-
var match = ghUrl.match(/github\.com\/([^\/]+\/[^\/\?#]+)/);
203-
if (!match) return;
204-
var repo = match[1].replace(/\.git$/, '');
205-
var cacheKey = 'gh_stats_' + repo.replace('/', '_');
206-
207-
function render(data) {
208-
var updated = new Date(data.pushed_at).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
209-
var licenseHtml = data.license
210-
? '<li><i class="fa fa-balance-scale"></i> {{ _("License") }} <span class="stat-value">' + data.license.spdx_id + '</span></li>'
211-
: '';
212-
container.innerHTML =
213-
'<ul class="github-stats-list">' +
214-
'<li><i class="fa fa-star"></i> {{ _("Stars") }} <span class="stat-value">' + data.stargazers_count.toLocaleString() + '</span></li>' +
215-
'<li><i class="fa fa-code-fork"></i> {{ _("Forks") }} <span class="stat-value">' + data.forks_count.toLocaleString() + '</span></li>' +
216-
'<li><i class="fa fa-exclamation-circle"></i> {{ _("Open Issues") }} <span class="stat-value">' + data.open_issues_count.toLocaleString() + '</span></li>' +
217-
'<li><i class="fa fa-eye"></i> {{ _("Watchers") }} <span class="stat-value">' + data.subscribers_count.toLocaleString() + '</span></li>' +
218-
licenseHtml +
219-
'<li><i class="fa fa-clock-o"></i> {{ _("Last Push") }} <span class="stat-value">' + updated + '</span></li>' +
220-
'</ul>' +
221-
'<a href="' + data.html_url + '" class="btn btn-default btn-block" target="_blank" rel="noopener">' +
222-
'<i class="fab fa-github"></i> {{ _("View on GitHub") }}</a>';
223-
}
224-
225-
// Serve from localStorage cache if still fresh
226-
try {
227-
var cached = localStorage.getItem(cacheKey);
228-
if (cached) {
229-
var entry = JSON.parse(cached);
230-
if (Date.now() - entry.ts < CACHE_TTL_MS) {
231-
render(entry.data);
232-
return;
233-
}
234-
}
235-
} catch (e) {}
236-
237-
fetch('https://api.github.com/repos/' + repo, {
238-
headers: { 'Accept': 'application/vnd.github.v3+json' }
239-
})
240-
.then(function (r) { return r.json(); })
241-
.then(function (data) {
242-
if (data.message) {
243-
container.innerHTML = '<p class="github-stats-error"><i class="fa fa-exclamation-triangle"></i> ' + data.message + '</p>';
244-
return;
245-
}
246-
try {
247-
localStorage.setItem(cacheKey, JSON.stringify({ ts: Date.now(), data: data }));
248-
} catch (e) {}
249-
render(data);
250-
})
251-
.catch(function () {
252-
container.innerHTML = '<p class="github-stats-error"><i class="fa fa-exclamation-triangle"></i> {{ _("Could not load stats.") }}</p>';
253-
});
254-
})();
255-
</script>
149+
{% block package_github_sidebar %}
150+
{% snippet 'snippets/github_sidebar.html', github_url=pkg.url %}
256151
{% endblock %}
257152
{% endif %}
258153

259154
{% endblock %}
260-

ckanext/pose_theme/custom_themes/pose_theme/templates/scheming/package/read_tool.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,5 +135,14 @@ <h1>
135135
{% snippet 'tool/snippets/tool_info.html', pkg=pkg %}
136136
{% endblock %}
137137

138+
{% if pkg.source_url and 'github.com' in pkg.source_url %}
139+
<style>
140+
.ckanext-tool-description-source { margin-top: 8px; }
141+
.ckanext-tool-description-source .label { font-size: 11px; font-weight: normal; letter-spacing: 0.02em; padding: 3px 7px; }
142+
</style>
143+
{% block package_github_sidebar %}
144+
{% snippet 'snippets/github_sidebar.html', github_url=pkg.source_url %}
145+
{% endblock %}
146+
{% endif %}
138147

139148
{% endblock %}

0 commit comments

Comments
 (0)