Skip to content
This repository has been archived by the owner on Mar 23, 2019. It is now read-only.

Add client view initial search content #158 #160

Merged
merged 10 commits into from Oct 17, 2018

Conversation

projectyang
Copy link
Contributor

@projectyang projectyang commented Oct 12, 2018

Set client id as default search in Clients view

Clients table will now show filtered results by client id as default.

Fixes #158, however users are now unable to retrieve a 'full' default clients view (e.g. expected search query with '' to retrieve full list of clients does not work)

Copy link
Contributor

@helfi92 helfi92 left a comment

Choose a reason for hiding this comment

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

Awesome work!

Regarding retrieving the full list, give the following a try:

diff --git a/src/views/Clients/ViewClients/index.jsx b/src/views/Clients/ViewClients/index.jsx
index db6aa55..3150ce0 100644
--- a/src/views/Clients/ViewClients/index.jsx
+++ b/src/views/Clients/ViewClients/index.jsx
@@ -93,13 +93,9 @@ export default class ViewWorker extends PureComponent {
     const { clientSearch } = this.state;
 
     refetch({
-      ...(clientSearch
-        ? {
-            clientOptions: {
-              prefix: clientSearch,
-            },
-          }
-        : null),
+      clientOptions: {
+        ...(clientSearch ? { prefix: clientSearch } : null),
+      },
       clientsConnection: {
         limit: VIEW_CLIENTS_PAGE_SIZE,
       },

state = {
clientSearch: '',
clientSearch: this.props.user.credentials.clientId,
Copy link
Contributor

Choose a reason for hiding this comment

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

If you log out and then refresh the page, the view will crash on this line. This is because this.props.user is undefined.

You can do:

clientSearch: this.props.user ? this.props.user.credentials.clientId || '',

@projectyang
Copy link
Contributor Author

projectyang commented Oct 12, 2018

I also noticed that if I were to query with spaces e.g. "   ", the following error appears:

screen shot 2018-10-12 at 3 36 08 pm

Should we attempt to sanitize any leading spaces in the search value before querying? E.g. "   exampleId" --> "exampleId"

@helfi92
Copy link
Contributor

helfi92 commented Oct 12, 2018

Good catch. Sanitization would be great to have!

Copy link
Contributor

@helfi92 helfi92 left a comment

Choose a reason for hiding this comment

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

Looks good, just a small change.

src/views/Clients/ViewClients/index.jsx Outdated Show resolved Hide resolved
src/views/Clients/ViewClients/index.jsx Outdated Show resolved Hide resolved
src/views/Clients/ViewClients/index.jsx Outdated Show resolved Hide resolved
@projectyang
Copy link
Contributor Author

Thanks for the help! Really appreciate the time you took to explain everything.

Copy link
Contributor

@helfi92 helfi92 left a comment

Choose a reason for hiding this comment

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

Hopefully the last change before merging :)

@@ -30,8 +32,11 @@ import clientsQuery from './clients.graphql';
},
}))
export default class ViewWorker extends PureComponent {
componentDidMount() {
this.handleClientSearchSubmit();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is going to fetch the list of clients twice. Let's rely on the initial graphql call to perform search the filtered clients. You can achieve that by adding the same logic for clientsOptions under variables. See other comment.


@hot(module)
@withAuth
@graphql(clientsQuery, {
options: () => ({
Copy link
Contributor

Choose a reason for hiding this comment

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

options can have access to props:

options: (props) => ({

src/views/Clients/ViewClients/index.jsx Show resolved Hide resolved
e.preventDefault();
if (e) {
e.preventDefault();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we won't be calling this method from componentDidMount anymore, we can remove the if statement and just use e.preventDefault().

@projectyang
Copy link
Contributor Author

projectyang commented Oct 15, 2018

I've made the recommended changes but discovered two scenarios that may cause issues for users:

Scenario 1:
If a user logs in or out on the Clients view, the search bar does not update automatically. This can lead to confusion if a user logs in (and triggers the default clientId query) and does not know about it.

screen shot 2018-10-15 at 10 59 22 am

My proposed solution is to use ComponentDidUpdate in the clients component to monitor when a log in/out has occurred and update state for the search component.
No need for lifecycle here, just used the props with ternary for the Search component.

Scenario 2:
Related to the above, if a user logins in or out on the Clients view an error is thrown by Apollo, which disappears/resolves shortly with the updated view:

screen shot 2018-10-15 at 10 36 56 am

I'm having difficulty solving this one. My assumption is that the graphql query for the Clients component is still in flight when resetStore() is called, thus throwing the error. Is the correct approach to wait for the query to finish before triggering resetStore()?

@helfi92
Copy link
Contributor

helfi92 commented Oct 15, 2018

I'm having difficulty solving this one. My assumption is that the graphql query for the Clients component is still in flight when resetStore() is called, thus throwing the error.

See if the following fixes it:

diff --git a/src/components/Dashboard/UserMenu.jsx b/src/components/Dashboard/UserMenu.jsx
index 3ff85f3..d573cab 100644
--- a/src/components/Dashboard/UserMenu.jsx
+++ b/src/components/Dashboard/UserMenu.jsx
@@ -59,12 +59,12 @@ export default class UserMenu extends Component {
     this.setState({ signInDialogOpen: false });
   };
 
-  handleClickSignOut = () => {
+  handleClickSignOut = async () => {
     this.handleMenuClose();
-    this.props.onUnauthorize();
     // Since Apollo caches query results, it’s important to get rid of them
     // when the login state changes.
-    this.props.client.resetStore();
+    await this.props.client.resetStore();
+    this.props.onUnauthorize();
   };
 
   render() {
diff --git a/src/components/SignInDialog/index.jsx b/src/components/SignInDialog/index.jsx
index 80983fd..b03c6e9 100644
--- a/src/components/SignInDialog/index.jsx
+++ b/src/components/SignInDialog/index.jsx
@@ -44,11 +44,14 @@ export default class SignInDialog extends Component {
     );
   }
 
-  handleCredentialsSignIn = credentials => {
+  handleCredentialsSignIn = async credentials => {
     const inOneWeek = new Date();
 
     inOneWeek.setDate(inOneWeek.getDate() + 7);
 
+    // Since Apollo caches query results, it’s important to get rid of them
+    // when the login state changes.
+    await this.props.client.resetStore();
     this.props.onAuthorize({
       credentials,
       expires: inOneWeek.toISOString(),
@@ -57,9 +60,6 @@ export default class SignInDialog extends Component {
         displayName: credentials.clientId,
       },
     });
-    // Since Apollo caches query results, it’s important to get rid of them
-    // when the login state changes.
-    this.props.client.resetStore();
     this.props.onClose();
   };

@projectyang
Copy link
Contributor Author

That fixed it!

I ended up using getDerivedStateFromProps to solve scenario one. Let me know your thoughts on that approach.

The eslint error is appearing since I only reference a state field inside getDerivedStateFromProps. Here's a relevant thread with a PR at the end that addresses this.

Copy link
Contributor

@helfi92 helfi92 left a comment

Choose a reason for hiding this comment

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

I like the idea of using getDerivedStateFromProps :) Just some nits.

src/views/Clients/ViewClients/index.jsx Outdated Show resolved Hide resolved
src/views/Clients/ViewClients/index.jsx Outdated Show resolved Hide resolved
src/views/Clients/ViewClients/index.jsx Outdated Show resolved Hide resolved
@helfi92
Copy link
Contributor

helfi92 commented Oct 16, 2018

@projectyang
Copy link
Contributor Author

Travis is hard to please...For the error it's failing on:

error: Unused state field: 'previousClientId' (react/no-unused-state) at src/views/Clients/ViewClients/index.jsx:40:5:

I believe it should pass since we are referring to the state previousClientId in getDerivedStateFromProps. This seems to be more of a problem with the eslint rules than the code in my opinion.

See this thread here - which reflects updates made to eslint-plugin-react which allows for this to pass.

The other option could be trying to incorporate previousClientId somewhere else in the component, which seems unnecessary if it's just to satisfy a rule.

@eliperelman
Copy link
Contributor

It's throwing because the previousClientId isn't used within render, which is a smell for something incorrect being done.

@projectyang
Copy link
Contributor Author

projectyang commented Oct 17, 2018

@eliperelman, can you help clarify for me why this is a smell? Apologies for my inexperience with React.

I was under the impression that this pattern was acceptable based on the React docs example.

My belief that this is an issue with the eslint package is based on this thread here for eslint-plugin-react where others have complained about similar situations regarding no-unused-state and getDerivedStateFromProps, which was eventually resolved and merged into master here.

state = {
clientSearch: '',
previousClientId: '',
Copy link
Contributor

Choose a reason for hiding this comment

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

You can remove the error with:

// eslint-disable-next-line react/no-unused-state
previousClientId: '',

It's also done in

// eslint-disable-next-line react/no-unused-state
.

Copy link
Contributor

@helfi92 helfi92 left a comment

Choose a reason for hiding this comment

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

Fantastic work 🎉

@helfi92 helfi92 merged commit 2c2fa70 into taskcluster:master Oct 17, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants