From 8413c92f759af7ae3354f83a8aa28f248266dd74 Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 11:21:17 -0400 Subject: [PATCH 01/11] Switch to local SVG use for code platform logo Codeberg logo is too complex for simple svg path definition --- index.html | 8 +- src/assets/GitHub_Invertocat.svg | 10 ++ src/assets/codeberg-logo_icon_white.svg | 164 ++++++++++++++++++++++++ src/utils/defineRibbonVals.js | 25 ++-- 4 files changed, 191 insertions(+), 16 deletions(-) create mode 100755 src/assets/GitHub_Invertocat.svg create mode 100644 src/assets/codeberg-logo_icon_white.svg diff --git a/index.html b/index.html index 7e96d4a..9aa5eae 100644 --- a/index.html +++ b/index.html @@ -28,9 +28,11 @@ class="fixed top-6 right-6 hidden md:flex items-center gap-3 text-white py-2 px-4 rounded-lg shadow-md transition-all z-50 no-underline group font-sans border border-white/10">
-
+
@@ -199,4 +201,4 @@

- + \ No newline at end of file diff --git a/src/assets/GitHub_Invertocat.svg b/src/assets/GitHub_Invertocat.svg new file mode 100755 index 0000000..5300969 --- /dev/null +++ b/src/assets/GitHub_Invertocat.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/codeberg-logo_icon_white.svg b/src/assets/codeberg-logo_icon_white.svg new file mode 100644 index 0000000..74a0fa9 --- /dev/null +++ b/src/assets/codeberg-logo_icon_white.svg @@ -0,0 +1,164 @@ + + + Codeberg logo + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Codeberg logo + + + + Robert Martinez + + + + + Codeberg and the Codeberg Logo are trademarks of Codeberg e.V. + + + 2020-04-09 + + + Codeberg e.V. + + + codeberg.org + + + + + + + + + + + + + diff --git a/src/utils/defineRibbonVals.js b/src/utils/defineRibbonVals.js index 9ab64a0..23bee23 100644 --- a/src/utils/defineRibbonVals.js +++ b/src/utils/defineRibbonVals.js @@ -7,10 +7,14 @@ * Usage: import { getPlatformDisplay } from './defineRibbonVals.js'; * * Input: platform (e.g., 'github'), defined from config.yaml and passed to this function. - * Output: platformDisplays[platform] = { path: SVG_PATH_DATA, viewBox: VIEWBOX_DATA, + * Output: platformDisplays[platform] = { path: SVG_PATH_DATA, viewBox: VIEWBOX_DATA, * displayName: DISPLAY_NAME, ribbonUrl: RIBBON_URL } */ +import githubSvg from '../assets/GitHub_Invertocat.svg?raw'; +// import gitlabSvg from '../assets/gitlab-logo-700-rgb.svg?raw'; +import codebergSvg from '../assets/codeberg-logo_icon_white.svg?raw'; + /** * Utility function to get the full platform display information * @param {string} platform - 'github', 'gitlab', or 'codeberg' @@ -19,25 +23,20 @@ export function getPlatformDisplay(platform) { const platformDisplays = { github: { - path: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z", - viewBox: "0 0 24 24", + svg: githubSvg, displayName: "GitHub", ribbonUrl: "https://github.com/" }, // gitlab: { - // path: "m23.71 11.83-2.13-6.52a.89.89 0 0 0-1.7 0l-2.13 6.52H6.25L4.12 5.31a.89.89 0 0 0-1.7 0L.29 11.83a1 1 0 0 0 .37 1.13l11.34 8.24 11.34-8.24a1 1 0 0 0 .37-1.13Z", - // viewBox: "0 0 24 24", - // color: "#FC6D26", + // svg: gitlabSvg, // displayName: "GitLab", // ribbonUrl: "https://gitlab.com/" //}, - // codeberg: { - // path: "M12.004 2.378a.636.636 0 0 0-.547.31L1.258 19.874a.636.636 0 0 0 .547.954h1.94c.143 0 .278-.074.354-.197L12 6.544l7.89 14.087a.406.406 0 0 0 .354.197h2.012a.636.636 0 0 0 .546-.954L12.551 2.688a.636.636 0 0 0-.547-.31Z", - // viewBox: "0 0 24 24", - // color: "#2185d0", - // displayName: "Codeberg", - // ribbonUrl: "https://codeberg.org/" - //} + codeberg: { + svg: codebergSvg, + displayName: "Codeberg", + ribbonUrl: "https://codeberg.org/" + } }; return platformDisplays[platform.toLowerCase()]; } From 4e9cc1c18a57ed269f680d78a487b57319b6a24a Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 11:32:16 -0400 Subject: [PATCH 02/11] Add Codeberg as an option for code platform --- src/api/fetchCodeRepos.js | 2 +- src/api/fetchStats.js | 2 +- src/ui/initUserInterface.js | 4 ++-- src/utils/defineApiUrls.js | 12 ++++++------ src/validateConfig.js | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/api/fetchCodeRepos.js b/src/api/fetchCodeRepos.js index a427a2b..398b1ad 100644 --- a/src/api/fetchCodeRepos.js +++ b/src/api/fetchCodeRepos.js @@ -105,7 +105,7 @@ export async function fetchCodeRepos( cardData: { pretty_name: repo.name, // , the one used for card title display description: repo.description, - stars: repo.stargazers_count || 0 + stars: repo.stargazers_count || repo.stars_count || 0 } }; }); diff --git a/src/api/fetchStats.js b/src/api/fetchStats.js index fc0c0bd..e1c4f17 100644 --- a/src/api/fetchStats.js +++ b/src/api/fetchStats.js @@ -24,7 +24,7 @@ export const fetchCatalogStats = async (repoApiUrl, organizationName, catalogRep //TODO: Update stars and forks to support other platforms (GitLab, Codeberg) once implemented // 1. Get Stars & Forks const repo = await fetch(`${repoApiUrl}${organizationName}/${catalogRepoName}`).then(r => r.ok ? r.json() : {}); - if (repo.stargazers_count !== undefined) update('gh-stars', 'gh-star-container', repo.stargazers_count); + if (repo.stargazers_count !== undefined || repo.stars_count !== undefined) update('gh-stars', 'gh-star-container', repo.stargazers_count || repo.stars_count); if (repo.forks_count !== undefined) update('gh-forks', 'gh-fork-container', repo.forks_count); // 2. Get Version (Tag) diff --git a/src/ui/initUserInterface.js b/src/ui/initUserInterface.js index 8dd1691..c8c250d 100644 --- a/src/ui/initUserInterface.js +++ b/src/ui/initUserInterface.js @@ -55,8 +55,8 @@ export const initializeUIFromConfig = (config) => { const platformDisplay = getPlatformDisplay(config.PLATFORM); if (repoRibbon && platformDisplay) { repoRibbon.href = `${platformDisplay.ribbonUrl}${config.ORGANIZATION_NAME}/${config.CATALOG_REPO_NAME}`; - const pathElement = document.getElementById('repo-ribbon-icon'); - pathElement.setAttribute('d', platformDisplay.path); + const svgElement = document.getElementById('repo-ribbon-icon-container'); + svgElement.innerHTML = platformDisplay.svg; const platformDisplayName = document.getElementById('platform-display-name'); platformDisplayName.textContent = platformDisplay.displayName || config.PLATFORM; repoRibbon.style.backgroundColor = config.COLORS.secondary; diff --git a/src/utils/defineApiUrls.js b/src/utils/defineApiUrls.js index 5b20e43..c12e032 100644 --- a/src/utils/defineApiUrls.js +++ b/src/utils/defineApiUrls.js @@ -2,9 +2,9 @@ * Defines API URLs based on the selected platform (GitHub, note: GitLab and Codeberg support under development). * This allows the rest of the codebase to use these constants when making API calls, * abstracting away platform-specific URL structures. - * + * * Usage: import { getPlatformApiUrls } from './defineApiUrls.js'; - * + * * Input: platform and organizationName (e.g., 'github' and 'imageomics'), defined from config.yaml and passed to this function. * Output: platformApiUrls[platform] = { org: ORG_API_URL, repo: REPO_API_URL } */ @@ -25,10 +25,10 @@ export function getPlatformApiUrls(platform, organizationName) { // org: `https://gitlab.com/api/v4/groups/${organizationName}/projects?per_page=100`, // repo: "https://gitlab.com/api/v4/projects/" // }, - // codeberg: { - // org: `https://codeberg.org/api/v1/orgs/${organizationName}/repos?limit=50`, - // repo: "https://codeberg.org/api/v1/repos/" - // } + codeberg: { + org: `https://codeberg.org/api/v1/orgs/${organizationName}/repos?limit=50`, + repo: "https://codeberg.org/api/v1/repos/" + } }; return platformApiUrls[platform.toLowerCase()]; } diff --git a/src/validateConfig.js b/src/validateConfig.js index d903afe..78264d8 100644 --- a/src/validateConfig.js +++ b/src/validateConfig.js @@ -31,11 +31,11 @@ export function validateConfig(config) { } if (!config.ORG_NAME) errors.push('ORG_NAME'); if (!config.CATALOG_REPO_NAME) errors.push('CATALOG_REPO_NAME'); - - /** Update to include 'codeberg' and 'gitlab' once supported + + /** Update to include 'gitlab' once supported * PLATFORM will be parsed without whitespace, but must be string to avoid undefined errors */ - const supportedPlatforms = ['github']; + const supportedPlatforms = ['github', 'codeberg']; const platform = config.PLATFORM; if (!platform || typeof platform !== 'string') { errors.push('PLATFORM'); From b8ff05fb1383d170106748345af7e529f28455ee Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 11:49:15 -0400 Subject: [PATCH 03/11] Update documentation to reflect addition of Codeberg as a code platform option --- README.md | 12 ++++++------ docs/personalization.md | 6 +++++- docs/tag-grouping-process.md | 7 ++++++- public/config.yaml | 2 +- src/utils/defineRibbonVals.js | 7 +++---- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b10087a..f038f2a 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ For those interested in creating a similar catalog website or contributing to th The website is styled using the [tailwindcss](https://tailwindcss.com/) package. -* **Real-time Data Fetching:** Displays all public organization repositories, fetched through the GitHub and Hugging Face APIs. Includes semantically meaningful virtual markers: +* **Real-time Data Fetching:** Displays all public organization repositories, fetched through the code platform and Hugging Face APIs. Includes semantically meaningful virtual markers: * "New" badge highlights products created within the last 30 days; - * "🚀 version-tag" badge indicates a new release within the last 2 weeks for GitHub repos, and links to that release; - * Star (⭐️) or like (❤️) counts displayed for GitHub or Hugging Face repos, respectively; - * Archived badge flags GitHub repos no longer under active development (read-only). + * "🚀 version-tag" badge indicates a new release within the last 2 weeks for code repos, and links to that release; + * Star (⭐️) or like (❤️) counts displayed for code platform or Hugging Face repos, respectively; + * Archived badge flags code repos no longer under active development (read-only). * **Search Functionality:** Quickly find items by keyword. -* **Filtering:** Filter by repository type (Code, Datasets, Models, Spaces) and tags. Optionally include archived GitHub repos. +* **Filtering:** Filter by repository type (Code, Datasets, Models, Spaces) and tags. Optionally include archived code repos. * **Sorting:** Sort items by last updated, date created, stars/likes ascending or descending, or alphabetically. * **URL Parameter Support:** Persist and share search states via URL hash (`#type=datasets&q=fish`) or query parameters (`?type=datasets`). Supports `type`, `q` (search query), `sort`, and `tag` parameters. * **Responsive Design:** The layout is optimized for use on computers and mobile devices. @@ -30,7 +30,7 @@ The site runs based on four primary files: * `style.css`: Custom styling for the application, including color schemes, layout, and animations. Colors are set via CSS custom properties that are populated from `config.yaml`. * `main.js`: Application manager, handles config loading, event listeners, and coordinates UI updates based on API fetches for dynamic rendering of the catalog items. * `src/`: Modular application logic, organized by purpose: - * `api/`: Data fetching modules for external platforms (GitHub and Hugging Face). + * `api/`: Data fetching modules for external platforms (code and Hugging Face). * `ui/`: DOM manipulation, HTML templating, and URL/State routing. * `utils/`: Utility functions such as data filtering, sorting, and tag (keyword) normalization. diff --git a/docs/personalization.md b/docs/personalization.md index cc26212..13957e0 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -32,7 +32,7 @@ Welcome to your new catalog repo! The primary way to personalize this catalog is ### API & Behavior Settings - * `PLATFORM`: Coding platform used (default: 'github', Codeberg and GitLab support in development) + * `PLATFORM`: Coding platform used: 'github' or 'codeberg' (default: 'github', GitLab support in development). Please see [notes on platform setup](#non-github-code-platform-setup) if using for non-GitHub code repositories * `API_BASE_URL`: Hugging Face API base URL (default: `"https://huggingface.co/api/"`) * `REFRESH_INTERVAL_DAYS`: Number of days to consider an item "new" (default: `30`) * `ADDITIONAL_REPOS`: Array of forked or non-org GitHub repositories to include, formatted `/` (non-forks are included by default). Use `[]` if there are none you wish to include @@ -88,3 +88,7 @@ When first setting up your catalog, run the export script to generate a full lis > **Required token**: The weekly tag scan workflow requires a fine-grained access token with **Pull requests: Read and write** permission on the catalog repo. Follow the instructions in [App Authentication](app-authentication.md) to create and install a private Catalog Automation App for token generation. See **[tag-grouping-process.md](tag-grouping-process.md)** for full setup instructions, conventions, and guidance on using AI assistance for the initial grouping pass. + +## Non-GitHub Code Platform Setup + +The default code platform for this catalog is GitHub. If you wish to use another supported platform (Codeberg), please note that the [tag export](../scripts/export-tags.js) and [fetch release](../scripts/fetch-releases.js) scripts may require header definition modifications to function properly. Workflows would also require token and other platform-specific updates if running from a non-GitHub repository. Otherwise, this app is set up to be able to run from Codeberg to fetch and display Codeberg repositories. diff --git a/docs/tag-grouping-process.md b/docs/tag-grouping-process.md index e73b013..452a227 100644 --- a/docs/tag-grouping-process.md +++ b/docs/tag-grouping-process.md @@ -2,11 +2,16 @@ ## What Are Tag Groups? -Tags on GitHub repos (topics) and Hugging Face repos (card metadata) are free-form text, so +Tags on code platform[^1] repos (topics) and Hugging Face repos (card metadata) are free-form text, so the same concept often appears under multiple spellings: `computer-vision`, `computer vision`, `cv`. Tag groups normalize this noise so the catalog filter dropdown shows one clean canonical tag instead of a dozen near-duplicates. +> [!NOTE] +> This workflow has only been run on GitHub. It may need platform-based adjustments to function as expected on other code platforms, such as Codeberg or GitLab. + +[^1]: GitHub, Codeberg, and GitLab. + Tag groups live in **`public/tag-groups.js`** as a plain JavaScript object: ```js diff --git a/public/config.yaml b/public/config.yaml index 06b960d..7514f69 100644 --- a/public/config.yaml +++ b/public/config.yaml @@ -22,7 +22,7 @@ COLORS: tag: "#9bcb5e" # Tag background color (Light Green) # API & Behavior Settings -# Codebase platform for API calls and link generation. Supported values: "github", pending: "codeberg" or "gitlab". +# Codebase platform for API calls and link generation. Supported values: "github" or "codeberg", pending: "gitlab". PLATFORM: github # Dataset, model, and space (demo) default: Hugging Face, other platforms would require a custom module API_BASE_URL: "https://huggingface.co/api/" diff --git a/src/utils/defineRibbonVals.js b/src/utils/defineRibbonVals.js index 23bee23..7a4486d 100644 --- a/src/utils/defineRibbonVals.js +++ b/src/utils/defineRibbonVals.js @@ -1,13 +1,12 @@ /** - * A collection of platform-specific display information (e.g., SVG path data) - * for code developer platforms including GitHub, pending: GitLab and Codeberg. + * A collection of platform-specific display information (e.g., SVGs and URLs) + * for code developer platforms including GitHub and Codeberg, pending: GitLab. * Used for linking to repo and rendering icon and platform name in the ribbon component of the UI. - * All paths are optimized for a 0 0 24 24 viewBox. * * Usage: import { getPlatformDisplay } from './defineRibbonVals.js'; * * Input: platform (e.g., 'github'), defined from config.yaml and passed to this function. - * Output: platformDisplays[platform] = { path: SVG_PATH_DATA, viewBox: VIEWBOX_DATA, + * Output: platformDisplays[platform] = { svg: CODE_PLATFORM_SVG, * displayName: DISPLAY_NAME, ribbonUrl: RIBBON_URL } */ From 2421553acdc709e6342141d0282f85b78a805f8b Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 11:53:07 -0400 Subject: [PATCH 04/11] Add template config for reference --- docs/personalization.md | 2 +- public/config-template.yaml | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 public/config-template.yaml diff --git a/docs/personalization.md b/docs/personalization.md index 13957e0..83332a8 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -4,7 +4,7 @@ Welcome to your new catalog repo! The primary way to personalize this catalog is ## Primary Configuration File -[**`public/config.yaml`**](../public/config.yaml): This is the main file to edit. It contains all configuration options (e.g., organization names, colors, branding, and API settings) with inline comments explaining each setting. Replace Imageomics-specific values with those appropriate for your organzation and catalog repository. +[**`public/config.yaml`**](../public/config.yaml): This is the main file to edit. It contains all configuration options (e.g., organization names, colors, branding, and API settings) with inline comments explaining each setting. Replace Imageomics-specific values with those appropriate for your organzation and catalog repository. A [template config](../public/config-template.yaml) is also provided for reference. ### Organization & Repository Settings diff --git a/public/config-template.yaml b/public/config-template.yaml new file mode 100644 index 0000000..831ea34 --- /dev/null +++ b/public/config-template.yaml @@ -0,0 +1,51 @@ +# Configuration file for Catalog Template +# Customize these values to personalize the catalog for your organization + +# Organization & Repository Settings +ORGANIZATION_NAME: imageomics # Codebase platform organization name (for API calls) +HF_ORGANIZATION_NAME: "" # Hugging Face organization name (case-sensitive, for API calls) +ORG_NAME: Imageomics # Display name for Codebase platform organization (can differ from API name) +CATALOG_REPO_NAME: catalog # Repository name for the catalog itself (used for stats badge) + +# Branding +CATALOG_TITLE: '' +CATALOG_DESCRIPTION: "Explore and discover public code, datasets, models, and spaces." +LOGO_URL: "https://github.com/Imageomics/Imageomics-guide/raw/3478acc0068a87a5604069d04a29bdb0795c2045/docs/logos/Imageomics_logo_butterfly.png" +FAVICON_URL: "" + +# Colors (CSS custom properties) +COLORS: + primary: "" # Primary brand color + secondary: "" # Secondary brand color + accent: "" # Accent color + accentDark: "" # Dark mode accent color + tag: "" # Tag background color + +# API & Behavior Settings +# Codebase platform for API calls and link generation. Supported values: "github" or "codeberg", pending: "gitlab". +PLATFORM: github +# Dataset, model, and space (demo) default: Hugging Face, other platforms would require a custom module +API_BASE_URL: "https://huggingface.co/api/" +# Define "new" repository criteria +REFRESH_INTERVAL_DAYS: 30 + +# Array of "owner/repo" strings to include in addition to non-forked org repos. +# Use this for forked repos within the org and repos outside the org entirely. +# ADDITIONAL_REPOS: +# - "user/repo-name" +ADDITIONAL_REPOS: [] + +# Array of Hugging Face repos from outside the org to include. +# Each entry must specify "repo" (owner/name) and "type" (datasets, models, or spaces). +# Organization names are case-sensitive in the Hugging Face API. +# ADDITIONAL_HF_REPOS: +# - repo: "user/dataset-name" +# type: "datasets" +# - repo: "user/model-name" +# type: "models" +# - repo: "user/space-name" +# type: "spaces" +ADDITIONAL_HF_REPOS: [] + +# Typography +FONT_FAMILY: Inter # Font family for the site From 0fc3221ca5082e473651fa27d221174a19a77685 Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 12:44:47 -0400 Subject: [PATCH 05/11] formatting fix --- index.html | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 9aa5eae..ea08f92 100644 --- a/index.html +++ b/index.html @@ -28,11 +28,8 @@ class="fixed top-6 right-6 hidden md:flex items-center gap-3 text-white py-2 px-4 rounded-lg shadow-md transition-all z-50 no-underline group font-sans border border-white/10">
-
- +
@@ -201,4 +198,4 @@

- \ No newline at end of file + From bb3601955081d572b4a0c9b4d929bf2dbe812874 Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 12:54:44 -0400 Subject: [PATCH 06/11] Check release not undefined for ribbon, as with stars and forks, there may not be a release --- src/api/fetchStats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/fetchStats.js b/src/api/fetchStats.js index e1c4f17..76f6888 100644 --- a/src/api/fetchStats.js +++ b/src/api/fetchStats.js @@ -30,7 +30,7 @@ export const fetchCatalogStats = async (repoApiUrl, organizationName, catalogRep // 2. Get Version (Tag) // TODO: Import from package.json const release = await fetch(`${repoApiUrl}${organizationName}/${catalogRepoName}/releases/latest`).then(r => r.ok ? r.json() : {}); - if (release.tag_name) update('gh-tag', 'gh-version-container', release.tag_name); + if (release.tag_name !== undefined) update('gh-tag', 'gh-version-container', release.tag_name); } catch (e) { console.warn("Could not fetch Code Repo stats", e); From 676cece134cdf350b952428707b5c2785b709b89 Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 17:06:55 -0400 Subject: [PATCH 07/11] Generalize tests for code fetching to cycle platforms Add profile repo key, Codeberg uses .profile like GitHub has .github --- src/api/fetchCodeRepos.js | 28 +++++++++++++-- src/utils/defineApiUrls.js | 4 +-- tests/api/fetchCodeRepos.test.js | 62 +++++++++++++++++++++++--------- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/api/fetchCodeRepos.js b/src/api/fetchCodeRepos.js index 398b1ad..113caef 100644 --- a/src/api/fetchCodeRepos.js +++ b/src/api/fetchCodeRepos.js @@ -2,6 +2,23 @@ import { handleError } from '../ui/render.js'; import { normalizeTag, filterDisplayTags } from '../utils/normalizeTag.js'; import { getPlatformDisplay } from '../utils/defineRibbonVals.js'; +// Define platform-specific values +const PLATFORM_CONFIGS = { + github: { + starsKey: 'stargazers_count', + profileRepo: '.github' + }, + /* gitlab: { + starsKey: 'star_count', + profileRepo: 'gitlab-profile', + //TODO + }, */ + codeberg: { + starsKey: 'stars_count', + profileRepo: '.profile' + } +}; + /** * Function for fetching code repositories from the specified platform (GitHub, GitLab, or Codeberg). * Both org-owned (non-forks) and additional repos are fetched; metadata is processed for each repo. @@ -28,6 +45,10 @@ export async function fetchCodeRepos( let allRepos = []; let nextUrl = `${orgApiUrl}`; + // get platform-specific keys + const platformConfig = PLATFORM_CONFIGS[platform]; + const starsKey = platformConfig.starsKey; + const profileRepo = platformConfig.profileRepo; try { while (nextUrl) { const ghResponse = await fetch(nextUrl); @@ -72,7 +93,10 @@ export async function fetchCodeRepos( // Keep only non-forks from org; deduplicate against additional repos by full_name const orgRepoNames = new Set(filteredAdditionalRepos.map(r => r.full_name)); - const orgNonForks = allRepos.filter(repo => repo.name !== ".github" && !repo.fork && !orgRepoNames.has(repo.full_name)); + const orgNonForks = allRepos.filter(repo => + repo.name !== profileRepo && + !repo.fork && + !orgRepoNames.has(repo.full_name)); // Process additional repos and all remaining org non-forks to include metadata and 'new' flag as appropriate let processedItems = [...filteredAdditionalRepos, ...orgNonForks] @@ -105,7 +129,7 @@ export async function fetchCodeRepos( cardData: { pretty_name: repo.name, // , the one used for card title display description: repo.description, - stars: repo.stargazers_count || repo.stars_count || 0 + stars: repo[starsKey] ?? 0 } }; }); diff --git a/src/utils/defineApiUrls.js b/src/utils/defineApiUrls.js index c12e032..2d68025 100644 --- a/src/utils/defineApiUrls.js +++ b/src/utils/defineApiUrls.js @@ -1,5 +1,5 @@ /** - * Defines API URLs based on the selected platform (GitHub, note: GitLab and Codeberg support under development). + * Defines API URLs based on the selected platform (GitHub or Codeberg, note: GitLab support under development). * This allows the rest of the codebase to use these constants when making API calls, * abstracting away platform-specific URL structures. * @@ -11,7 +11,7 @@ /** * Utility function to get the platform-specific API URLs for organization repos and individual repo details. - * @param {string} platform - 'github', pending: 'gitlab', or 'codeberg' + * @param {string} platform - 'github' or 'codeberg', pending: 'gitlab' * @param {string} organizationName - The name of the organization (used in URL construction) * @returns {object} An object containing ORG_API_URL and REPO_API_URL */ diff --git a/tests/api/fetchCodeRepos.test.js b/tests/api/fetchCodeRepos.test.js index 98c594b..55e815e 100644 --- a/tests/api/fetchCodeRepos.test.js +++ b/tests/api/fetchCodeRepos.test.js @@ -14,7 +14,32 @@ vi.mock('../../src/utils/defineRibbonVals.js', () => ({ getPlatformDisplay: vi.fn(() => 'GitHub') })); -describe('fetchCodeRepos', () => { +// define configs for each platform +const platformConfigs = [ + { + name: 'github', + orgApiUrl: 'https://api.github.com/orgs/test-org/repos', + repoApiUrl: 'https://api.github.com/repos/', + platformProfileRepo: '.github', + starsKey: 'stargazers_count' + }, + /* { + name: 'gitlab', + orgApiUrl: 'https://gitlab.com/api/v4/groups/test-org/projects', + repoApiUrl: 'https://gitlab.com/api/v4/projects/', + platformProfileRepo: 'gitlab-profile', + starsKey: 'star_count' + }, */ + { + name: 'codeberg', + orgApiUrl: 'https://codeberg.org/api/v1/orgs/test-org/repos', + repoApiUrl: 'https://codeberg.org/api/v1/repos/', + platformProfileRepo: '.profile', + starsKey: 'stars_count' + } +]; + +describe.each(platformConfigs)('fetchCodeRepos - $name', (platformConfig) => { const originalFetch = global.fetch; beforeEach(() => { @@ -25,8 +50,11 @@ describe('fetchCodeRepos', () => { vi.clearAllMocks(); }); - const orgApiUrl = 'https://api.github.com/orgs/test-org/repos'; - const repoApiUrl = 'https://api.github.com/repos/'; + const orgApiUrl = platformConfig.orgApiUrl; + const repoApiUrl = platformConfig.repoApiUrl; + const platform = platformConfig.name; + const starsKey = platformConfig.starsKey; + const platformProfileRepo = platformConfig.platformProfileRepo; const refreshIntervalDays = 30; const releasesMap = {}; @@ -37,7 +65,7 @@ describe('fetchCodeRepos', () => { const oldestDateISO = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000).toISOString(); // 90 days ago it('maps raw repo data and attaches release data from releasesMap', async () => { - // Mock a single page GitHub response + // Mock a single page platform response global.fetch.mockResolvedValueOnce({ ok: true, headers: { get: () => null }, // No 'link' header means no pagination @@ -47,7 +75,7 @@ describe('fetchCodeRepos', () => { updated_at: now.toISOString(), created_at: recentDateISO, topics: ['python'], - stargazers_count: 42, + [starsKey]: 42, }]) }); @@ -57,7 +85,7 @@ describe('fetchCodeRepos', () => { }; const items = await fetchCodeRepos( - 'github', + platform, [], // No additional repos orgApiUrl, repoApiUrl, @@ -108,7 +136,7 @@ describe('fetchCodeRepos', () => { }); const items = await fetchCodeRepos( - 'github', + platform, [], orgApiUrl, repoApiUrl, @@ -164,7 +192,7 @@ describe('fetchCodeRepos', () => { ]; const items = await fetchCodeRepos( - 'github', + platform, additionalRepos, orgApiUrl, repoApiUrl, @@ -189,8 +217,8 @@ describe('fetchCodeRepos', () => { expect(items.map(i => i.id)).toContain('external-org/external-additional'); }); - // Test that forks and .github repos are excluded from the final list - it('excludes repository targets designated as forks and .github', async () => { + // Test that forks and platform profile repos are excluded from the final list + it('excludes repository targets designated as forks and platform profile repos', async () => { global.fetch.mockResolvedValueOnce({ ok: true, headers: { get: () => null }, @@ -217,8 +245,8 @@ describe('fetchCodeRepos', () => { updated_at: recentDateISO }, { - full_name: 'test-org/.github', - name: '.github', + full_name: `test-org/${platformProfileRepo}`, + name: platformProfileRepo, fork: false, created_at: recentDateISO, updated_at: recentDateISO @@ -231,7 +259,7 @@ describe('fetchCodeRepos', () => { ]; const items = await fetchCodeRepos( - 'github', + platform, additionalRepos, orgApiUrl, repoApiUrl, @@ -242,7 +270,7 @@ describe('fetchCodeRepos', () => { expect(items.map(i => i.id)).toContain('test-org/valid-repo'); expect(items.map(i => i.id)).toContain('test-org/forked-in-list'); expect(items.map(i => i.id)).not.toContain('test-org/forked-repo'); - expect(items.map(i => i.id)).not.toContain('test-org/.github'); + expect(items.map(i => i.id)).not.toContain(`test-org/${platformProfileRepo}`); }); // Test that isNew flag is set correctly based on creation date and refresh interval @@ -267,7 +295,7 @@ describe('fetchCodeRepos', () => { }); const items = await fetchCodeRepos( - 'github', + platform, [], orgApiUrl, repoApiUrl, @@ -292,7 +320,7 @@ describe('fetchCodeRepos', () => { }); const items = await fetchCodeRepos( - 'github', + platform, [], orgApiUrl, repoApiUrl, @@ -302,7 +330,7 @@ describe('fetchCodeRepos', () => { expect(handleError).toHaveBeenCalledWith( expect.any(Error), - expect.stringContaining('Failed to fetch code from github') + expect.stringContaining(`Failed to fetch code from ${platform}`) ); expect(items).toEqual([]); }); From 299ebe1fefc7eddf45644dcbbc3817874e081aa7 Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 17:09:47 -0400 Subject: [PATCH 08/11] Remove extraneous template --- docs/personalization.md | 2 +- public/config-template.yaml | 51 ------------------------------------- 2 files changed, 1 insertion(+), 52 deletions(-) delete mode 100644 public/config-template.yaml diff --git a/docs/personalization.md b/docs/personalization.md index 83332a8..103f640 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -4,7 +4,7 @@ Welcome to your new catalog repo! The primary way to personalize this catalog is ## Primary Configuration File -[**`public/config.yaml`**](../public/config.yaml): This is the main file to edit. It contains all configuration options (e.g., organization names, colors, branding, and API settings) with inline comments explaining each setting. Replace Imageomics-specific values with those appropriate for your organzation and catalog repository. A [template config](../public/config-template.yaml) is also provided for reference. +[**`public/config.yaml`**](../public/config.yaml): This is the main file to edit. It contains all configuration options (e.g., organization names, colors, branding, and API settings) with inline comments explaining each setting. Replace Imageomics-specific values with those appropriate for your organization and catalog repository. ### Organization & Repository Settings diff --git a/public/config-template.yaml b/public/config-template.yaml deleted file mode 100644 index 831ea34..0000000 --- a/public/config-template.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# Configuration file for Catalog Template -# Customize these values to personalize the catalog for your organization - -# Organization & Repository Settings -ORGANIZATION_NAME: imageomics # Codebase platform organization name (for API calls) -HF_ORGANIZATION_NAME: "" # Hugging Face organization name (case-sensitive, for API calls) -ORG_NAME: Imageomics # Display name for Codebase platform organization (can differ from API name) -CATALOG_REPO_NAME: catalog # Repository name for the catalog itself (used for stats badge) - -# Branding -CATALOG_TITLE: '' -CATALOG_DESCRIPTION: "Explore and discover public code, datasets, models, and spaces." -LOGO_URL: "https://github.com/Imageomics/Imageomics-guide/raw/3478acc0068a87a5604069d04a29bdb0795c2045/docs/logos/Imageomics_logo_butterfly.png" -FAVICON_URL: "" - -# Colors (CSS custom properties) -COLORS: - primary: "" # Primary brand color - secondary: "" # Secondary brand color - accent: "" # Accent color - accentDark: "" # Dark mode accent color - tag: "" # Tag background color - -# API & Behavior Settings -# Codebase platform for API calls and link generation. Supported values: "github" or "codeberg", pending: "gitlab". -PLATFORM: github -# Dataset, model, and space (demo) default: Hugging Face, other platforms would require a custom module -API_BASE_URL: "https://huggingface.co/api/" -# Define "new" repository criteria -REFRESH_INTERVAL_DAYS: 30 - -# Array of "owner/repo" strings to include in addition to non-forked org repos. -# Use this for forked repos within the org and repos outside the org entirely. -# ADDITIONAL_REPOS: -# - "user/repo-name" -ADDITIONAL_REPOS: [] - -# Array of Hugging Face repos from outside the org to include. -# Each entry must specify "repo" (owner/name) and "type" (datasets, models, or spaces). -# Organization names are case-sensitive in the Hugging Face API. -# ADDITIONAL_HF_REPOS: -# - repo: "user/dataset-name" -# type: "datasets" -# - repo: "user/model-name" -# type: "models" -# - repo: "user/space-name" -# type: "spaces" -ADDITIONAL_HF_REPOS: [] - -# Typography -FONT_FAMILY: Inter # Font family for the site From 65c937a37dad3fe1d4e0efdbc9dd1c9f851b5eea Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 17:28:50 -0400 Subject: [PATCH 09/11] Remove extra HTML --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index ea08f92..367c169 100644 --- a/index.html +++ b/index.html @@ -29,7 +29,7 @@
+ aria-hidden="true">
From 98d03cac3b90f3f8db9cba3abbdf511f8c8b9fdb Mon Sep 17 00:00:00 2001 From: egrace479 Date: Thu, 9 Jul 2026 17:29:15 -0400 Subject: [PATCH 10/11] Ensure lowercase platform and make const definition more efficient --- src/api/fetchCodeRepos.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/api/fetchCodeRepos.js b/src/api/fetchCodeRepos.js index 113caef..a0f87ea 100644 --- a/src/api/fetchCodeRepos.js +++ b/src/api/fetchCodeRepos.js @@ -46,9 +46,8 @@ export async function fetchCodeRepos( let allRepos = []; let nextUrl = `${orgApiUrl}`; // get platform-specific keys - const platformConfig = PLATFORM_CONFIGS[platform]; - const starsKey = platformConfig.starsKey; - const profileRepo = platformConfig.profileRepo; + const platformConfig = PLATFORM_CONFIGS[platform.toLowerCase()]; + const { starsKey, profileRepo } = platformConfig; try { while (nextUrl) { const ghResponse = await fetch(nextUrl); From 887df31c7146cee718943804db2e03aca51745e2 Mon Sep 17 00:00:00 2001 From: Elizabeth Campolongo <38985481+egrace479@users.noreply.github.com> Date: Fri, 10 Jul 2026 17:45:53 -0400 Subject: [PATCH 11/11] Improve phrasing Co-authored-by: Hilmar Lapp --- docs/personalization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/personalization.md b/docs/personalization.md index 103f640..d8a0756 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -89,6 +89,6 @@ When first setting up your catalog, run the export script to generate a full lis See **[tag-grouping-process.md](tag-grouping-process.md)** for full setup instructions, conventions, and guidance on using AI assistance for the initial grouping pass. -## Non-GitHub Code Platform Setup +## Code Repository Platform Setup -The default code platform for this catalog is GitHub. If you wish to use another supported platform (Codeberg), please note that the [tag export](../scripts/export-tags.js) and [fetch release](../scripts/fetch-releases.js) scripts may require header definition modifications to function properly. Workflows would also require token and other platform-specific updates if running from a non-GitHub repository. Otherwise, this app is set up to be able to run from Codeberg to fetch and display Codeberg repositories. +The default code repository platform for this catalog is GitHub. If you wish to use another supported platform (Codeberg), please note that the [tag export](../scripts/export-tags.js) and [fetch release](../scripts/fetch-releases.js) scripts may require header definition modifications to function properly. Workflows would also require token and other platform-specific updates if running from a non-GitHub repository. Otherwise, this app is set up to be able to run from Codeberg to fetch and display Codeberg repositories.