Fix nx lint setup (#3234)
* Fix nx lint setup * Fixes * Fixes * Add missing metadata Fixes Fix Fixes * Fix
This commit is contained in:
@ -1,9 +1,11 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import { ResponsiveTimeRange } from '@nivo/calendar'
|
||||
import { ResponsiveTimeRange } from '@nivo/calendar';
|
||||
|
||||
export const ActivityLog = ({ data }: { data: { value: number, day: string }[] }) => {
|
||||
return <ResponsiveTimeRange
|
||||
data={data}
|
||||
/>;
|
||||
}
|
||||
export const ActivityLog = ({
|
||||
data,
|
||||
}: {
|
||||
data: { value: number; day: string }[];
|
||||
}) => {
|
||||
return <ResponsiveTimeRange data={data} />;
|
||||
};
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import Image from 'next/image';
|
||||
import Database from 'better-sqlite3';
|
||||
import AvatarGrid from '@/app/components/AvatarGrid';
|
||||
import { ResponsiveTimeRange } from '@nivo/calendar'
|
||||
import { ActivityLog } from './components/ActivityLog';
|
||||
import { Metadata } from 'next';
|
||||
import Image from 'next/image';
|
||||
|
||||
import { ActivityLog } from './components/ActivityLog';
|
||||
|
||||
interface Contributor {
|
||||
login: string;
|
||||
@ -11,21 +10,22 @@ interface Contributor {
|
||||
pullRequestCount: number;
|
||||
}
|
||||
|
||||
|
||||
export function generateMetadata({ params }: { params: { slug: string } }): Metadata {
|
||||
return {
|
||||
title: params.slug + ' | Contributors',
|
||||
};
|
||||
export function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
}): Metadata {
|
||||
return {
|
||||
title: params.slug + ' | Contributors',
|
||||
};
|
||||
}
|
||||
|
||||
export default async function ({ params }: { params: { slug: string } }) {
|
||||
const db = new Database('db.sqlite', { readonly: true });
|
||||
|
||||
|
||||
export default async function (
|
||||
{ params }: { params: { slug: string } }) {
|
||||
|
||||
const db = new Database('db.sqlite', { readonly: true });
|
||||
|
||||
const contributor = db.prepare(`
|
||||
const contributor = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT
|
||||
u.login,
|
||||
u.avatarUrl,
|
||||
@ -35,9 +35,13 @@ export default async function (
|
||||
users u
|
||||
WHERE
|
||||
u.login = :user_id
|
||||
`).get({'user_id' : params.slug}) as Contributor;
|
||||
`,
|
||||
)
|
||||
.get({ user_id: params.slug }) as Contributor;
|
||||
|
||||
const pullRequestActivity = db.prepare(`
|
||||
const pullRequestActivity = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT
|
||||
COUNT(*) as value,
|
||||
DATE(createdAt) as day
|
||||
@ -49,11 +53,13 @@ const pullRequestActivity = db.prepare(`
|
||||
DATE(createdAt)
|
||||
ORDER BY
|
||||
DATE(createdAt)
|
||||
`).all({'user_id': params.slug}) as { value: number, day: string }[];
|
||||
`,
|
||||
)
|
||||
.all({ user_id: params.slug }) as { value: number; day: string }[];
|
||||
|
||||
|
||||
|
||||
const pullRequestList = db.prepare(`
|
||||
const pullRequestList = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT
|
||||
id,
|
||||
title,
|
||||
@ -69,32 +75,46 @@ const pullRequestList = db.prepare(`
|
||||
authorId = (SELECT id FROM users WHERE login = :user_id)
|
||||
ORDER BY
|
||||
DATE(createdAt) DESC
|
||||
`).all({'user_id': params.slug}) as { title: string, createdAt: string, url: string }[];
|
||||
`,
|
||||
)
|
||||
.all({ user_id: params.slug }) as {
|
||||
title: string;
|
||||
createdAt: string;
|
||||
url: string;
|
||||
}[];
|
||||
|
||||
|
||||
db.close();
|
||||
|
||||
|
||||
return (
|
||||
<div style={{maxWidth: '900px', display: 'flex', padding: '40px', gap: '24px'}}>
|
||||
<div style={{ flexDirection: 'column', width: '240px'}}>
|
||||
<Image src={contributor.avatarUrl} alt={contributor.login} width={240} height={240} />
|
||||
<div
|
||||
style={{
|
||||
maxWidth: '900px',
|
||||
display: 'flex',
|
||||
padding: '40px',
|
||||
gap: '24px',
|
||||
}}
|
||||
>
|
||||
<div style={{ flexDirection: 'column', width: '240px' }}>
|
||||
<Image
|
||||
src={contributor.avatarUrl}
|
||||
alt={contributor.login}
|
||||
width={240}
|
||||
height={240}
|
||||
/>
|
||||
<h1>{contributor.login}</h1>
|
||||
</div>
|
||||
<div style={{flexDirection: 'column'}}>
|
||||
<div style={{width: '450px', height: '200px'}}>
|
||||
<ActivityLog
|
||||
data={pullRequestActivity}
|
||||
/>
|
||||
</div>
|
||||
<div style={{width: '450px'}}>
|
||||
{pullRequestList.map(pr => (
|
||||
<div>
|
||||
<a href={pr.url}>{pr.title}</a>
|
||||
</div>
|
||||
))}
|
||||
<div style={{ flexDirection: 'column' }}>
|
||||
<div style={{ width: '450px', height: '200px' }}>
|
||||
<ActivityLog data={pullRequestActivity} />
|
||||
</div>
|
||||
<div style={{ width: '450px' }}>
|
||||
{pullRequestList.map((pr) => (
|
||||
<div>
|
||||
<a href={pr.url}>{pr.title}</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,19 +1,23 @@
|
||||
|
||||
import Database from 'better-sqlite3';
|
||||
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { slug: string } }) {
|
||||
const db = new Database('db.sqlite', { readonly: true });
|
||||
request: Request,
|
||||
{ params }: { params: { slug: string } },
|
||||
) {
|
||||
const db = new Database('db.sqlite', { readonly: true });
|
||||
|
||||
if(params.slug !== 'users' && params.slug !== 'labels' && params.slug !== 'pullRequests' && params.slug !== 'issues') {
|
||||
return Response.json({ error: 'Invalid table name' }, { status: 400 });
|
||||
}
|
||||
if (
|
||||
params.slug !== 'users' &&
|
||||
params.slug !== 'labels' &&
|
||||
params.slug !== 'pullRequests' &&
|
||||
params.slug !== 'issues'
|
||||
) {
|
||||
return Response.json({ error: 'Invalid table name' }, { status: 400 });
|
||||
}
|
||||
|
||||
const rows = db.prepare('SELECT * FROM ' + params.slug).all();
|
||||
|
||||
db.close();
|
||||
const rows = db.prepare('SELECT * FROM ' + params.slug).all();
|
||||
|
||||
return Response.json(rows);
|
||||
db.close();
|
||||
|
||||
return Response.json(rows);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import { graphql } from '@octokit/graphql';
|
||||
import Database from 'better-sqlite3';
|
||||
|
||||
const db = new Database('db.sqlite', { verbose: console.log });
|
||||
|
||||
@ -83,8 +83,13 @@ const query = graphql.defaults({
|
||||
},
|
||||
});
|
||||
|
||||
async function fetchData(cursor: string | null = null, isIssues: boolean = false, accumulatedData: Array<PullRequestNode | IssueNode> = []): Promise<Array<PullRequestNode | IssueNode>> {
|
||||
const { repository } = await query<RepoData>(`
|
||||
async function fetchData(
|
||||
cursor: string | null = null,
|
||||
isIssues: boolean = false,
|
||||
accumulatedData: Array<PullRequestNode | IssueNode> = [],
|
||||
): Promise<Array<PullRequestNode | IssueNode>> {
|
||||
const { repository } = await query<RepoData>(
|
||||
`
|
||||
query ($cursor: String) {
|
||||
repository(owner: "twentyhq", name: "twenty") {
|
||||
pullRequests(first: 100, after: $cursor, orderBy: {field: CREATED_AT, direction: DESC}) @skip(if: ${isIssues}) {
|
||||
@ -148,10 +153,17 @@ async function fetchData(cursor: string | null = null, isIssues: boolean = false
|
||||
}
|
||||
}
|
||||
}
|
||||
`, { cursor });
|
||||
`,
|
||||
{ cursor },
|
||||
);
|
||||
|
||||
const newAccumulatedData: Array<PullRequestNode | IssueNode> = [...accumulatedData, ...(isIssues ? repository.issues.nodes : repository.pullRequests.nodes)];
|
||||
const pageInfo = isIssues ? repository.issues.pageInfo : repository.pullRequests.pageInfo;
|
||||
const newAccumulatedData: Array<PullRequestNode | IssueNode> = [
|
||||
...accumulatedData,
|
||||
...(isIssues ? repository.issues.nodes : repository.pullRequests.nodes),
|
||||
];
|
||||
const pageInfo = isIssues
|
||||
? repository.issues.pageInfo
|
||||
: repository.pullRequests.pageInfo;
|
||||
|
||||
if (pageInfo.hasNextPage) {
|
||||
return fetchData(pageInfo.endCursor, isIssues, newAccumulatedData);
|
||||
@ -173,11 +185,12 @@ async function fetchAssignableUsers(): Promise<Set<string>> {
|
||||
}
|
||||
`);
|
||||
|
||||
return new Set(repository.assignableUsers.nodes.map(user => user.login));
|
||||
return new Set(repository.assignableUsers.nodes.map((user) => user.login));
|
||||
}
|
||||
|
||||
const initDb = () => {
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS pullRequests (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT,
|
||||
@ -190,9 +203,11 @@ const initDb = () => {
|
||||
authorId TEXT,
|
||||
FOREIGN KEY (authorId) REFERENCES users(id)
|
||||
);
|
||||
`).run();
|
||||
`,
|
||||
).run();
|
||||
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS issues (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT,
|
||||
@ -204,9 +219,11 @@ const initDb = () => {
|
||||
authorId TEXT,
|
||||
FOREIGN KEY (authorId) REFERENCES users(id)
|
||||
);
|
||||
`).run();
|
||||
`,
|
||||
).run();
|
||||
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
login TEXT,
|
||||
@ -214,81 +231,133 @@ const initDb = () => {
|
||||
url TEXT,
|
||||
isEmployee BOOLEAN
|
||||
);
|
||||
`).run();
|
||||
`,
|
||||
).run();
|
||||
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS labels (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT,
|
||||
color TEXT,
|
||||
description TEXT
|
||||
);
|
||||
`).run();
|
||||
`,
|
||||
).run();
|
||||
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS pullRequestLabels (
|
||||
pullRequestId TEXT,
|
||||
labelId TEXT,
|
||||
FOREIGN KEY (pullRequestId) REFERENCES pullRequests(id),
|
||||
FOREIGN KEY (labelId) REFERENCES labels(id)
|
||||
);
|
||||
`).run();
|
||||
`,
|
||||
).run();
|
||||
|
||||
db.prepare(`
|
||||
db.prepare(
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS issueLabels (
|
||||
issueId TEXT,
|
||||
labelId TEXT,
|
||||
FOREIGN KEY (issueId) REFERENCES issues(id),
|
||||
FOREIGN KEY (labelId) REFERENCES labels(id)
|
||||
);
|
||||
`).run();
|
||||
|
||||
`,
|
||||
).run();
|
||||
};
|
||||
|
||||
export async function GET() {
|
||||
initDb();
|
||||
|
||||
initDb();
|
||||
// TODO if we ever hit API Rate Limiting
|
||||
const lastPRCursor = null;
|
||||
const lastIssueCursor = null;
|
||||
|
||||
// TODO if we ever hit API Rate Limiting
|
||||
const lastPRCursor = null;
|
||||
const lastIssueCursor = null;
|
||||
const assignableUsers = await fetchAssignableUsers();
|
||||
const prs = (await fetchData(lastPRCursor)) as Array<PullRequestNode>;
|
||||
const issues = (await fetchData(lastIssueCursor, true)) as Array<IssueNode>;
|
||||
|
||||
const assignableUsers = await fetchAssignableUsers();
|
||||
const prs = await fetchData(lastPRCursor) as Array<PullRequestNode>;
|
||||
const issues = await fetchData(lastIssueCursor, true) as Array<IssueNode>;
|
||||
|
||||
const insertPR = db.prepare('INSERT INTO pullRequests (id, title, body, url, createdAt, updatedAt, closedAt, mergedAt, authorId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING');
|
||||
const insertIssue = db.prepare('INSERT INTO issues (id, title, body, url, createdAt, updatedAt, closedAt, authorId) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING');
|
||||
const insertUser = db.prepare('INSERT INTO users (id, login, avatarUrl, url, isEmployee) VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING');
|
||||
const insertLabel = db.prepare('INSERT INTO labels (id, name, color, description) VALUES (?, ?, ?, ?) ON CONFLICT(id) DO NOTHING');
|
||||
const insertPullRequestLabel = db.prepare('INSERT INTO pullRequestLabels (pullRequestId, labelId) VALUES (?, ?)');
|
||||
const insertIssueLabel = db.prepare('INSERT INTO issueLabels (issueId, labelId) VALUES (?, ?)');
|
||||
const insertPR = db.prepare(
|
||||
'INSERT INTO pullRequests (id, title, body, url, createdAt, updatedAt, closedAt, mergedAt, authorId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
||||
);
|
||||
const insertIssue = db.prepare(
|
||||
'INSERT INTO issues (id, title, body, url, createdAt, updatedAt, closedAt, authorId) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
||||
);
|
||||
const insertUser = db.prepare(
|
||||
'INSERT INTO users (id, login, avatarUrl, url, isEmployee) VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
||||
);
|
||||
const insertLabel = db.prepare(
|
||||
'INSERT INTO labels (id, name, color, description) VALUES (?, ?, ?, ?) ON CONFLICT(id) DO NOTHING',
|
||||
);
|
||||
const insertPullRequestLabel = db.prepare(
|
||||
'INSERT INTO pullRequestLabels (pullRequestId, labelId) VALUES (?, ?)',
|
||||
);
|
||||
const insertIssueLabel = db.prepare(
|
||||
'INSERT INTO issueLabels (issueId, labelId) VALUES (?, ?)',
|
||||
);
|
||||
|
||||
for (const pr of prs) {
|
||||
console.log(pr);
|
||||
if(pr.author == null) { continue; }
|
||||
insertUser.run(pr.author.resourcePath, pr.author.login, pr.author.avatarUrl, pr.author.url, assignableUsers.has(pr.author.login) ? 1 : 0);
|
||||
insertPR.run(pr.id, pr.title, pr.body, pr.url, pr.createdAt, pr.updatedAt, pr.closedAt, pr.mergedAt, pr.author.resourcePath);
|
||||
for (const pr of prs) {
|
||||
console.log(pr);
|
||||
if (pr.author == null) {
|
||||
continue;
|
||||
}
|
||||
insertUser.run(
|
||||
pr.author.resourcePath,
|
||||
pr.author.login,
|
||||
pr.author.avatarUrl,
|
||||
pr.author.url,
|
||||
assignableUsers.has(pr.author.login) ? 1 : 0,
|
||||
);
|
||||
insertPR.run(
|
||||
pr.id,
|
||||
pr.title,
|
||||
pr.body,
|
||||
pr.url,
|
||||
pr.createdAt,
|
||||
pr.updatedAt,
|
||||
pr.closedAt,
|
||||
pr.mergedAt,
|
||||
pr.author.resourcePath,
|
||||
);
|
||||
|
||||
for (const label of pr.labels.nodes) {
|
||||
insertLabel.run(label.id, label.name, label.color, label.description);
|
||||
insertPullRequestLabel.run(pr.id, label.id);
|
||||
}
|
||||
}
|
||||
for (const label of pr.labels.nodes) {
|
||||
insertLabel.run(label.id, label.name, label.color, label.description);
|
||||
insertPullRequestLabel.run(pr.id, label.id);
|
||||
}
|
||||
}
|
||||
|
||||
for (const issue of issues) {
|
||||
if(issue.author == null) { continue; }
|
||||
insertUser.run(issue.author.resourcePath, issue.author.login, issue.author.avatarUrl, issue.author.url, assignableUsers.has(issue.author.login) ? 1 : 0);
|
||||
for (const issue of issues) {
|
||||
if (issue.author == null) {
|
||||
continue;
|
||||
}
|
||||
insertUser.run(
|
||||
issue.author.resourcePath,
|
||||
issue.author.login,
|
||||
issue.author.avatarUrl,
|
||||
issue.author.url,
|
||||
assignableUsers.has(issue.author.login) ? 1 : 0,
|
||||
);
|
||||
|
||||
insertIssue.run(issue.id, issue.title, issue.body, issue.url, issue.createdAt, issue.updatedAt, issue.closedAt, issue.author.resourcePath);
|
||||
insertIssue.run(
|
||||
issue.id,
|
||||
issue.title,
|
||||
issue.body,
|
||||
issue.url,
|
||||
issue.createdAt,
|
||||
issue.updatedAt,
|
||||
issue.closedAt,
|
||||
issue.author.resourcePath,
|
||||
);
|
||||
|
||||
for (const label of issue.labels.nodes) {
|
||||
insertLabel.run(label.id, label.name, label.color, label.description);
|
||||
insertIssueLabel.run(issue.id, label.id);
|
||||
}
|
||||
}
|
||||
for (const label of issue.labels.nodes) {
|
||||
insertLabel.run(label.id, label.name, label.color, label.description);
|
||||
insertIssueLabel.run(issue.id, label.id);
|
||||
}
|
||||
}
|
||||
|
||||
db.close();
|
||||
db.close();
|
||||
|
||||
return new Response("Data synced", { status: 200 });
|
||||
};
|
||||
return new Response('Data synced', { status: 200 });
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Image from 'next/image';
|
||||
import Database from 'better-sqlite3';
|
||||
|
||||
import AvatarGrid from '@/app/components/AvatarGrid';
|
||||
|
||||
interface Contributor {
|
||||
@ -9,11 +9,11 @@ interface Contributor {
|
||||
}
|
||||
|
||||
const Contributors = async () => {
|
||||
|
||||
|
||||
const db = new Database('db.sqlite', { readonly: true });
|
||||
|
||||
const contributors = db.prepare(`SELECT
|
||||
const contributors = db
|
||||
.prepare(
|
||||
`SELECT
|
||||
u.login,
|
||||
u.avatarUrl,
|
||||
COUNT(pr.id) AS pullRequestCount
|
||||
@ -25,9 +25,10 @@ const Contributors = async () => {
|
||||
u.id
|
||||
ORDER BY
|
||||
pullRequestCount DESC;
|
||||
`).all() as Contributor[];
|
||||
|
||||
|
||||
`,
|
||||
)
|
||||
.all() as Contributor[];
|
||||
|
||||
db.close();
|
||||
|
||||
return (
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import { createGraphiQLFetcher } from '@graphiql/toolkit';
|
||||
import { GraphiQL } from 'graphiql';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
import 'graphiql/graphiql.css';
|
||||
|
||||
// Create a named function for your component
|
||||
|
||||
Reference in New Issue
Block a user