Skip to content
Merged
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ The .env_sample file shows the necessary configuration keywords, including
a personal access token for GitHub API access and the target GitHub
repository name.

To create a GitHub API token, open your personal GitHub Settings, and select "Developer Settings" from the sidebar. Open "Personal access tokens" and select "Tokens (classic)"

Click on "Generate new token" and select the "Generate new token (classic)" option from the pulldown. You can set a Note to identify this particular token. Select the Expiration (30 days default), and "repo". Make sure you copy and save the generated token right away, because you can't display it again.

#### Frontend

```bash
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/CommentCard.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ describe('CommentCard', () => {
render(<CommentCard comment={mockComment} />);

await user.click(screen.getByRole('button', { name: 'Edit comment' }));
expect(screen.getByText('Edit comment')).toBeInTheDocument();
expect(
screen.getByRole('heading', { name: 'Edit comment' })
).toBeInTheDocument();
expect(screen.getByPlaceholderText('Write markdown…')).toHaveValue(
mockComment.body
);
Expand Down
15 changes: 11 additions & 4 deletions frontend/src/components/ProjectStatusPanel.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Generated-by: Cursor
// Assisted-by: openai-code-assist
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
Alert,
Expand Down Expand Up @@ -165,8 +166,8 @@ const StatusSection = ({
const ProjectStatusPanel = () => {
const initial = useMemo(() => getInitialDateRange(), []);

const [startDate, setStartDate] = useState(initial.start);
const [endDate, setEndDate] = useState(initial.end);
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const [draftStartDate, setDraftStartDate] = useState(initial.start);
const [draftEndDate, setDraftEndDate] = useState(initial.end);
const [loading, setLoading] = useState(false);
Expand All @@ -188,10 +189,16 @@ const ProjectStatusPanel = () => {
}, []);

useEffect(() => {
if (!startDate || !endDate) {
return;
}
load(startDate, endDate);
}, [startDate, endDate, load]);

useEffect(() => {
if (!startDate || !endDate) {
return;
}
try {
localStorage.setItem(STORAGE_START_KEY, startDate);
localStorage.setItem(STORAGE_END_KEY, endDate);
Expand All @@ -202,8 +209,8 @@ const ProjectStatusPanel = () => {

const onApply = () => {
if (draftStartDate > draftEndDate) {
setDraftStartDate(startDate);
setDraftEndDate(endDate);
setDraftStartDate(startDate ?? initial.start);
setDraftEndDate(endDate ?? initial.end);
return;
}
setStartDate(draftStartDate);
Expand Down
22 changes: 14 additions & 8 deletions frontend/src/components/ProjectStatusPanel.test.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Generated-by: Cursor
// Assisted-by: openai-code-assist
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
Expand Down Expand Up @@ -59,8 +60,12 @@ describe('ProjectStatusPanel', () => {
});

it('loads report and renders linked rows', async () => {
const user = userEvent.setup();
render(<ProjectStatusPanel />);

expect(api.fetchProjectStatusReport).not.toHaveBeenCalled();
await user.click(screen.getByRole('button', { name: 'Apply' }));

await waitFor(() => {
expect(api.fetchProjectStatusReport).toHaveBeenCalledWith(
'2025-04-03',
Expand All @@ -81,6 +86,7 @@ describe('ProjectStatusPanel', () => {
});

it('shows days since update in PR backlog section', async () => {
const user = userEvent.setup();
api.fetchProjectStatusReport.mockResolvedValue({
start_date: '2025-04-04',
end_date: '2025-04-10',
Expand All @@ -100,6 +106,8 @@ describe('ProjectStatusPanel', () => {
],
});
render(<ProjectStatusPanel />);
expect(api.fetchProjectStatusReport).not.toHaveBeenCalled();
await user.click(screen.getByRole('button', { name: 'Apply' }));
await waitFor(() => {
expect(screen.getByText('Stale open')).toBeInTheDocument();
});
Expand All @@ -110,6 +118,9 @@ describe('ProjectStatusPanel', () => {
const user = userEvent.setup();
render(<ProjectStatusPanel />);

expect(api.fetchProjectStatusReport).not.toHaveBeenCalled();
await user.click(screen.getByRole('button', { name: 'Apply' }));

await waitFor(() => {
expect(
screen.getByRole('button', {
Expand Down Expand Up @@ -160,10 +171,7 @@ describe('ProjectStatusPanel', () => {
});

render(<ProjectStatusPanel />);

await waitFor(() => {
expect(api.fetchProjectStatusReport).toHaveBeenCalled();
});
expect(api.fetchProjectStatusReport).not.toHaveBeenCalled();

await user.clear(screen.getByLabelText('Starting'));
await user.type(screen.getByLabelText('Starting'), '2025-04-01');
Expand Down Expand Up @@ -200,15 +208,13 @@ describe('ProjectStatusPanel', () => {

render(<ProjectStatusPanel />);

await waitFor(() => {
expect(api.fetchProjectStatusReport).toHaveBeenCalledTimes(1);
});
expect(api.fetchProjectStatusReport).not.toHaveBeenCalled();

await user.click(screen.getByRole('button', { name: 'Today' }));

expect(screen.getByLabelText('Starting')).toHaveValue(start);
expect(screen.getByLabelText('Ending')).toHaveValue(today);
expect(api.fetchProjectStatusReport).toHaveBeenCalledTimes(1);
expect(api.fetchProjectStatusReport).not.toHaveBeenCalled();
expect(localStorage.getItem(STORAGE_START_KEY)).toBe('2025-04-03');
expect(localStorage.getItem(STORAGE_END_KEY)).toBe('2025-04-10');

Expand Down
Loading