Copilot commented on code in PR #464:
URL: https://github.com/apache/casbin-website/pull/464#discussion_r3074336189
##########
src/theme/Footer/Links/MultiColumn/index.js:
##########
@@ -0,0 +1,75 @@
+import React from "react";
+import clsx from "clsx";
+import {ThemeClassNames} from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import FooterMoreBadges from "@site/src/components/FooterMoreBadges";
+
+function ColumnLinkItem({item}) {
+ return item.html ? (
+ <li
+ className={clsx("footer__item", item.className)}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <li key={item.href ?? item.to} className="footer__item">
+ <LinkItem item={item} />
+ </li>
Review Comment:
For non-HTML items, `item.className` is currently not applied in either
`ColumnLinkItem` (line 16) or `CustomColumnItem` (line 31). This is an
observable styling regression vs the HTML branch (lines 10/25). Use
`clsx(\"footer__item\", item.className)` (or equivalent) in the non-HTML
branches as well, and consider removing the redundant `key` on the `<li>` since
keys are already provided by the parent map.
##########
src/theme/Footer/Links/MultiColumn/index.js:
##########
@@ -0,0 +1,75 @@
+import React from "react";
+import clsx from "clsx";
+import {ThemeClassNames} from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import FooterMoreBadges from "@site/src/components/FooterMoreBadges";
+
+function ColumnLinkItem({item}) {
+ return item.html ? (
+ <li
+ className={clsx("footer__item", item.className)}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <li key={item.href ?? item.to} className="footer__item">
+ <LinkItem item={item} />
+ </li>
+ );
+}
+
+function CustomColumnItem({item}) {
+ return item.html ? (
+ <div
+ className={item.className}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <div className="footer__item">
+ <LinkItem item={item} />
+ </div>
+ );
+}
+
+function Column({column}) {
+ const isFooterMoreColumn =
column.className?.split(/\s+/u).includes("footer-more-column");
+
+ return (
+ <div
+ className={clsx(
+ ThemeClassNames.layout.footer.column,
+ "col footer__col",
+ column.className
+ )}
+ >
+ <div className="footer__title">{column.title}</div>
+ {isFooterMoreColumn ? (
+ <>
+ <FooterMoreBadges />
+ {column.items.map((item, index) => (
+ <CustomColumnItem key={index} item={item} />
+ ))}
Review Comment:
These maps use array indices as React keys, which can cause unnecessary
remounts and subtle UI issues when items are reordered/inserted. Prefer stable
semantic keys (e.g., `column.title` or another unique column identifier, and
`item.href ?? item.to` for link items / a stable id for HTML items) where
possible.
##########
src/theme/Footer/Links/MultiColumn/index.js:
##########
@@ -0,0 +1,75 @@
+import React from "react";
+import clsx from "clsx";
+import {ThemeClassNames} from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import FooterMoreBadges from "@site/src/components/FooterMoreBadges";
+
+function ColumnLinkItem({item}) {
+ return item.html ? (
+ <li
+ className={clsx("footer__item", item.className)}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <li key={item.href ?? item.to} className="footer__item">
+ <LinkItem item={item} />
+ </li>
+ );
+}
+
+function CustomColumnItem({item}) {
+ return item.html ? (
+ <div
+ className={item.className}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <div className="footer__item">
+ <LinkItem item={item} />
+ </div>
Review Comment:
For non-HTML items, `item.className` is currently not applied in either
`ColumnLinkItem` (line 16) or `CustomColumnItem` (line 31). This is an
observable styling regression vs the HTML branch (lines 10/25). Use
`clsx(\"footer__item\", item.className)` (or equivalent) in the non-HTML
branches as well, and consider removing the redundant `key` on the `<li>` since
keys are already provided by the parent map.
##########
src/theme/Footer/Links/MultiColumn/index.js:
##########
@@ -0,0 +1,75 @@
+import React from "react";
+import clsx from "clsx";
+import {ThemeClassNames} from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import FooterMoreBadges from "@site/src/components/FooterMoreBadges";
+
+function ColumnLinkItem({item}) {
+ return item.html ? (
+ <li
+ className={clsx("footer__item", item.className)}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <li key={item.href ?? item.to} className="footer__item">
+ <LinkItem item={item} />
+ </li>
+ );
+}
+
+function CustomColumnItem({item}) {
+ return item.html ? (
+ <div
+ className={item.className}
Review Comment:
For non-HTML items, `item.className` is currently not applied in either
`ColumnLinkItem` (line 16) or `CustomColumnItem` (line 31). This is an
observable styling regression vs the HTML branch (lines 10/25). Use
`clsx(\"footer__item\", item.className)` (or equivalent) in the non-HTML
branches as well, and consider removing the redundant `key` on the `<li>` since
keys are already provided by the parent map.
##########
src/theme/Footer/Links/MultiColumn/index.js:
##########
@@ -0,0 +1,75 @@
+import React from "react";
+import clsx from "clsx";
+import {ThemeClassNames} from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import FooterMoreBadges from "@site/src/components/FooterMoreBadges";
+
+function ColumnLinkItem({item}) {
+ return item.html ? (
+ <li
+ className={clsx("footer__item", item.className)}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <li key={item.href ?? item.to} className="footer__item">
+ <LinkItem item={item} />
+ </li>
+ );
+}
+
+function CustomColumnItem({item}) {
+ return item.html ? (
+ <div
+ className={item.className}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <div className="footer__item">
+ <LinkItem item={item} />
+ </div>
+ );
+}
+
+function Column({column}) {
+ const isFooterMoreColumn =
column.className?.split(/\s+/u).includes("footer-more-column");
+
+ return (
+ <div
+ className={clsx(
+ ThemeClassNames.layout.footer.column,
+ "col footer__col",
+ column.className
+ )}
+ >
+ <div className="footer__title">{column.title}</div>
+ {isFooterMoreColumn ? (
+ <>
+ <FooterMoreBadges />
+ {column.items.map((item, index) => (
+ <CustomColumnItem key={index} item={item} />
+ ))}
+ </>
+ ) : (
+ <ul className="footer__items clean-list">
+ {column.items.map((item, index) => (
+ <ColumnLinkItem key={index} item={item} />
+ ))}
Review Comment:
These maps use array indices as React keys, which can cause unnecessary
remounts and subtle UI issues when items are reordered/inserted. Prefer stable
semantic keys (e.g., `column.title` or another unique column identifier, and
`item.href ?? item.to` for link items / a stable id for HTML items) where
possible.
##########
src/theme/Footer/Links/MultiColumn/index.js:
##########
@@ -0,0 +1,75 @@
+import React from "react";
+import clsx from "clsx";
+import {ThemeClassNames} from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import FooterMoreBadges from "@site/src/components/FooterMoreBadges";
+
+function ColumnLinkItem({item}) {
+ return item.html ? (
+ <li
+ className={clsx("footer__item", item.className)}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <li key={item.href ?? item.to} className="footer__item">
+ <LinkItem item={item} />
+ </li>
+ );
+}
+
+function CustomColumnItem({item}) {
+ return item.html ? (
+ <div
+ className={item.className}
+ // Developer provided the HTML, so assume it's safe.
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{__html: item.html}}
+ />
+ ) : (
+ <div className="footer__item">
+ <LinkItem item={item} />
+ </div>
+ );
+}
+
+function Column({column}) {
+ const isFooterMoreColumn =
column.className?.split(/\s+/u).includes("footer-more-column");
+
+ return (
+ <div
+ className={clsx(
+ ThemeClassNames.layout.footer.column,
+ "col footer__col",
+ column.className
+ )}
+ >
+ <div className="footer__title">{column.title}</div>
+ {isFooterMoreColumn ? (
+ <>
+ <FooterMoreBadges />
+ {column.items.map((item, index) => (
+ <CustomColumnItem key={index} item={item} />
+ ))}
+ </>
+ ) : (
+ <ul className="footer__items clean-list">
+ {column.items.map((item, index) => (
+ <ColumnLinkItem key={index} item={item} />
+ ))}
+ </ul>
+ )}
+ </div>
+ );
+}
+
+export default function FooterLinksMultiColumn({columns}) {
+ return (
+ <div className="row footer__links">
+ {columns.map((column, index) => (
+ <Column key={index} column={column} />
+ ))}
Review Comment:
These maps use array indices as React keys, which can cause unnecessary
remounts and subtle UI issues when items are reordered/inserted. Prefer stable
semantic keys (e.g., `column.title` or another unique column identifier, and
`item.href ?? item.to` for link items / a stable id for HTML items) where
possible.
##########
src/theme/Footer/Links/MultiColumn/index.js:
##########
@@ -0,0 +1,75 @@
+import React from "react";
+import clsx from "clsx";
+import {ThemeClassNames} from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import FooterMoreBadges from "@site/src/components/FooterMoreBadges";
+
+function ColumnLinkItem({item}) {
+ return item.html ? (
+ <li
+ className={clsx("footer__item", item.className)}
Review Comment:
For non-HTML items, `item.className` is currently not applied in either
`ColumnLinkItem` (line 16) or `CustomColumnItem` (line 31). This is an
observable styling regression vs the HTML branch (lines 10/25). Use
`clsx(\"footer__item\", item.className)` (or equivalent) in the non-HTML
branches as well, and consider removing the redundant `key` on the `<li>` since
keys are already provided by the parent map.
##########
.github/workflows/pr_ci.yml:
##########
@@ -22,5 +22,8 @@ jobs:
- name: Install dependencies
run: yarn install
+ - name: Generate footer stars
Review Comment:
This step hits the GitHub API; without authentication it’s more likely to be
rate-limited or intermittently fail (you fall back to existing JSON, but it
will still log errors and may reduce signal in CI). Consider passing
`GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}` as an env var for this step to
increase rate limits and stability.
##########
src/components/FooterMoreBadges/stars.json:
##########
@@ -0,0 +1,13 @@
+{
+ "generatedAt": "2026-04-13T13:15:04.436Z",
Review Comment:
Because `stars.json` is checked into the repo and also regenerated in CI,
the `generatedAt` field will change on every successful run, which encourages
noisy diffs and accidental commits after local builds. Consider omitting
`generatedAt` from the tracked file (or moving it to an untracked/generated
artifact) if it’s not used by the UI.
##########
scripts/generate-footer-stars.js:
##########
@@ -0,0 +1,90 @@
+const fs = require("fs");
+const path = require("path");
+
+const badges = require("../src/components/FooterMoreBadges/badges.json");
+
+const outputPath = path.join(
+ __dirname,
+ "..",
+ "src",
+ "components",
+ "FooterMoreBadges",
+ "stars.json"
+);
+
+function getRepoKey(owner, repo) {
+ return `${owner}/${repo}`;
+}
+
+function readExistingStars() {
+ if (!fs.existsSync(outputPath)) {
+ return null;
+ }
+
+ try {
+ return JSON.parse(fs.readFileSync(outputPath, "utf8"));
+ } catch {
+ return null;
+ }
+}
+
+async function fetchStars() {
+ const headers = {
+ Accept: "application/vnd.github+json",
+ "User-Agent": "casbin-website-footer-stars",
+ };
+
+ if (process.env.GITHUB_TOKEN) {
+ headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
+ }
+
+ const results = await Promise.all(
+ badges.map(async({owner, repo}) => {
+ const response = await
fetch(`https://api.github.com/repos/${owner}/${repo}`, {
+ headers,
+ });
Review Comment:
This script calls `fetch(...)` but doesn’t define/import it. That will crash
on Node runtimes where `fetch` isn’t available globally (notably Node < 18).
Either import a fetch implementation (e.g., via undici/node-fetch) in this
script, or enforce a Node >= 18 runtime explicitly in the GitHub Actions
workflows that run `generate:footer-stars`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]