Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/update-discourse-data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
run: |
python tools/fetch-news.py
python tools/fetch-faq.py
python tools/fetch-community-metrics.py

- name: Configure Git author
run: |
Expand All @@ -42,6 +43,7 @@ jobs:
run: |
git add assets/data/news.json
git add assets/data/faq.json
git add assets/data/community-metrics.json
git commit -m "Update Discourse data data [skip ci]" || echo "No changes to commit"

- name: Push commit
Expand Down
60 changes: 60 additions & 0 deletions assets/data/community-metrics.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"generated_at": "2026-02-22T15:31:13.791892+00:00",
"github": {
"repositories": [
{
"id": "core",
"label": "preCICE core",
"full_name": "precice/precice",
"url": "https://github.com/precice/precice",
"description": "A coupling library and ecosystem for partitioned multi-physics and multi-scale simulations, including surface and volume coupling.",
"stars": 887,
"forks": 224,
"open_issues": 230,
"watchers": 35,
"contributors": 66,
"latest_commit_at": "2026-02-18T13:23:28Z",
"latest_release": {
"name": "v3.3.1",
"tag_name": "v3.3.1",
"published_at": "2026-01-14T15:28:58Z",
"url": "https://github.com/precice/precice/releases/tag/v3.3.1",
"assets_count": 8,
"downloads_count": 345
}
},
{
"id": "tutorials",
"label": "Tutorials",
"full_name": "precice/tutorials",
"url": "https://github.com/precice/tutorials",
"description": "Various tutorial cases for the coupling library preCICE with real solvers. These files are meant to be rendered on precice.org, so don't look at the README files here.",
"stars": 131,
"forks": 138,
"open_issues": 110,
"watchers": 10,
"contributors": 48,
"latest_commit_at": "2026-02-20T20:01:02Z",
"latest_release": {
"name": "v202404.0 - Now with preCICE v3",
"tag_name": "v202404.0",
"published_at": "2024-04-16T20:35:04Z",
"url": "https://github.com/precice/tutorials/releases/tag/v202404.0",
"assets_count": 0,
"downloads_count": 0
}
}
]
},
"discourse": {
"url": "https://precice.discourse.group",
"title": "preCICE Forum on Discourse",
"site_creation_date": "2019-09-16T04:29:48.122Z",
"users_count": 676,
"topics_count": 1163,
"posts_count": 8866,
"active_users_30_days": 62,
"topics_30_days": 18,
"posts_30_days": 83
}
}
9 changes: 9 additions & 0 deletions content/community/community.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ Meet the community online, ask questions, and help others at the [preCICE forum

Are you looking for something else? Maybe one of the other [community channels](community-channels.html) is for you.

## Community metrics

The following metrics are updated automatically and provide a quick snapshot of community activity.

<p id="community-metrics-status" class="text-muted">Loading automatically generated metrics...</p>
<div id="community-metrics"></div>

<script src="js/community-metrics.js"></script>

## Support preCICE

There are different ways how to support preCICE and get priority support from the preCICE developers in return. [Find out which options](community-support-precice.html).
Expand Down
176 changes: 176 additions & 0 deletions js/community-metrics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
(function () {
var REPO_BLURBS = {
core: "Core coupling library and ecosystem.",
tutorials: "Ready-to-run tutorial cases for users and developers.",
};

function formatNumber(value) {
if (typeof value !== "number") {
return "n/a";
}
return new Intl.NumberFormat("en-US").format(value);
}

function formatDate(value) {
if (!value) {
return "n/a";
}

var parsed = new Date(value);
if (Number.isNaN(parsed.getTime())) {
return "n/a";
}

return parsed.toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});
}

function createMetricItem(label, value) {
var item = document.createElement("li");
item.innerHTML = "<strong>" + label + ":</strong> " + value;
return item;
}

function createSection(title, description, metrics, linkUrl, linkLabel) {
var section = document.createElement("section");
section.style.marginBottom = "14px";

var heading = document.createElement("h4");
heading.textContent = title;
heading.style.marginBottom = "4px";
section.appendChild(heading);

if (description) {
var blurb = document.createElement("p");
blurb.className = "text-muted";
blurb.style.marginBottom = "6px";
blurb.style.fontSize = "0.95em";
blurb.textContent = description;
section.appendChild(blurb);
}

var list = document.createElement("ul");
list.className = "list-unstyled";
list.style.marginBottom = "6px";

for (var i = 0; i < metrics.length; i += 1) {
var metric = metrics[i];
list.appendChild(createMetricItem(metric[0], metric[1]));
}
section.appendChild(list);

if (linkUrl && linkLabel) {
var paragraph = document.createElement("p");
paragraph.className = "no-margin";
var link = document.createElement("a");
link.href = linkUrl;
link.target = "_blank";
link.rel = "noopener noreferrer";
link.className = "no-external-marker";
link.innerHTML = linkLabel + " &nbsp;<i class=\"fas fa-chevron-right\"></i>";
paragraph.appendChild(link);
section.appendChild(paragraph);
}

return section;
}

function createRepositorySection(repo) {
var latestRelease = repo.latest_release;
var latestReleaseValue = "n/a";
if (latestRelease && latestRelease.url) {
latestReleaseValue =
"<a href=\"" +
latestRelease.url +
"\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"no-external-marker\">" +
(latestRelease.tag_name || latestRelease.name || "Release") +
"</a> (" +
formatDate(latestRelease.published_at) +
")";
}

var releaseDownloads = latestRelease ? formatNumber(latestRelease.downloads_count) : "n/a";

return createSection(
repo.label,
REPO_BLURBS[repo.id] || "",
[
["Stars", formatNumber(repo.stars)],
["Contributors", formatNumber(repo.contributors)],
["Open issues", formatNumber(repo.open_issues)],
["Latest commit", formatDate(repo.latest_commit_at)],
["Latest release", latestReleaseValue],
["Release downloads", releaseDownloads],
],
repo.url,
"Open repository"
);
}

function createDiscourseSection(discourse) {
return createSection(
"Discourse forum",
"Community activity snapshot.",
[
["Users", formatNumber(discourse.users_count)],
["Topics", formatNumber(discourse.topics_count)],
["Posts", formatNumber(discourse.posts_count)],
["Active users (30d)", formatNumber(discourse.active_users_30_days)],
["Topics (30d)", formatNumber(discourse.topics_30_days)],
["Posts (30d)", formatNumber(discourse.posts_30_days)],
],
discourse.url,
"Open forum"
);
}

function showError(status, message) {
if (status) {
status.textContent = message;
}
}

document.addEventListener("DOMContentLoaded", async function () {
var container = document.getElementById("community-metrics");
if (!container) {
return;
}

var status = document.getElementById("community-metrics-status");

try {
var response = await fetch("/assets/data/community-metrics.json");
if (!response.ok) {
throw new Error("HTTP " + response.status);
}

var metrics = await response.json();
var repositories = (metrics.github && metrics.github.repositories) || [];
var discourse = metrics.discourse;

if (!repositories.length || !discourse) {
throw new Error("Missing metrics data");
}

container.innerHTML = "";
for (var i = 0; i < repositories.length; i += 1) {
container.appendChild(createRepositorySection(repositories[i]));
}
container.appendChild(createDiscourseSection(discourse));

if (status) {
status.textContent =
"Automatically generated metrics. Last updated " + formatDate(metrics.generated_at) + ".";
}
} catch (error) {
console.error("Could not load community metrics:", error);
showError(
status,
"Could not load the metrics right now. You can still browse all details on GitHub and in the forum."
);
}
});
})();
Loading