Skip to content

Dev#395

Merged
DinneK merged 273 commits intomainfrom
dev
Jun 18, 2025
Merged

Dev#395
DinneK merged 273 commits intomainfrom
dev

Conversation

@DinneK
Copy link
Contributor

@DinneK DinneK commented Jun 18, 2025

This is the request to merge dev into main in order to begin packaging the frontend.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit

prettier

[prettier] reported by reviewdog 🐶

projectType: []


[prettier] reported by reviewdog 🐶

document.querySelectorAll('input[name="org-filter"]:checked').forEach(checkbox => {
selectedFiltersObject.organization.push(checkbox.value);
});
document.querySelectorAll('input[name="tier-filter"]:checked').forEach(checkbox => {
selectedFiltersObject.maturityModelTier.push(checkbox.value);
});
document.querySelectorAll('input[name="fisma-level-filter"]:checked').forEach(checkbox => {
selectedFiltersObject.fismaLevel.push(checkbox.value);
});
document.querySelectorAll('input[name="project-type-filter"]:checked').forEach(checkbox => {
selectedFiltersObject.projectType.push(checkbox.value);
});
return selectedFiltersObject;


[prettier] reported by reviewdog 🐶

const selected = getSelectedFilters();
const allProjects = Object.keys(projects).flatMap((org) => projects[org].map((project) => ({...project, org})))


[prettier] reported by reviewdog 🐶

const matchesOrg = selected.organization.length === 0 || selected.organization.includes(project.org);
const matchesTier = selected.maturityModelTier.length === 0 || selected.maturityModelTier.includes("Tier" + project.maturityModelTier);
const matchesFisma = selected.fismaLevel.length === 0 || selected.fismaLevel.includes(project.fismaLevel);
const matchesType = selected.projectType.length === 0 || selected.projectType.includes(project.projectType);
return matchesOrg && matchesTier && matchesFisma && matchesType;
});
updatePagination(filteredProjects);


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶

const selectedFiltersContainer = document.getElementById('filter-tags');
selectedFiltersContainer.innerHTML = '';


[prettier] reported by reviewdog 🐶

const filtersButtonGroup = document.createElement('div');
filtersButtonGroup.className = "usa-button-group";
selectedFiltersContainer.appendChild(filtersButtonGroup);


[prettier] reported by reviewdog 🐶

