Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENYO-5363: Added graphql-example #61

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open

Conversation

hangyeolryu
Copy link
Contributor

@hangyeolryu hangyeolryu commented Jun 20, 2018

Use Apollo with Enact and Github GraphqQL API

A sample application that demonstrates how to use GraphqQL with Enact components. It uses Apollo Client (GraphqQL client).

Enact-DCO-1.0-Signed-off-by: HanGyeol Ryu [email protected]

Copy link
Contributor

@rundmt rundmt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made some comments.

@@ -0,0 +1,3 @@
{
"token":"a67285b115df55b4bc1b38"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this token a real token or a fake token?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fake :p

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about setting it to a blank or default value and warning on the screen if the value is not set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok sure

}
}

const App = MoonstoneDecorator(AppBase);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's some extra spacing here

<Query query={GET_USER} variables={{login: userId}}>
{({loading, data}) => {
if (loading) {
return (<Panel {...rest}><p>Loading...</p></Panel>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move Panel above Query? Seems like we're duplicating a lot.

/>
<Detail userId={userId} lists={lists} />
</ActivityPanels>
</ApolloProvider>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets put the parenthesis on a different line, we have quite a few different styles we should probably stick to one.

if (loading) {
return (<Panel {...rest}><p>Loading...</p></Panel>);
} else if (!data && !data.user) {
return <Panel {...rest}><p>User not found...</p></Panel>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have parenthesis like the single line above?

} else if (!data && !data.user) {
return <Panel {...rest}><p>User not found...</p></Panel>;
} else {
return (<Panel {...rest}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other files we have parenthesis on different lines should we move the component code down a line?

{lists.org && <List list={data.user.organizations.nodes} />}
{lists.fol && <List list={data.user.followers.nodes} />}
</Column>
</Panel>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here parenthesis.

render: ({onInputChange, onSearch, onRepoSelection, onFolSelection, onOrgSelection, ...rest}) => {
delete rest.onUserIdChange;
delete rest.onListSelectionChange;
return (<Panel {...rest}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here parenthesis.

constructor (props) {
super(props);
this.userId = 'haileyr';
this.lists = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are all initially set to true should these values be passed to Search for the initial state of the FormCheckboxItem.


constructor (props) {
super(props);
this.userId = 'haileyr';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this an empty string?

"pack-p": "enact pack -p",
"watch": "enact pack --watch",
"clean": "enact clean",
"lint": "enact lint .",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be updated to use --strict

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated it.

delete rest.onUserIdChange;
delete rest.onListSelectionChange;
return (<Panel {...rest}>
{!apiToken && <Notification open><p>Please set your github token in src/config.json.</p></Notification>}
<Header title="Dev checks" type="compact" />
<Input placeholder="Github id" onChange={onInputChange} dismissOnEnter />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the input could be disabled if apiToken is not set?

Copy link
Contributor

@rundmt rundmt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@lishammel lishammel changed the title Added graphql-example ENYO-5363: Added graphql-example Jul 2, 2018
Copy link
Contributor

@webOS101 webOS101 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost done!


this.state = {
userId: '',
lists: {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the duplication of data between this.lists and this.state.lists? There should only be one 'source of truth'.

});

export default ListBase;
export {ListBase as List, ListBase};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the exports of the Base version and just rename to List? This pattern is good for the framework, for consistency, but I don't think we need to demonstrate this in app code.

userId: PropTypes.string
},

computed: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not any need to have this indirection. You can just directly assign renderItem below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That way gives a lint error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it and do not see a lint error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my commit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, can you write up a bug report about enact/display-name returning that warning in situations it clearly should not?

{({loading, data}) => {
if (loading) {
return <Panel {...rest}><p>Loading...</p></Panel>;
} else if (!data && !data.user) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be || not && or else it will throw.

{!apiToken && <Notification open><p>Please set your github token in src/config.json.</p></Notification>}
<Header title="Dev checks" type="compact" />
<Input placeholder="Github id" onChange={onInputChange} dismissOnEnter />
<IconButton onClick={onSearch} small={false} backgroundOpacity="transparent">search</IconButton>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not use the pattern of setting boolean props to false.

onInputChange: (ev, props) => {
props.onUserIdChange(ev.value);
},
onRepoSelection: (value, props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's be consistent and use ev throughout the handlers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not returning an event. It returns an object with a value. but I will just change it.

@@ -46,5 +46,4 @@ const ListBase = kind({
}
});

export default ListBase;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you apply this same pattern to the other files as well?

Roy Sutton added 2 commits July 16, 2018 17:25
Enact-DCO-1.0-Signed-off-by: Roy Sutton [email protected]
Enact-DCO-1.0-Signed-off-by: Roy Sutton [email protected]
Enact-DCO-1.0-Signed-off-by: Roy Sutton [email protected]
@webOS101 webOS101 changed the base branch from master to develop July 16, 2018 22:04
return [
<Cell key="header" shrink><Divider>Repositories</Divider></Cell>,
<Cell
component={VirtualList} size={list.length <= 4 ? (60 * list.length) : null}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

size would be better on its own line.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure would be! Fixed.

Enact-DCO-1.0-Signed-off-by: Roy Sutton [email protected]
Copy link
Contributor

@viodragon2 viodragon2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See inline comments.

user(login: $login) {
name
avatarUrl
organizations(first: 10) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why limit to 10? Any reason why we don't show more?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason. There was an example used first 10. I can put 1-100, so I will change this to 100.

repositories(first: 10) {
nodes {
name
url
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this getting used anywhere?

}
followers(first: 10) {
nodes {
name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name field is not a required field in github user account which can render an empty item. We should look for login field instead. Or maybe both?


render: ({userId, repo, org, fol, ...rest}) => (
<Query query={GET_USER} variables={{login: userId}}>
{({loading, data}) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we handle error?

Copy link
Contributor Author

@hangyeolryu hangyeolryu Aug 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which kind of errors?
I put

else if (!data || !data.user) {
return <Panel {...rest}><p>User not found...</p></Panel>;

for any erroneous data. I think this is enough for this app. Or you can suggest. :)

Copy link
Contributor

@viodragon2 viodragon2 Aug 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant request errors. In case github API does not respond or failed to respond, should we treat it differently?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm ok. I will write something up.

<Query query={GET_USER} variables={{login: userId}}>
{({loading, data}) => {
if (loading) {
return <Panel {...rest}><p>Loading...</p></Panel>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason why we can't wrap Panel outside Query?

On a side note, would be it possible to have three separate <Query> for each type and render lists accordingly instead of fetching all type every time? I don't know if we can do flexible layout dynamically, but wanted to throw out there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried putting Panel outside Query, but it doesn't work.

The query response size is not that big, so I thought it's more efficient requesting all at once than querying three times.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't it work? Doesn't <Query> simply return render prop function to create children? I can't imagine why it would fail.

Regarding fetching data, the response size depends on the user. For example, torvalds has one of the most followers in the world but has only one organization, and when you search for his github info, it takes a while.
Plus, you also need to think about the purpose of this sample. What are we trying to provide to the developers? What are we providing that's not available from Apollo's documentation? Or are we trying to show that we can use other libraries in general, and don't want to dig too deep into GraphQL?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding, the purpose if this app was me getting used to Enact and also making an Enact sample app using GraphGL. As I worked on this, I realized that GraphGL was not really a library that will be commonly used with Enact. So, I focused on more of me experiencing Enact.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and for the Panel wrapping Query, I tried it again. It fails because for the html for successful response. It should be wrapped in a tag but if I do so, the layout breaks.

return (
<Panel {...rest}>
{!apiToken && <Notification open><p>Please set your github token in src/config.json.</p></Notification>}
<Header title="Dev checks" type="compact" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "Dev checks" title mean?

<Header title="Dev checks" type="compact" />
<Input placeholder="Github id" ref={this.userId} onChange={this.onUserIdChange} onKeyUp={this.onKeyUp} />
<IconButton onClick={this.onSearch} backgroundOpacity="transparent">search</IconButton>
<FormCheckboxItem defaultSelected={repo} onToggle={this.onRepoToggle}>Repositories</FormCheckboxItem>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once defaultSelected is set there's no point updating.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not understanding this part.

<Input placeholder="Github id" ref={this.userId} onChange={this.onUserIdChange} onKeyUp={this.onKeyUp} />
<IconButton onClick={this.onSearch} backgroundOpacity="transparent">search</IconButton>
<FormCheckboxItem defaultSelected={repo} onToggle={this.onRepoToggle}>Repositories</FormCheckboxItem>
<FormCheckboxItem defaultSelected={org} onToggle={this.onOrgToggle}>Organizations</FormCheckboxItem>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultSelected is not needed for this one I believe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for org?

<Query query={GET_USER} variables={{login: userId}}>
{({loading, data}) => {
if (loading) {
return <Panel {...rest}><p>Loading...</p></Panel>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not Spinner?

<ApolloProvider client={client}>
<ActivityPanels {...this.props} index={index} onSelectBreadcrumb={this.handleSelectBreadcrumb}>
<Search
apiToken={config.token}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think apiToken needs to belong in Search. You should be able to put Notification adjacent to AcitivityPanels as it's displayed in a floating layer.


## Setup and use
1. Get a personal access token for the [GitHub API](https://github.com/settings/tokens/new).
- Assign a name to the token and select the "read:org" scope.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we mention "read:org" under "admin:org"?

@CLAassistant
Copy link

CLAassistant commented Aug 9, 2018

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
0 out of 2 committers have signed the CLA.

❌ Hailey Ryu
❌ hangyeolryu


Hailey Ryu seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Contributor

@ryanjduffy ryanjduffy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just dismissing the review request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants