Skip to content
This repository was archived by the owner on Feb 11, 2026. It is now read-only.
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
66 changes: 33 additions & 33 deletions src/app/login/githublogin.css
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
a {
color: white; /* Change the text color to white */
text-decoration: underline; /* Ensure the text is underlined */
color: white; /* Change the text color to white */
text-decoration: underline; /* Ensure the text is underlined */
}

.login-page-background {
background-image: url('../../../public/InstructLab-Background-Image.png');
/* Replace with your background image URL */
background-size: cover;
background-position: center;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-image: url('../../../public/InstructLab-Background-Image.png');
/* Replace with your background image URL */
background-size: cover;
background-position: center;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}

.login-container {
text-align: center;
text-align: center;
}

.sign-in-text {
margin-top: 1rem;
color: white;
padding: 20px;
text-align: center;
font-size: xx-large;
margin-top: 1rem;
color: white;
padding: 20px;
text-align: center;
font-size: xx-large;
}

.description-text {
margin-top: 1rem;
color: white;
padding-bottom: 50px;
font-size: x-large;
font-style: italic;
text-align: center;
margin-top: 1rem;
color: white;
padding-bottom: 50px;
font-size: x-large;
font-style: italic;
text-align: center;
}

.urls-text {
margin-top: 1rem;
color: white;
padding: 20px;
text-align: center;
font-size: large;
margin-top: 1rem;
color: white;
padding: 20px;
text-align: center;
font-size: large;
}

.policy-text {
margin-top: 1rem;
color: white;
padding-top: 20px;
text-align: center;
font-size: large;
}
margin-top: 1rem;
color: white;
padding-top: 20px;
text-align: center;
font-size: large;
}
131 changes: 45 additions & 86 deletions src/components/Dashboard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// src/app/dashboard/page.tsx
'use client';

import * as React from 'react';
import { useSession } from 'next-auth/react';
import { Button } from '@patternfly/react-core/dist/dynamic/components/Button';
import { useRouter } from 'next/navigation';
import { Chip } from '@patternfly/react-core/dist/dynamic/components/Chip';
import { Label } from '@patternfly/react-core/dist/dynamic/components/Label';
import { PageSection } from '@patternfly/react-core/dist/dynamic/components/Page';
import { Title } from '@patternfly/react-core/dist/dynamic/components/Title';
import { Table, Thead, Tr, Th, Td, Tbody, ThProps } from '@patternfly/react-table';
import { Card, CardTitle, CardBody } from '@patternfly/react-core/dist/dynamic/components/Card';
import { Stack, StackItem } from '@patternfly/react-core/dist/dynamic/layouts/Stack';
import { Flex, FlexItem } from '@patternfly/react-core/dist/dynamic/layouts/Flex';
import { useRouter } from 'next/navigation';
import { fetchPullRequests, getGitHubUsername } from '../../utils/github';
import { PullRequest } from '../../types';

Expand All @@ -17,8 +16,6 @@ const Index: React.FunctionComponent = () => {
const [pullRequests, setPullRequests] = React.useState<PullRequest[]>([]);
const [username, setUsername] = React.useState<string | null>(null);
const [error, setError] = React.useState<string | null>(null);
const [activeSortIndex, setActiveSortIndex] = React.useState<number | undefined>(undefined);
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc' | undefined>(undefined);
const router = useRouter();

const fetchAndSetPullRequests = React.useCallback(async () => {
Expand All @@ -30,7 +27,11 @@ const Index: React.FunctionComponent = () => {
const filteredPRs = data.filter(
(pr: PullRequest) => pr.user.login === fetchedUsername && pr.labels.some((label) => label.name === 'skill' || label.name === 'knowledge')
);
setPullRequests(filteredPRs);

// Sort by date (newest first)
const sortedPRs = filteredPRs.sort((a: PullRequest, b: PullRequest) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());

setPullRequests(sortedPRs);
} catch (error) {
setError('Failed to fetch pull requests.');
}
Expand All @@ -43,39 +44,6 @@ const Index: React.FunctionComponent = () => {
return () => clearInterval(intervalId);
}, [session, fetchAndSetPullRequests]);

const getSortableRowValues = (pr: PullRequest): (string | number)[] => {
const labels = pr.labels.map((label) => label.name).join(', ');
return [pr.title, pr.user.login, pr.state, new Date(pr.created_at).getTime(), new Date(pr.updated_at).getTime(), labels];
};

let sortedPullRequests = pullRequests;
if (activeSortIndex !== undefined) {
sortedPullRequests = pullRequests.sort((a, b) => {
const aValue = getSortableRowValues(a)[activeSortIndex];
const bValue = getSortableRowValues(b)[activeSortIndex];

if (typeof aValue === 'number' && typeof bValue === 'number') {
return activeSortDirection === 'asc' ? aValue - bValue : bValue - aValue;
} else if (typeof aValue === 'string' && typeof bValue === 'string') {
return activeSortDirection === 'asc' ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
}

return 0;
});
}

const getSortParams = (columnIndex: number): ThProps['sort'] => ({
sortBy: {
index: activeSortIndex,
direction: activeSortDirection
},
onSort: (_event, index, direction) => {
setActiveSortIndex(index);
setActiveSortDirection(direction as 'asc' | 'desc');
},
columnIndex
});

const handleEditClick = (pr: PullRequest) => {
const hasKnowledgeLabel = pr.labels.some((label) => label.name === 'knowledge');
const hasSkillLabel = pr.labels.some((label) => label.name === 'skill');
Expand All @@ -98,50 +66,41 @@ const Index: React.FunctionComponent = () => {
</Title>
<div style={{ marginBottom: '20px' }} />
{error && <div>{error}</div>}
<Table aria-label="Pull Requests">
<Thead>
<Tr>
<Th sort={getSortParams(0)}>Title</Th>
<Th sort={getSortParams(1)}>Author</Th>
<Th sort={getSortParams(2)}>State</Th>
<Th sort={getSortParams(3)}>Created At</Th>
<Th sort={getSortParams(4)}>Updated At</Th>
<Th>Link</Th>
<Th sort={getSortParams(5)}>Labels</Th>
<Th>Actions</Th>
</Tr>
</Thead>
<Tbody>
{sortedPullRequests.map((pr) => (
<Tr key={pr.number}>
<Td>{pr.title}</Td>
<Td>{pr.user.login}</Td>
<Td>{pr.state}</Td>
<Td>{new Date(pr.created_at).toLocaleString()}</Td>
<Td>{new Date(pr.updated_at).toLocaleString()}</Td>
<Td>
<a href={pr.html_url} target="_blank" rel="noopener noreferrer">
View PR
</a>
</Td>
<Td>
{pr.labels.map((label) => (
<Chip key={label.name} isReadOnly>
{label.name}
</Chip>
))}
</Td>
<Td>
{pr.state === 'open' && (
<Button variant="primary" onClick={() => handleEditClick(pr)}>
Edit
</Button>
)}
</Td>
</Tr>
))}
</Tbody>
</Table>
<Stack hasGutter>
{pullRequests.map((pr) => (
<StackItem key={pr.number}>
<Card>
<CardTitle>{pr.title}</CardTitle>
<CardBody>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<FlexItem>State: {pr.state}</FlexItem>
<FlexItem>Created At: {new Date(pr.created_at).toLocaleString()}</FlexItem>
<FlexItem>Updated At: {new Date(pr.updated_at).toLocaleString()}</FlexItem>
<FlexItem>
{pr.labels.map((label) => (
<Label key={label.name} color="blue" style={{ marginRight: '5px' }}>
{label.name}
</Label>
))}
</FlexItem>
<FlexItem alignSelf={{ default: 'alignSelfFlexEnd' }} flex={{ default: 'flexNone' }}>
<Button variant="secondary" component="a" href={pr.html_url} target="_blank" rel="noopener noreferrer">
View PR
</Button>
</FlexItem>
<FlexItem alignSelf={{ default: 'alignSelfFlexEnd' }} flex={{ default: 'flexNone' }}>
{pr.state === 'open' && (
<Button variant="primary" onClick={() => handleEditClick(pr)}>
Edit
</Button>
)}
</FlexItem>
</Flex>
</CardBody>
</Card>
</StackItem>
))}
</Stack>
</PageSection>
);
};
Expand Down