Skip to content

Commit 6a6e23f

Browse files
committed
Merge remote-tracking branch 'upstream/main' into fix-7284-footer-i18n
2 parents 0a7c55b + 24ce401 commit 6a6e23f

18 files changed

Lines changed: 805 additions & 38 deletions

.github/scripts/issue-management/claim-handler.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,13 @@ async function handleClaim({ github, context }) {
2828
return;
2929
}
3030

31-
const issueAuthor = context.payload.issue.user.login;
32-
33-
const MAINTAINERS = ['jhasourav07', 'aamod-dev', 'souravjhahind'];
34-
const isOpenedByMaintainer = MAINTAINERS.includes(issueAuthor.toLowerCase());
35-
36-
if (!isOpenedByMaintainer && commenter.toLowerCase() !== issueAuthor.toLowerCase()) {
37-
await github.rest.issues.createComment({
38-
owner,
39-
repo,
40-
issue_number: issueNumber,
41-
body: `❌ Only the author of this issue (@${issueAuthor}) can claim it.`,
42-
});
43-
return;
44-
}
45-
46-
// Re-fetch to avoid stale assignee data from the webhook payload
31+
// Re-fetch to avoid stale issue/assignee/state data from the webhook payload
4732
const { data: freshIssue } = await github.rest.issues.get({
4833
owner,
4934
repo,
5035
issue_number: issueNumber,
5136
});
37+
5238
const currentAssignees = freshIssue.assignees.map((a) => a.login.toLowerCase());
5339

