Repository: gitify-app/gitify
Pull request #999 (2024-04-11 14:16:52)

refactor: improve PAT login experience
Main updates
- improve formatting of content
- simplify help text descriptions
- simplify Generate PAT
- new PAT url includes date created (inspired by Graphite experience).

| Current | New |
| --- | --- |
|![Screenshot 2024-04-11 at 10 15 04 AM](https://github.com/gitify-app/gitify/assets/386277/345fe71f-d37d-4afa-885a-9ddc00d7e8fc)![Screenshot 2024-04-11 at 10 16 10 AM](https://github.com/gitify-app/gitify/assets/386277/37a5c09f-498c-43b7-892d-0b7cb8842a5e) |![Screenshot 2024-04-11 at 10 02 57 AM](https://github.com/gitify-app/gitify/assets/386277/b8534c67-8923-45ea-b949-ed3b17273a9a)  ![Screenshot 2024-04-11 at 10 07 40 AM](https://github.com/gitify-app/gitify/assets/386277/8c040f6f-db33-45d4-86f0-ce2baf04f386) |









Patch:
diff --git a/.husky/pre-commit b/.husky/pre-commit
index c6254913..db4bafce 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,2 +1,2 @@
 pnpx lint-staged
-pnpm test -- --onlyChanged
+pnpm test
\ No newline at end of file
diff --git a/src/components/fields/FieldInput.tsx b/src/components/fields/FieldInput.tsx
index 93093278..669c0763 100644
--- a/src/components/fields/FieldInput.tsx
+++ b/src/components/fields/FieldInput.tsx
@@ -31,7 +31,7 @@ export const FieldInput: FC<IProps> = ({
 
           <input
             type={type}
-            className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none"
+            className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none text-sm"
             id={input.name}
             placeholder={placeholder}
             required={required}
diff --git a/src/routes/LoginWithToken.tsx b/src/routes/LoginWithToken.tsx
index fa533303..2f05eade 100644
--- a/src/routes/LoginWithToken.tsx
+++ b/src/routes/LoginWithToken.tsx
@@ -10,6 +10,8 @@ import type { AuthTokenOptions } from '../types';
 import { openExternalLink } from '../utils/comms';
 import { Constants } from '../utils/constants';
 
+import { format } from 'date-fns';
+
 interface IValues {
   token?: string;
   hostname?: string;
@@ -53,6 +55,9 @@ export const LoginWithToken: FC = () => {
   const renderForm = (formProps: FormRenderProps) => {
     const { handleSubmit, submitting, pristine, values } = formProps;
 
+    const buttonClasses =
+      'rounded bg-gray-300 font-semibold rounded text-sm text-center hover:bg-gray-500 hover:text-white dark:text-black focus:outline-none cursor-pointer';
+
     return (
       <form onSubmit={handleSubmit}>
         <FieldInput
@@ -60,25 +65,21 @@ export const LoginWithToken: FC = () => {
           label="Token"
           placeholder="The 40 characters token generated on GitHub"
           helpText={
-            <>
-              To generate a token, go to GitHub,{' '}
-              <button
-                type="button"
-                className="underline hover:text-gray-500 dark:hover:text-gray-300  cursor-pointer"
-                onClick={() =>
-                  openLink(
-                    'https://github.com/settings/tokens/new?scopes=notifications,read:user,repo&description=gitify_token',
-                  )
-                }
-              >
-                personal access tokens
-              </button>{' '}
-              and create one with the {Constants.AUTH_SCOPE.length} scopes{' '}
-              <span className="underline font-extrabold text-yellow-500">
-                {Constants.AUTH_SCOPE.join(', ')}{' '}
-              </span>
-              .
-            </>
+            <div>
+              <div>
+                Create a Personal Access Token on GitHub and paste above.
+              </div>
+              <div>
+                The required scopes will be selected for you.{' '}
+                <button
+                  type="button"
+                  className={`px-2 py-1 my-2 text-xs ${buttonClasses}`}
+                  onClick={() => openLink(getNewTokenURL())}
+                >
+                  Generate a PAT
+                </button>
+              </div>
+            </div>
           }
         />
 
@@ -86,7 +87,14 @@ export const LoginWithToken: FC = () => {
           name="hostname"
           label="Hostname"
           placeholder="github.company.com"
-          helpText="Defaults to github.com. Change only if you are using GitHub for Enterprise."
+          helpText={
+            <div>
+              <div>Defaults to github.com.</div>
+              <div className="italic">
+                Change only if you are using GitHub Enterprise Server.
+              </div>
+            </div>
+          }
         />
 
         {!isValidToken && (
@@ -96,7 +104,7 @@ export const LoginWithToken: FC = () => {
         )}
 
         <button
-          className="float-right px-4 py-2 my-4 bg-gray-300 font-semibold rounded text-sm text-center hover:bg-gray-500 hover:text-white dark:text-black focus:outline-none"
+          className={`float-right px-4 py-2 my-4 ${buttonClasses}`}
           title="Submit Button"
           disabled={submitting || pristine}
           type="submit"
@@ -134,7 +142,7 @@ export const LoginWithToken: FC = () => {
         </button>
 
         <h3 className="text-lg font-semibold">
-          Login with personal access token
+          Login with Personal Access Token
         </h3>
       </div>
 
@@ -153,3 +161,12 @@ export const LoginWithToken: FC = () => {
     </div>
   );
 };
+
+function getNewTokenURL(): string {
+  const date = format(new Date(), 'PP p');
+  const newTokenURL = new URL('https://github.com/settings/tokens/new');
+  newTokenURL.searchParams.append('description', `Gitify (Created on ${date})`);
+  newTokenURL.searchParams.append('scopes', Constants.AUTH_SCOPE.join(','));
+
+  return newTokenURL.toString();
+}
diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx
index 89eb56c2..ddc94a44 100644
--- a/src/routes/Settings.tsx
+++ b/src/routes/Settings.tsx
@@ -244,7 +244,7 @@ export const SettingsRoute: FC = () => {
           <button
             type="button"
             className={footerButtonClass}
-            title={`Logout ${accounts.user.login}`}
+            title={`Logout from ${accounts.user.login}`}
             role="button"
             onClick={logoutUser}
           >


Test patch:
diff --git a/src/routes/LoginWithToken.test.tsx b/src/routes/LoginWithToken.test.tsx
index 6b5c5e44..cb50d13d 100644
--- a/src/routes/LoginWithToken.test.tsx
+++ b/src/routes/LoginWithToken.test.tsx
@@ -72,7 +72,7 @@ describe('routes/LoginWithToken.tsx', () => {
     expect(validate(values).token).toBe('Invalid token.');
   });
 
-  it("should click on the 'personal access tokens' link and open the browser", async () => {
+  it("should click on the 'Generate a PAT' link and open the browser", async () => {
     render(
       <AppContext.Provider value={{ validateToken: mockValidateToken }}>
         <MemoryRouter>
@@ -81,7 +81,7 @@ describe('routes/LoginWithToken.tsx', () => {
       </AppContext.Provider>,
     );
 
-    fireEvent.click(screen.getByText('personal access tokens'));
+    fireEvent.click(screen.getByText('Generate a PAT'));
 
     expect(openExternalMock).toHaveBeenCalledTimes(1);
   });
diff --git a/src/routes/Settings.test.tsx b/src/routes/Settings.test.tsx
index 26ba42a9..eefc923b 100644
--- a/src/routes/Settings.test.tsx
+++ b/src/routes/Settings.test.tsx
@@ -64,7 +64,7 @@ describe('routes/Settings.tsx', () => {
       );
     });
 
-    fireEvent.click(screen.getByTitle('Logout octocat'));
+    fireEvent.click(screen.getByTitle('Logout from octocat'));
 
     expect(logoutMock).toHaveBeenCalledTimes(1);
 
diff --git a/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap b/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap
index c913860c..109d0a93 100644
--- a/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap
+++ b/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap
@@ -58,7 +58,7 @@ exports[`routes/LoginEnterprise.tsx renders correctly 1`] = `
           Hostname
         </label>
         <input
-          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none"
+          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none text-sm"
           id="hostname"
           name="hostname"
           onBlur={[Function]}
@@ -80,7 +80,7 @@ exports[`routes/LoginEnterprise.tsx renders correctly 1`] = `
           Client ID
         </label>
         <input
-          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none"
+          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none text-sm"
           id="clientId"
           name="clientId"
           onBlur={[Function]}
@@ -102,7 +102,7 @@ exports[`routes/LoginEnterprise.tsx renders correctly 1`] = `
           Client Secret
         </label>
         <input
-          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none"
+          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none text-sm"
           id="clientSecret"
           name="clientSecret"
           onBlur={[Function]}
diff --git a/src/routes/__snapshots__/LoginWithToken.test.tsx.snap b/src/routes/__snapshots__/LoginWithToken.test.tsx.snap
index 79dadca9..36969118 100644
--- a/src/routes/__snapshots__/LoginWithToken.test.tsx.snap
+++ b/src/routes/__snapshots__/LoginWithToken.test.tsx.snap
@@ -39,7 +39,7 @@ exports[`routes/LoginWithToken.tsx renders correctly 1`] = `
     <h3
       className="text-lg font-semibold"
     >
-      Login with personal access token
+      Login with Personal Access Token
     </h3>
   </div>
   <div
@@ -58,7 +58,7 @@ exports[`routes/LoginWithToken.tsx renders correctly 1`] = `
           Token
         </label>
         <input
-          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none"
+          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none text-sm"
           id="token"
           name="token"
           onBlur={[Function]}
@@ -72,27 +72,22 @@ exports[`routes/LoginWithToken.tsx renders correctly 1`] = `
         <div
           className="mt-3 text-gray-700 dark:text-gray-200 text-xs"
         >
-          To generate a token, go to GitHub,
-           
-          <button
-            className="underline hover:text-gray-500 dark:hover:text-gray-300  cursor-pointer"
-            onClick={[Function]}
-            type="button"
-          >
-            personal access tokens
-          </button>
-           
-          and create one with the 
-          3
-           scopes
-           
-          <span
-            className="underline font-extrabold text-yellow-500"
-          >
-            read:user, notifications, repo
-             
-          </span>
-          .
+          <div>
+            <div>
+              Create a Personal Access Token on GitHub and paste above.
+            </div>
+            <div>
+              The required scopes will be selected for you.
+               
+              <button
+                className="px-2 py-1 my-2 text-xs rounded bg-gray-300 font-semibold rounded text-sm text-center hover:bg-gray-500 hover:text-white dark:text-black focus:outline-none cursor-pointer"
+                onClick={[Function]}
+                type="button"
+              >
+                Generate a PAT
+              </button>
+            </div>
+          </div>
         </div>
       </div>
       <div
@@ -105,7 +100,7 @@ exports[`routes/LoginWithToken.tsx renders correctly 1`] = `
           Hostname
         </label>
         <input
-          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none"
+          className="appearance-none block w-full dark:text-gray-800 bg-gray-100 border border-red rounded py-1.5 px-4 mb-2 focus:bg-gray-200 focus:outline-none text-sm"
           id="hostname"
           name="hostname"
           onBlur={[Function]}
@@ -119,11 +114,20 @@ exports[`routes/LoginWithToken.tsx renders correctly 1`] = `
         <div
           className="mt-3 text-gray-700 dark:text-gray-200 text-xs"
         >
-          Defaults to github.com. Change only if you are using GitHub for Enterprise.
+          <div>
+            <div>
+              Defaults to github.com.
+            </div>
+            <div
+              className="italic"
+            >
+              Change only if you are using GitHub Enterprise Server.
+            </div>
+          </div>
         </div>
       </div>
       <button
-        className="float-right px-4 py-2 my-4 bg-gray-300 font-semibold rounded text-sm text-center hover:bg-gray-500 hover:text-white dark:text-black focus:outline-none"
+        className="float-right px-4 py-2 my-4 rounded bg-gray-300 font-semibold rounded text-sm text-center hover:bg-gray-500 hover:text-white dark:text-black focus:outline-none cursor-pointer"
         disabled={true}
         title="Submit Button"
         type="submit"
diff --git a/src/routes/__snapshots__/Settings.test.tsx.snap b/src/routes/__snapshots__/Settings.test.tsx.snap
index 3948a30f..d871c688 100644
--- a/src/routes/__snapshots__/Settings.test.tsx.snap
+++ b/src/routes/__snapshots__/Settings.test.tsx.snap
@@ -416,7 +416,7 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
       <button
         class="hover:text-gray-500 py-1 px-2 my-1 mx-2 focus:outline-none"
         role="button"
-        title="Logout octocat"
+        title="Logout from octocat"
         type="button"
       >
         <svg