const filtersArray = selectedFiltersObject[filterCategory];
filtersArray.forEach(filter => {


[prettier] reported by reviewdog 🐶

const filterButton = document.createElement('button');
filterButton.className = 'usa-button margin-bottom-1';
filterButton.textContent = filter;
filtersButtonGroup.appendChild(filterButton);


[prettier] reported by reviewdog 🐶

addGlobalEventListener("click", "#filter-tags .usa-button", e => {
const buttonName = e.target.textContent;
const selectedCheckboxes = document.querySelectorAll("input:checked");
selectedCheckboxes.forEach(checkbox => {
if (buttonName == checkbox.value) {
e.target.remove();
checkbox.checked = false;
updateFilters();
}
})
}, filtersButtonGroup);


[prettier] reported by reviewdog 🐶

const selected = getSelectedFilters();


[prettier] reported by reviewdog 🐶

const projectSections = document.querySelectorAll(".project_section");


[prettier] reported by reviewdog 🐶

const projectCards = section.querySelectorAll(".project-card");


[prettier] reported by reviewdog 🐶

checkFilterCriteria(card, selected);


[prettier] reported by reviewdog 🐶

addFilterButtonGroup(selected);
updateHeadingVisibility();


[prettier] reported by reviewdog 🐶

const cardName = card.querySelector(".usa-card__heading").innerText;
const currentProject = parsedProjectsData.find((project) => project.name === cardName)
const matchesOrganization = selectedFiltersObject.organization.length === 0 || selectedFiltersObject.organization.includes(currentProject.owner);
const projectMaturityModelTier = "Tier " + currentProject.maturityModelTier;
const matchesMaturityModelTier = selectedFiltersObject.maturityModelTier.length === 0 || selectedFiltersObject.maturityModelTier.includes(projectMaturityModelTier);
const matchesFismaLevel = selectedFiltersObject.fismaLevel.length === 0 || selectedFiltersObject.fismaLevel.includes(currentProject.fismaLevel);
const matchesProjectType = selectedFiltersObject.projectType.length === 0 || selectedFiltersObject.projectType.includes(currentProject.projectType);


[prettier] reported by reviewdog 🐶

card.hidden = !(matchesOrganization && matchesMaturityModelTier && matchesFismaLevel && matchesProjectType);


[prettier] reported by reviewdog 🐶

const totalProjects = (filteredProjects || parsedProjectsData).length;
const totalPages = Math.ceil(totalProjects / itemsPerPage);
currentPage = Math.min(currentPage, totalPages || 1);
renderPaginationControls(totalPages);
}


[prettier] reported by reviewdog 🐶

import { reportHeadingTemplate, projectCardTemplate } from "../templates";
import { templateDiv, parsedProjectsData, orgsData, siteData, findObject, baseurl } from "./data";
import { getFilteredProjects } from "./filters";
import { getPageRange, updateHeadingVisibility } from "./utilities";
import DOMPurify from 'dompurify';


[prettier] reported by reviewdog 🐶

const itemsPerPage = 10;


[prettier] reported by reviewdog 🐶

return new Promise(resolve => {
if(parsedProjectsData && parsedProjectsData.length) {
resolve();


[prettier] reported by reviewdog 🐶

if(parsedProjectsData && parsedProjectsData.length) {
clearInterval(checkData);
resolve();


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶

function renderProjectGroups(projects, groupByKey = 'org') {
if(!projects || !projects.length) {
templateDiv.innerHTML = '<p>No Projects Found</p>'


[prettier] reported by reviewdog 🐶

const groupKey = curr[groupByKey];
if(!acc[groupKey]) {
acc[groupKey] = [];


[prettier] reported by reviewdog 🐶

acc[groupKey].push(curr);
return acc
}, {});
for (const org in groupedByOrg) {
const orgProject = findObject(parsedOrgsData, org);
const orgHeading = reportHeadingTemplate(orgProject);
const projectSectionsTemplate = document.createElement('div');
projectSectionsTemplate.className = 'project_section';
templateDiv.append(projectSectionsTemplate);
const reportHeading = document.createElement('div');
reportHeading.className = "report_heading";
reportHeading.innerHTML = DOMPurify.sanitize(orgHeading);
projectSectionsTemplate.appendChild(reportHeading);
const projectCards = document.createElement('ul');
projectCards.className = "usa-card-group flex-align-stretch";
projectSectionsTemplate.appendChild(projectCards);
groupedByOrg[org].forEach(repoData => {
repoData.baseurl = siteData.baseurl;
const projectCard = document.createElement('li');
projectCard.className = 'usa-card project-card tablet:grid-col-12';
projectCard.id = repoData.name;
projectCard.setAttribute('org-name', repoData.owner);
projectCard.innerHTML = DOMPurify.sanitize(projectCardTemplate(repoData));
projectCards.appendChild(projectCard);
});


[prettier] reported by reviewdog 🐶

await ensureReadyData();
templateDiv.innerHTML = ''


[prettier] reported by reviewdog 🐶

const displayProjects = (projects || getFilteredProjects()).slice().sort((a, b) => a.owner.localeCompare(b.owner));


[prettier] reported by reviewdog 🐶

org: project.owner || project.owner


[prettier] reported by reviewdog 🐶

const totalPages = Math.ceil(allProjects.length / itemsPerPage);
if(currentPage < 1 || currentPage > totalPages) {
currentPage = 1;


[prettier] reported by reviewdog 🐶

const startIndex = (currentPage - 1) * itemsPerPage;
const paginatedProjects = allProjects.slice(startIndex, startIndex + itemsPerPage);


[prettier] reported by reviewdog 🐶

renderProjectGroups(paginatedProjects);
updateHeadingVisibility();
renderPaginationControls(allProjects.length);


[prettier] reported by reviewdog 🐶

export const renderPaginatedProjects = createProjectCards;


[prettier] reported by reviewdog 🐶

const paginationDiv = document.getElementById('pagination-controls') || document.createElement('div');
paginationDiv.id = 'pagination-controls';
paginationDiv.className = 'usa-pagination';
paginationDiv.innerHTML = '';
const totalPages = Math.ceil(totalProjectsCount / itemsPerPage);
currentPage = Math.max(1, Math.min(currentPage, totalPages || 1));
const paginationList = document.createElement('ul');
paginationList.className = 'usa-pagination__list';


[prettier] reported by reviewdog 🐶

className: 'usa-pagination__previous-page',
label: 'Previous page',


[prettier] reported by reviewdog 🐶

icon: 'navigate_before',
text: 'Previous',
onclick: () => navigateToPage(currentPage - 1)
});
paginationList.appendChild(prevItem);


[prettier] reported by reviewdog 🐶

const pageRange = getPageRange(currentPage, totalPages, 3);


[prettier] reported by reviewdog 🐶

const isEllipsis = page === '...';
const pageItem = document.createElement('li');
pageItem.className = `usa-pagination__item ${isEllipsis ? 'usa-pagination__overflow' :
'usa-pagination__page-no'}`;


[prettier] reported by reviewdog 🐶

pageItem.innerHTML = `<span aria-label="ellipsis indicating non-visible pages">…</span>`;


[prettier] reported by reviewdog 🐶

const isCurrent = page === currentPage;
const pageButton = document.createElement('a');
pageButton.href = 'javascript:void(0);';
pageButton.className = `usa-pagination__button${isCurrent ? ' usa-current' : ''}`;
pageButton.textContent = page;
pageButton.setAttribute('aria-label', `Page ${page}`);
if (isCurrent) pageButton.setAttribute('aria-current', 'page');
pageButton.addEventListener('click', () => navigateToPage(page));
pageItem.appendChild(pageButton);


[prettier] reported by reviewdog 🐶

paginationList.appendChild(pageItem);
});


[prettier] reported by reviewdog 🐶

className: 'usa-pagination__next-page',
label: 'Next page',


[prettier] reported by reviewdog 🐶

icon: 'navigate_next',
text: 'Next',
onclick: () => navigateToPage(currentPage + 1)
});
paginationList.appendChild(nextItem);


[prettier] reported by reviewdog 🐶

paginationDiv.appendChild(paginationList);


[prettier] reported by reviewdog 🐶

templateDiv.parentElement.appendChild(paginationDiv);


[prettier] reported by reviewdog 🐶

if(page >= 1 && page <= Math.ceil(getFilteredProjects().length / itemsPerPage)) {
currentPage = page;
createProjectCards();


[prettier] reported by reviewdog 🐶

iconPosition = 'before',
onclick


[prettier] reported by reviewdog 🐶

const item = document.createElement('li');
item.className = 'usa-pagination__item usa-pagination__arrow';


[prettier] reported by reviewdog 🐶

const button = document.createElement('a');
button.href = 'javascript:void(0);';
button.className = `usa-pagination__link ${className}`;
button.setAttribute('aria-label', label);
if(disabled) button.classList.add('usa-pagination__disabled');


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶

button.innerHTML = iconPosition === 'before'
? `${iconHtml}<span class="usa-pagination__link-text">${text}</span>`
: `<span class="usa-pagination__link-text">${text}</span>${iconHtml}`;


[prettier] reported by reviewdog 🐶

if(!disabled) {
button.addEventListener('click', onclick);


[prettier] reported by reviewdog 🐶

item.appendChild(button);
return item;


[prettier] reported by reviewdog 🐶

import { sortSelection, filtersContainer } from "./data";
import { addGlobalEventListener } from "./utilities";
import { updateFilters, updateFilteredProjects, getFilteredProjects, setFilteredProjects } from "./filters";
import { renderPaginatedProjects } from "./rendering";


[prettier] reported by reviewdog 🐶

const selection = sortSelection.value;


[prettier] reported by reviewdog 🐶

const targetProjects = getFilteredProjects();


[prettier] reported by reviewdog 🐶

if(["maturity_model_tier", "stargazers_count", "forks_count"].includes(selection)) {
sortByNumberAttribute(targetProjects, selection, isDescending);
} else {
sortByStringAttribute(targetProjects, selection, isDescending);


[prettier] reported by reviewdog 🐶

setFilteredProjects(targetProjects);
renderPaginatedProjects();


[prettier] reported by reviewdog 🐶

const attributeA = a[attribute] !== undefined ? Number(a[attribute]) : Infinity;
const attributeB = b[attribute] !== undefined ? Number(b[attribute]) : Infinity;
return isDescending ? attributeB - attributeA : attributeA - attributeB;
});


[prettier] reported by reviewdog 🐶

const hasAttributeA = typeof a[attribute] === 'string';
const hasAttributeB = typeof b[attribute] === 'string';


[prettier] reported by reviewdog 🐶

return isDescending ? b[attribute].localeCompare(a[attribute]) : a[attribute].localeCompare(b[attribute]);


[prettier] reported by reviewdog 🐶

// If only one object has the attribute, determine order based on `isDescending`
if (hasAttributeA) return isDescending ? 1 : -1;
if (hasAttributeB) return isDescending ? -1 : 1;


[prettier] reported by reviewdog 🐶

return isDescending ? b.name.localeCompare(a.name) : a.name.localeCompare(b.name);
});


[prettier] reported by reviewdog 🐶

addGlobalEventListener('change', '.usa-checkbox__input', e => {


[prettier] reported by reviewdog 🐶

updateFilters();


[prettier] reported by reviewdog 🐶

}, filtersContainer)


[prettier] reported by reviewdog 🐶

import { baseurl } from "./data";


[prettier] reported by reviewdog 🐶

const filterButtons = document.querySelectorAll(".usa-accordion__button");
const isMobile = window.innerWidth < 768;


[prettier] reported by reviewdog 🐶

filterButtons.forEach((button) => {
const contentId = button.getAttribute("aria-controls");
const content = document.getElementById(contentId);
const icon = button.querySelector("svg use");


[prettier] reported by reviewdog 🐶

if(isMobile) {
button.setAttribute("aria-expanded", "false");
content.setAttribute("hidden", "true");
icon.setAttribute("href", `${baseurl}/assets/img/sprite.svg#expand_more`);
} else {
button.setAttribute("aria-expanded", "true");
content.removeAttribute("hidden");
icon.setAttribute("href", `${baseurl}/assets/img/sprite.svg#expand_less`);
}
});
}