5440
if (currentAssignees.length > 0) {
@@ -71,6 +57,38 @@ async function handleClaim({ github, context }) {
7157
return;
7258
}
7359

60+
const issueAuthor = freshIssue.user.login;
61+
const issueAuthorLower = issueAuthor.toLowerCase();
62+
const commenterLower = commenter.toLowerCase();
63+
64+
const MAINTAINERS = ['jhasourav07', 'aamod-dev', 'souravjhahind'];
65+
const isOpenedByMaintainer = MAINTAINERS.includes(issueAuthorLower);
66+
67+
// Check if the issue is older than 1 week (7 days)
68+
const createdAt = new Date(freshIssue.created_at);
69+
const now = new Date();
70+
const ageInMs = now.getTime() - createdAt.getTime();
71+
const oneWeekInMs = 7 * 24 * 60 * 60 * 1000;
72+
const isOlderThanOneWeek = ageInMs > oneWeekInMs;
73+
74+
// Check if opened by any other person other than jhasourav07 or aamod007 (and aamod-dev for safety)
75+
const isOpenedByOther = !['jhasourav07', 'aamod007', 'aamod-dev'].includes(issueAuthorLower);
76+
77+
const isAuthor = commenterLower === issueAuthorLower;
78+
const canClaimOlderIssue = isOpenedByOther && isOlderThanOneWeek;
79+
80+
const isAllowedToClaim = isAuthor || isOpenedByMaintainer || canClaimOlderIssue;
81+
82+
if (!isAllowedToClaim) {
83+
await github.rest.issues.createComment({
84+
owner,
85+
repo,
86+
issue_number: issueNumber,
87+
body: `❌ Only the author of this issue (@${issueAuthor}) can claim it.`,
88+
});
89+
return;
90+
}
91+
7492
const existingIssues = await findExistingAssignments(github, owner, repo, commenter, issueNumber);
7593
if (existingIssues.length >= MAX_ASSIGNED_ISSUES) {
7694
const issueList = existingIssues

CONTRIBUTING.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ To maintain high quality in our codebase, we use structured **Issue Templates**
412412
- **🐛 Bug Report Template**: For reporting visual glitches, API errors, or unexpected behavior.
413413
- **✨ Feature Request Template**: For suggesting new isometric monolith designs, themes, or time/accuracy improvements.
414414

415-
By using these templates, you provide maintainers with clear details and context. Since you authored the issue, you can immediately claim it for yourself by commenting `/claim`! (Note: Issues authored by `jhasourav07` can be claimed by anyone).
415+
By using these templates, you provide maintainers with clear details and context. Since you authored the issue, you can immediately claim it for yourself by commenting `/claim`! (Note: Issues authored by `jhasourav07` can be claimed by anyone immediately. Additionally, if an issue is opened by anyone other than `jhasourav07` or `aamod007`, is older than 1 week, and has no assignees, any contributor can claim it).
416416

417417
### 🔍 Semantic Duplicate Detection
418418

@@ -427,13 +427,13 @@ To help maintainers keep the repository organized and prevent multiple contribut
427427

428428
Our automation runs entirely through issue comments. Here is how you interact with it:
429429

430-
| Command | Who Can Use It? | What It Does |
431-
| ----------------------------- | ------------------------------------------------------- | --------------------------------------------------------- |
432-
| `/claim` | **Issue Author (or Anyone if authored by jhasourav07)** | Self-assigns the issue to you. |
433-
| `/unclaim` | **Assigned Contributor** | Removes the assignment from yourself (opens it back up). |
434-
| `/addlabel <label1> <label2>` | **Anyone** | Adds labels to the issue (e.g. `/addlabel frontend bug`). |
435-
| `/unassign @username` | **Maintainers Only** | Removes the assignee from an issue. |
436-
| `/assign @username` | **Maintainers Only** | Manually assigns someone to an issue. |
430+
| Command | Who Can Use It? | What It Does |
431+
| ----------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
432+
| `/claim` | **Issue Author (or Anyone if authored by jhasourav07, or Anyone if older than 1 week with no assignees)** | Self-assigns the issue to you. |
433+
| `/unclaim` | **Assigned Contributor** | Removes the assignment from yourself (opens it back up). |
434+
| `/addlabel <label1> <label2>` | **Anyone** | Adds labels to the issue (e.g. `/addlabel frontend bug`). |
435+
| `/unassign @username` | **Maintainers Only** | Removes the assignee from an issue. |
436+
| `/assign @username` | **Maintainers Only** | Manually assigns someone to an issue. |
437437

438438
### ⏳ The Inactivity Policy (Assignment Expiry)
439439

@@ -458,7 +458,7 @@ If the bot rejects your command, check these common scenarios:
458458
- **"Commands cannot be used on closed issues"**: You cannot claim, assign, or unassign on closed issues. Find an open one!
459459
- **"You already have X/5 active assigned issues"**: You have reached the maximum of 5 concurrent assignments. Finish one of your current tasks before claiming a new issue. If you're stuck, use the `/unclaim` command to unassign yourself from an issue, or ask a maintainer to `/unassign` you.
460460
- **"This issue is already assigned to @username"**: Be faster next time! Look for issues without assignees.
461-
- **"Only the author of this issue can claim it"**: You tried to `/claim` an issue you did not create. You can only claim issues that you authored (unless the issue was authored by `jhasourav07`, which anyone can claim).
461+
- **"Only the author of this issue can claim it"**: You tried to `/claim` an issue you did not create. You can only claim issues that you authored (unless the issue is older than 1 week with no assignees, or was authored by `jhasourav07`, which anyone can claim).
462462
- **"The following label(s) do not exist"**: You can only add existing repo labels. The bot will reply with a list of valid labels you can use.
463463
- **"You don't have permission"**: You tried to use `/assign` or `/unassign`. Please use `/claim` instead.
464464

app/components/Footer.error-resilience.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ vi.mock('lucide-react', () => ({
4848
BookOpen: () => null,
4949
GitBranch: () => null,
5050
HelpCircle: () => null,
51+
Shield: () => <div>Shield</div>,
52+
FileText: () => <div>FileText</div>,
5153
}));
5254

5355
vi.mock('react-icons/fa', () => ({

app/components/Footer.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
BookOpen,
1313
GitBranch,
1414
HelpCircle,
15+
Shield,
16+
FileText,
1517
} from 'lucide-react';
1618
import { FaGithub, FaDiscord, FaLinkedin } from 'react-icons/fa';
1719
import { FaXTwitter } from 'react-icons/fa6';
@@ -92,6 +94,8 @@ const RESOURCE_ICON_MAP: Record<string, React.ReactNode> = {
9294
github_repo: <GitBranch size={15} className="shrink-0" />,
9395
guidelines: <BookOpen size={15} className="shrink-0" />,
9496
faq: <HelpCircle size={15} className="shrink-0" />,
97+
privacy: <Shield size={15} className="shrink-0" />,
98+
terms: <FileText size={15} className="shrink-0" />,
9599
};
96100

97101
export function Footer() {
@@ -128,6 +132,16 @@ export function Footer() {
128132
href: '/support',
129133
isExternal: false,
130134
},
135+
{
136+
label: t('footer.privacy'),
137+
href: '/privacy',
138+
isExternal: false,
139+
},
140+
{
141+
label: t('footer.terms'),
142+
href: '/terms',
143+
isExternal: false,
144+
},
131145
];
132146

133147
const socialLinks: SocialLink[] = [
@@ -207,6 +221,8 @@ export function Footer() {
207221
if (link.href.includes('README')) iconKey = 'documentation';
208222
else if (link.href.includes('CODE_OF_CONDUCT') || link.href.includes('guidelines'))
209223
iconKey = 'guidelines';
224+
else if (link.href === '/privacy') iconKey = 'privacy';
225+
else if (link.href === '/terms') iconKey = 'terms';
210226
else if (link.href.includes('support') || link.href.includes('faq'))
211227
iconKey = 'faq';
212228

app/components/navbar.responsive-breakpoints.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,14 @@ describe('Navbar Responsive Breakpoints & Menu Toggle', () => {
142142
expect(screen.getByRole('button', { name: 'Open menu' })).toBeDefined();
143143
});
144144

145-
it('4. Hides the desktop nav row on mobile and only reveals mobile hamburger controls, via complementary md: classes', () => {
145+
it('4. Hides the desktop nav row on mobile and only reveals mobile hamburger controls, via complementary lg: classes', () => {
146146
const { container } = render(<Navbar />);
147147

148-
const desktopNavRow = container.querySelector('.hidden.items-center.gap-2.md\\:flex');
148+
const desktopNavRow = container.querySelector('.hidden.items-center.gap-2.lg\\:flex');
149149
expect(desktopNavRow).toBeInTheDocument();
150150

151151
const mobileControls = container.querySelector(
152-
'.md\\:hidden.inline-flex.items-center.justify-center.gap-1'
152+
'.lg\\:hidden.inline-flex.items-center.justify-center.gap-1'
153153
);
154154
expect(mobileControls).toBeInTheDocument();
155155
});

0 commit comments

Comments
 (0)