Skip to content

Commit db3558f

Browse files
committed
docs(demo): IssueDetail no longer takes time to navigate to
1 parent 1f7b191 commit db3558f

File tree

13 files changed

+159
-157
lines changed

13 files changed

+159
-157
lines changed
+8-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import { useSuspense } from '@data-client/react';
22
import { List } from 'antd';
33
import parseLink from 'parse-link-header';
4+
import { memo } from 'react';
45
import { Issue, IssueResource } from 'resources/Issue';
56

67
import IssueListItem from './IssueListItem';
78
import NextPage from './NextPage';
89

9-
export default function IssueList({ owner, repo, q }: Props) {
10+
function IssueList({ owner, repo, query = '' }: Props) {
11+
const q = `${query} repo:${owner}/${repo}`;
1012
const {
1113
results: { items: issues },
1214
link,
13-
} = useSuspense(IssueResource.search, { owner, repo, q });
15+
} = useSuspense(IssueResource.search, { q });
1416
const nextPage = parseLink(link)?.next?.page;
1517

1618
return (
@@ -19,16 +21,14 @@ export default function IssueList({ owner, repo, q }: Props) {
1921
itemLayout="horizontal"
2022
dataSource={issues}
2123
renderItem={(issue) => <IssueListItem key={issue.pk()} issue={issue} />}
22-
loadMore={
23-
nextPage ? (
24-
<NextPage owner={owner} repo={repo} q={q} page={nextPage} />
25-
) : null
26-
}
24+
loadMore={nextPage ? <NextPage q={q} page={nextPage} /> : null}
2725
/>
2826
</>
2927
);
3028
}
3129

32-
type Props = { owner: string; repo: string; q: string } & {
30+
export default memo(IssueList);
31+
32+
type Props = { owner: string; repo: string; query?: string } & {
3333
state?: Issue['state'];
3434
};

examples/github-app/src/pages/IssueListItem.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { Link } from '@anansi/router';
22
import { List, Avatar, Skeleton } from 'antd';
33
import { humanTime } from 'components/human';
44
import Labels from 'components/Labels';
5+
import { memo } from 'react';
56
import { Issue } from 'resources/Issue';
67

7-
export default function IssueListItem({ issue }: { issue: Issue }) {
8+
function IssueListItem({ issue }: { issue: Issue }) {
89
const actions = [];
910
if (issue.comments) {
1011
actions.push(
@@ -54,3 +55,4 @@ export default function IssueListItem({ issue }: { issue: Issue }) {
5455
</List.Item>
5556
);
5657
}
58+
export default memo(IssueListItem);

examples/github-app/src/pages/IssuesPage.tsx

+5-11
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ import IssueList from './IssueList';
77

88
export default function IssuePage({ owner, repo }: Props) {
99
const search = useLocationSearch();
10-
const q = search?.get('q') || 'is:issue is:open';
10+
const query = `${search?.get('query') || 'is:open'} is:issue`;
1111

1212
return (
1313
<>
14-
{' '}
1514
<Breadcrumb
1615
itemRender={(route, params, routes, paths) =>
1716
route.href ? <Link name="Home">{route.title}</Link> : route.title
@@ -40,15 +39,10 @@ export default function IssuePage({ owner, repo }: Props) {
4039
},
4140
]}
4241
/>
43-
<IssueList owner={owner} repo={repo} q={q} />
42+
<IssueList owner={owner} repo={repo} query={query} />
4443
</>
4544
);
4645
}
47-
type Props = { owner: string; repo: string } & (
48-
| {
49-
page: number;
50-
}
51-
| {
52-
state?: Issue['state'];
53-
}
54-
);
46+
type Props = { owner: string; repo: string } & {
47+
state?: Issue['state'];
48+
};

examples/github-app/src/pages/NextPage.tsx

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ import { useController, useLoading } from '@data-client/react';
22
import { Button } from 'antd';
33
import { IssueResource } from 'resources/Issue';
44

5-
export default function NextPage({ repo, owner, q, page }: Props) {
5+
export default function NextPage({ q, page }: Props) {
66
const ctrl = useController();
77
const [loadMore, loading] = useLoading(() =>
88
ctrl.fetch(IssueResource.search.getPage, {
99
page,
10-
repo,
11-
owner,
1210
q,
1311
}),
1412
);
@@ -20,8 +18,6 @@ export default function NextPage({ repo, owner, q, page }: Props) {
2018
}
2119

2220
export interface Props {
23-
repo: string;
24-
owner: string;
2521
q: string;
2622
page: string;
2723
}

examples/github-app/src/pages/PullsPage.tsx

+5-10
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,10 @@ import IssueList from './IssueList';
55

66
export default function PullsPage({ owner, repo }: Props) {
77
const search = useLocationSearch();
8-
const q = search?.get('q') || 'is:pr is:open';
8+
const query = `${search?.get('query') || 'is:open'} is:pr`;
99

10-
return <IssueList owner={owner} repo={repo} q={q} />;
10+
return <IssueList owner={owner} repo={repo} query={query} />;
1111
}
12-
type Props = { owner: string; repo: string } & (
13-
| {
14-
page: number;
15-
}
16-
| {
17-
state?: Issue['state'];
18-
}
19-
);
12+
type Props = { owner: string; repo: string } & {
13+
state?: Issue['state'];
14+
};

examples/github-app/src/resources/Base.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import { getAuth } from './Auth';
1616
const HOST = 'https://api.github.com';
1717

1818
export class GithubEntity extends Entity {
19-
readonly id: number = -1;
19+
// -1 is not valid, so this indicates it was not initialized
20+
id = -1;
2021
}
2122

2223
export const GithubGqlEndpoint = new GQLEndpoint(

examples/github-app/src/resources/Comment.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { GithubEntity, githubResource } from './Base';
44
import { User } from './User';
55

66
export class Comment extends GithubEntity {
7-
readonly issueUrl: string = '';
8-
readonly htmlUrl: string = '';
9-
readonly body: string = '';
10-
readonly user: User = User.fromJS();
11-
readonly createdAt = Temporal.Instant.fromEpochSeconds(0);
12-
readonly updatedAt = Temporal.Instant.fromEpochSeconds(0);
13-
readonly authorAssociation: string = 'NONE';
7+
issueUrl = '';
8+
htmlUrl = '';
9+
body = '';
10+
user = User.fromJS();
11+
createdAt = Temporal.Instant.fromEpochSeconds(0);
12+
updatedAt = Temporal.Instant.fromEpochSeconds(0);
13+
authorAssociation = 'NONE';
1414

1515
get owner() {
1616
const pieces = this.issueUrl.split('/issues')[0].split('/');

examples/github-app/src/resources/Event.tsx

+8-8
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ import { Push } from './Push';
1616
import { Review } from './Review';
1717

1818
export class Event extends GithubEntity {
19-
readonly type: EventType = 'WatchEvent';
20-
readonly actor: Record<string, any> = {};
21-
readonly repo: { id: number; name: string; url: string } = {} as any;
22-
readonly payload: Record<string, any> = {};
23-
readonly public: boolean = true;
24-
readonly createdAt = Temporal.Instant.fromEpochSeconds(0);
19+
type: EventType = 'WatchEvent';
20+
actor: Record<string, any> = {};
21+
repo: { id: number; name: string; url: string } = {} as any;
22+
payload: Record<string, unknown> = {};
23+
public = true;
24+
createdAt = Temporal.Instant.fromEpochSeconds(0);
2525

2626
get icon() {
2727
return typeToIcon[this.type];
@@ -34,7 +34,7 @@ export class Event extends GithubEntity {
3434
export class PullRequestEvent extends Event {
3535
readonly type = 'PullRequestEvent';
3636

37-
declare readonly payload: {
37+
declare payload: {
3838
action: 'closed' | 'opened';
3939
number: number;
4040
pullRequest: Pull;
@@ -47,7 +47,7 @@ export class PullRequestEvent extends Event {
4747
}
4848
export class PullRequestReviewEvent extends Event {
4949
readonly type = 'PullRequestReviewEvent';
50-
declare readonly payload: {
50+
declare payload: {
5151
action: 'created';
5252
pullRequest: Pull;
5353
review: Review;

examples/github-app/src/resources/Issue.tsx

+43-29
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,30 @@ import { stateToIcon } from './stateToIcon';
66
import { User } from './User';
77

88
export class Issue extends GithubEntity {
9-
readonly number: number = 0;
10-
readonly repositoryUrl: string = '';
11-
readonly labelsUrl: string = '';
12-
readonly htmlUrl: string = '';
13-
readonly body: string = '';
14-
readonly title: string = '';
15-
readonly user: User = User.fromJS({});
16-
readonly state: 'open' | 'closed' = 'open';
17-
readonly locked: boolean = false;
18-
readonly comments: number = 0;
19-
readonly createdAt = Temporal.Instant.fromEpochSeconds(0);
20-
readonly updatedAt = Temporal.Instant.fromEpochSeconds(0);
21-
readonly closedAt: Date | null = null;
22-
readonly labels: Label[] = [];
23-
readonly authorAssociation: string = 'NONE';
24-
readonly pullRequest: Record<string, any> | null = null;
25-
readonly draft?: boolean;
9+
number = 0;
10+
owner = '';
11+
repo = '';
12+
repositoryUrl = '';
13+
labelsUrl = '';
14+
htmlUrl = '';
15+
body = '';
16+
title = '';
17+
user = User.fromJS({});
18+
state: 'open' | 'closed' = 'open';
19+
locked = false;
20+
comments = 0;
21+
createdAt = Temporal.Instant.fromEpochSeconds(0);
22+
updatedAt = Temporal.Instant.fromEpochSeconds(0);
23+
closedAt: Date | null = null;
24+
labels: Label[] = [];
25+
authorAssociation = 'NONE';
26+
pullRequest: Record<string, any> | null = null;
27+
draft?: boolean;
2628

2729
get stateIcon() {
2830
return stateToIcon[this.state];
2931
}
3032

31-
get owner() {
32-
const pieces = this.repositoryUrl.split('/');
33-
return pieces[pieces.length - 2];
34-
}
35-
36-
get repo() {
37-
const pieces = this.repositoryUrl.split('/');
38-
return pieces[pieces.length - 1];
39-
}
40-
4133
static schema = {
4234
user: User,
4335
createdAt: Temporal.Instant.from,
@@ -47,18 +39,40 @@ export class Issue extends GithubEntity {
4739
};
4840

4941
pk() {
50-
return [this.repositoryUrl, this.number].join(',');
42+
if (!this.owner) {
43+
const { owner, repo } = splitRepoUrl(this.repositoryUrl);
44+
return `${owner}/${repo}/${this.number}`;
45+
}
46+
return `${this.owner}/${this.repo}/${this.number}`;
5147
}
48+
49+
static process(
50+
input: any,
51+
parent: any,
52+
key: string | undefined,
53+
args: any[],
54+
) {
55+
const { owner, repo } = splitRepoUrl(input.repositoryUrl);
56+
return { owner, repo, ...input };
57+
}
58+
}
59+
60+
function splitRepoUrl(url: string) {
61+
const [a, b, c, d, owner, repo] = url.split('/');
62+
return { owner, repo };
5263
}
5364

5465
export const IssueResource = githubResource({
5566
path: '/repos/:owner/:repo/issues/:number',
5667
schema: Issue,
68+
dataExpiryLength: 60000,
5769
pollFrequency: 60000,
5870
searchParams: {} as IssueFilters | undefined,
71+
paginationField: 'page',
5972
}).extend((Base) => ({
6073
search: Base.getList.extend({
61-
path: '/search/issues\\?q=:q?%20repo\\::owner/:repo&page=:page?',
74+
path: '/search/issues',
75+
searchParams: {} as IssueFilters & { q: string },
6276
schema: {
6377
results: {
6478
incompleteResults: false,

examples/github-app/src/resources/Label.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { GithubEntity, githubResource } from './Base';
22
import PreviewEndpoint from './PreviewEndpoint';
33

44
export class Label extends GithubEntity {
5-
readonly nodeId: string = '';
6-
readonly name: string = '';
7-
readonly description: string = '';
8-
readonly color: string = '000000';
9-
readonly default: boolean = false;
5+
nodeId = '';
6+
name = '';
7+
description = '';
8+
color = '000000';
9+
default = false;
1010
}
1111
export const LabelResource = githubResource({
1212
path: '/repos/:owner/:repo/labels/:name',

examples/github-app/src/resources/Repository.tsx

+28-29
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,34 @@ import { Temporal } from '@js-temporal/polyfill';
33
import { GithubEntity, githubResource, GithubGqlEndpoint } from './Base';
44

55
export class Repository extends GithubEntity {
6-
readonly name: string = '';
7-
readonly fullName: string = '';
8-
readonly private: boolean = false;
9-
readonly description: string = '';
10-
readonly fork: boolean = false;
11-
readonly homepage: string = '';
12-
readonly language: string | null = null;
13-
readonly forksCount: number = 0;
14-
readonly stargazersCount: number = 0;
15-
readonly watchersCount: number = 0;
16-
readonly size: number = 0;
17-
readonly defaultBranch: string = 'master';
18-
readonly openIssuesCount: number = 0;
19-
readonly isTemplate: boolean = false;
20-
readonly topics: string[] = [];
21-
readonly hasIssues: boolean = false;
22-
readonly hasProjects: boolean = false;
23-
readonly hasWiki: boolean = false;
24-
readonly hasPages: boolean = false;
25-
readonly hasDownloads: boolean = false;
26-
readonly archived: boolean = false;
27-
readonly disabled: boolean = false;
28-
readonly visibility: 'public' | 'private' = 'public';
29-
readonly pushedAt = Temporal.Instant.fromEpochSeconds(0);
30-
readonly createdAt = Temporal.Instant.fromEpochSeconds(0);
31-
readonly updatedAt = Temporal.Instant.fromEpochSeconds(0);
32-
readonly templateRepository: null = null;
33-
readonly owner: { login: string } = { login: '' };
6+
name = '';
7+
fullName = '';
8+
private = false;
9+
description = '';
10+
fork = false;
11+
homepage = '';
12+
language: string | null = null;
13+
forksCount = 0;
14+
stargazersCount = 0;
15+
watchersCount = 0;
16+
size = 0;
17+
defaultBranch = 'master';
18+
openIssuesCount = 0;
19+
isTemplate = false;
20+
topics: string[] = [];
21+
hasIssues = false;
22+
hasProjects = false;
23+
hasWiki = false;
24+
hasPages = false;
25+
hasDownloads = false;
26+
archived = false;
27+
disabled = false;
28+
visibility: 'public' | 'private' = 'public';
29+
pushedAt = Temporal.Instant.fromEpochSeconds(0);
30+
createdAt = Temporal.Instant.fromEpochSeconds(0);
31+
updatedAt = Temporal.Instant.fromEpochSeconds(0);
32+
templateRepository: null = null;
33+
owner = { login: '' };
3434

3535
static schema = {
3636
pushedAt: Temporal.Instant.from,
@@ -42,7 +42,6 @@ export class Repository extends GithubEntity {
4242
return [this.owner.login, this.name].join(',');
4343
}
4444

45-
// for the inheritance
4645
static key = 'Repository';
4746
}
4847

0 commit comments

Comments
 (0)