[prettier] reported by reviewdog 🐶

updateFilterMenuState()
window.addEventListener("resize", updateFilterMenuState)


[prettier] reported by reviewdog 🐶

document.querySelectorAll(".usa-accordion__button").forEach((button) => {
button.addEventListener("click", () => {
const expanded = button.getAttribute("aria-expanded");
const content = document.getElementById(button.getAttribute("id"));
const icon = button.querySelector("svg use");
if(expanded === 'false') {
content.removeAttribute("hidden");
icon.setAttribute("href", `${baseurl}/assets/img/sprite.svg#expand_less`);
} else {
content.setAttribute("hidden", "true");
icon.setAttribute("href", `${baseurl}/assets/img/sprite.svg#expand_more`);
}
});
});
}


[prettier] reported by reviewdog 🐶

export function addGlobalEventListener(type, selector, callback, parent = document) {
parent.addEventListener(type, e => {


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶

const range = [];
const start = Math.max(2, currentPage - visibleRange);
const end = Math.min(totalPages - 1, currentPage + visibleRange);


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶

if (start > 2) range.push('...');


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶

if (end < totalPages - 1) range.push('...');


[prettier] reported by reviewdog 🐶

if (totalPages > 1) range.push(totalPages);


[prettier] reported by reviewdog 🐶


[prettier] reported by reviewdog 🐶

const projectSections = document.querySelectorAll(".project_section");
projectSections.forEach(section => {
let hasVisibleCard = false;


[prettier] reported by reviewdog 🐶

let reportHeading = section.querySelector('.report_heading');


[prettier] reported by reviewdog 🐶

let projectCards = section.querySelectorAll('.project-card');


[prettier] reported by reviewdog 🐶

hasVisibleCard = true;


[prettier] reported by reviewdog 🐶

// Hide heading if all cards under section are hidden
reportHeading.hidden = !hasVisibleCard;
});


[prettier] reported by reviewdog 🐶

import { createProjectCards } from "./modules/rendering";
import { updateFilteredProjects } from "./modules/filters";
import { setupEventListeners } from './modules/events';
import { setupFilterMenuListeners } from "./modules/ui";


[prettier] reported by reviewdog 🐶

await createProjectCards();
updateFilteredProjects();
setupEventListeners();
}, 50);


[prettier] reported by reviewdog 🐶

setupFilterMenuListeners();
});


[prettier] reported by reviewdog 🐶

export const reportHeadingTemplate = function(data) {
return `

Copy link
Collaborator

@natalialuzuriaga natalialuzuriaga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran locally and everything LGTM!

@DinneK DinneK merged commit 9977b7b into main Jun 18, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants