Skip to content

Commit

Permalink
Implement Base Structure and GitHub OAuth Login (#97)
Browse files Browse the repository at this point in the history
* Initializing theme files (#11)

* Adding a basic mantine theme file. It will be updated as the code base develops.

Any colors or gaps will not be hardcoded.

They should first be defined in the theme and then should be used in the code.

* updating .gitignore

* Includes a comprehensive test setup with mock data and support structure. (#12)

setting up tests in the future will be easier.

* 9 tech debt setup public private routing (#13)

* Working version of routing

* Implemented routing, however tests for the login page needs to figured out.

* implemented notification from mantine (#14)

* 8 feature implement login functionality using GitHub oauth (#15)

* clean up

* A simple but beautiful login page

* Github Oauth setup

* 16 tech debt complete todos (#17)

* Fixed testing setup and have all tests for OAuth.

* Fixed remaining TODOs, added tests.

* Adding a DEVELOPER.md and .env.example
  • Loading branch information
cskcvarma authored May 29, 2024
1 parent 71de70f commit d003469
Show file tree
Hide file tree
Showing 74 changed files with 1,279 additions and 400 deletions.
8 changes: 8 additions & 0 deletions ui/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
VITE_GITHUB_CLIENT_ID=your_client_id
VITE_GITHUB_REDIRECT_URI=http://localhost:3000/oauth/callback
VITE_GITHUB_CLIENT_SECRET=your_client_secret
VITE_GITHUB_CLIENT_USER_IDENTITY_URL=https://github.com/login/oauth/authorize
VITE_GITHUB_LOGIN_URL=https://github.com/login/oauth/access_token
VITE_GITHUB_CORS_LOGIN_URL=https://cors-anywhere.herokuapp.com/https://github.com/login/oauth/authorize
VITE_GITHUB_SCOPES=repo
VITE_STORAGE_EXPIRY_DURATION=21600000
2 changes: 1 addition & 1 deletion ui/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
*.mjs
*.d.ts
*.d.mts
vite.config.ts
vite.config.ts!/coverage/
99 changes: 99 additions & 0 deletions ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,102 @@ yarn-debug.log*
yarn-error.log*
/.stylelintcache
/.eslintcache
!/coverage/
!/.eslintcache
/.eslintcache
/coverage/ui/src/api/api-client.ts.html
/coverage/ui/src/App.tsx.html
/coverage/ui/src/providers/app-provider.tsx.html
/coverage/ui/src/layouts/AppLayout.tsx.html
/coverage/ui/src/providers/auth-provider/auth-provider.tsx.html
/coverage/ui/src/store/auth-store/auth-store.ts.html
/coverage/base.css
/coverage/block-navigation.js
/coverage/clover.xml
/coverage/coverage-final.json
/coverage/favicon.png
/coverage/ui/src/api/github-client.ts.html
/coverage/ui/src/components/Header/Header.tsx.html
/coverage/ui/src/api/repos/github/index.html
/coverage/ui/src/api/repos/index.html
/coverage/ui/src/api/user/github/index.html
/coverage/ui/src/api/user/index.html
/coverage/ui/src/api/index.html
/coverage/ui/src/components/Header/ReposList/index.html
/coverage/ui/src/components/Header/UserMenu/index.html
/coverage/ui/src/components/Header/index.html
/coverage/ui/src/components/Loading/index.html
/coverage/ui/src/components/NavBar/index.html
/coverage/ui/src/components/index.html
/coverage/ui/src/layouts/index.html
/coverage/ui/src/providers/auth-provider/index.html
/coverage/ui/src/providers/index.html
/coverage/ui/src/store/auth-store/index.html
/coverage/ui/src/store/index.html
/coverage/ui/src/utils/index.html
/coverage/ui/src/index.html
/coverage/ui/test-utils/index.html
/coverage/ui/index.html
/coverage/index.html
/coverage/ui/src/api/repos/github/index.ts.html
/coverage/ui/src/api/repos/index.ts.html
/coverage/ui/src/api/user/github/index.ts.html
/coverage/ui/src/api/user/index.ts.html
/coverage/ui/src/api/index.ts.html
/coverage/ui/src/components/Header/ReposList/index.ts.html
/coverage/ui/src/components/Header/UserMenu/index.ts.html
/coverage/ui/src/components/Header/index.ts.html
/coverage/ui/src/components/Loading/index.ts.html
/coverage/ui/src/components/NavBar/index.ts.html
/coverage/ui/src/components/index.ts.html
/coverage/ui/src/layouts/index.ts.html
/coverage/ui/src/providers/auth-provider/index.ts.html
/coverage/ui/src/providers/index.ts.html
/coverage/ui/src/store/auth-store/index.ts.html
/coverage/ui/src/store/index.ts.html
/coverage/ui/src/utils/index.ts.html
/coverage/ui/test-utils/index.ts.html
/coverage/ui/src/components/Loading/Loading.tsx.html
/coverage/ui/src/main.tsx.html
/coverage/ui/src/providers/mantine-provider.tsx.html
/coverage/ui/src/components/NavBar/NavBar.tsx.html
/coverage/ui/postcss.config.cjs.html
/coverage/prettify.css
/coverage/prettify.js
/coverage/ui/src/providers/react-query-provider.tsx.html
/coverage/ui/test-utils/render.tsx.html
/coverage/ui/src/api/repos/repo-query-keys.ts.html
/coverage/ui/src/components/Header/ReposList/ReposList.tsx.html
/coverage/sort-arrow-sprite.png
/coverage/sorter.js
/coverage/ui/src/theme.ts.html
/coverage/ui/src/api/repos/github/use-repos.ts.html
/coverage/ui/src/api/user/github/use-user.ts.html
/coverage/ui/src/api/user/user-query-keys.ts.html
/coverage/ui/src/components/Header/UserMenu/UserMenu.tsx.html
/coverage/ui/src/utils/yaml_to_json.ts.html
/coverage/ui/test-utils/__mocks__/dynamic-store.mock.ts.html
/coverage/ui/test-utils/__mocks__/index.html
/coverage/ui/test-utils/__mocks__/index.ts.html
/coverage/ui/test-utils/__mocks__/repo.mock.ts.html
/coverage/ui/test-utils/__mocks__/repos.mock.ts.html
/coverage/ui/test-utils/__mocks__/user.mock.ts.html
/coverage/.tmp/coverage-0.json
/coverage/.tmp/coverage-1.json
/coverage/.tmp/coverage-2.json
/coverage/.tmp/coverage-3.json
/coverage/.tmp/coverage-4.json
/coverage/.tmp/coverage-5.json
/coverage/.tmp/coverage-6.json
/coverage/.tmp/coverage-7.json
/coverage/ui/src/pages/Login/index.html
/coverage/ui/src/pages/index.html
/coverage/ui/src/routes/index.html
/coverage/ui/src/pages/Login/index.ts.html
/coverage/ui/src/pages/index.ts.html
/coverage/ui/src/routes/index.ts.html
/coverage/ui/src/utils/isAuthenticated.ts.html
/coverage/ui/src/pages/Login/Login.tsx.html
/coverage/ui/src/routes/protected.tsx.html
/coverage/ui/src/routes/router.tsx.html
/coverage/ui/src/providers/router-provider.tsx.html
8 changes: 6 additions & 2 deletions ui/.stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,9 @@
"ignorePseudoClasses": ["global"]
}
]
}
}
},
"ignoreFiles": [
"coverage/**",
"node_modules/**"
]
}
47 changes: 47 additions & 0 deletions ui/DEVELOPER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Developer Setup Guide

## Setting Up GitHub OAuth

To set up GitHub OAuth for this application, you will need to configure several environment variables in a `.env.local` file. Below are the steps to get you started.

1. **Create a GitHub OAuth App**:
- Go to [GitHub Developer Settings](https://github.com/settings/developers).
- Click on "New OAuth App".
- Fill in the details with your application's information:
- **Application name**: Your app's name
- **Homepage URL**: `http://localhost:3000`
- **Authorization callback URL**: `http://localhost:3000/oauth/callback`
- After creating the app, you will get a **Client ID** and **Client Secret**.

2. **Set Environment Variables**:
- Create a file named `.env.local` in the root directory of your project.
- Copy and paste the following template into `.env.local` and fill in the values with your GitHub OAuth credentials and URLs.

```plaintext
VITE_GITHUB_CLIENT_ID=your_client_id
VITE_GITHUB_REDIRECT_URI=http://localhost:3000/oauth/callback
VITE_GITHUB_CLIENT_SECRET=your_client_secret
VITE_GITHUB_CLIENT_USER_IDENTITY_URL=https://github.com/login/oauth/authorize
VITE_GITHUB_LOGIN_URL=https://github.com/login/oauth/access_token
VITE_GITHUB_CORS_LOGIN_URL=https://cors-anywhere.herokuapp.com/https://github.com/login/oauth/authorize
VITE_GITHUB_SCOPES=repo
VITE_STORAGE_EXPIRY_DURATION=21600000
```
3. **Run the Application**:
- Make sure you have all dependencies installed.
- Start the development server:
```sh
npm install
npm run dev
```
## Additional Notes
- The `VITE_GITHUB_CORS_LOGIN_URL` is used to handle CORS issues during development. You might need to adjust this depending on your deployment environment.
- The `VITE_STORAGE_EXPIRY_DURATION` is set to 6 hours (21600000 milliseconds).
By following these steps, you should be able to set up and run the application with GitHub OAuth configured.
Happy coding!
9 changes: 8 additions & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"build": "tsc && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"clean": "rm -rf node_modules && rm -rf coverage && yarn cache clean",
"ci": "npm run clean && yarn install",
"code:fix": "npm run lint:fix && npm run prettier:write && npm run typecheck",
"lint": "npm run lint:eslint && npm run lint:stylelint",
"lint:fix": "npm run lint:eslint:fix && npm run lint:stylelint:fix",
Expand All @@ -17,13 +19,15 @@
"prettier": "prettier --check \"**/*.{ts,tsx}\"",
"prettier:write": "prettier --write \"**/*.{ts,tsx}\"",
"vitest": "vitest run",
"vitest:cover": "vitest run --coverage",
"vitest:watch": "vitest",
"test": "npm run typecheck && npm run prettier && npm run lint && npm run vitest"
"test": "npm run typecheck && npm run prettier && npm run lint && npm run vitest:cover"
},
"dependencies": {
"@mantine/core": "^7.9.0",
"@mantine/form": "^7.9.0",
"@mantine/hooks": "^7.9.0",
"@mantine/notifications": "^7.9.2",
"@tabler/icons-react": "^3.3.0",
"@tanstack/react-query": "^5.34.1",
"@testing-library/dom": "^10.1.0",
Expand All @@ -37,6 +41,7 @@
"zustand": "^4.5.2"
},
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@tanstack/react-query-devtools": "^5.34.1",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
Expand All @@ -50,6 +55,7 @@
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^1.6.0",
"eslint": "^8.57.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^18.0.0",
Expand All @@ -69,6 +75,7 @@
"stylelint-config-standard-scss": "^13.0.0",
"typescript": "^5.4.5",
"vite": "^5.2.10",
"vite-plugin-istanbul": "^6.0.2",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "^1.5.2"
}
Expand Down
8 changes: 2 additions & 6 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import '@mantine/core/styles.css';
import '@mantine/notifications/styles.css';
import React, { FC } from 'react';
import './App.css';
import { AppLayout } from '@/layouts';
import { AppProvider } from '@/providers';

export const App: FC = () => (
<AppProvider>
<AppLayout />
</AppProvider>
);
export const App: FC = () => <AppProvider />;
Empty file.
38 changes: 0 additions & 38 deletions ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tsx

This file was deleted.

Empty file.
Empty file removed ui/src/HOC/index.ts
Empty file.
35 changes: 35 additions & 0 deletions ui/src/__tests__/theme.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { theme } from '@/theme';

describe('Theme Configuration', () => {
describe('Colors', () => {
it('should have deepBlue and blue color palettes defined', () => {
expect(theme.colors?.deepBlue).toBeDefined();
expect(theme.colors?.blue).toBeDefined();
});

it('should have 10 shades for deepBlue', () => {
expect(theme.colors?.deepBlue?.length).toBe(10);
});
});

describe('Shadows', () => {
it('should define medium and extra-large shadows', () => {
expect(theme.shadows?.md).toBeDefined();
expect(theme.shadows?.xl).toBeDefined();
});

it('should have correct shadow value for md', () => {
expect(theme.shadows?.md).toBe('1px 1px 3px rgba(0, 0, 0, .25)');
});
});

describe('Typography', () => {
it('should have a Roboto font family for headings', () => {
expect(theme.headings?.fontFamily).toBe('Roboto, sans-serif');
});

it('should define font size for h1', () => {
expect(theme.headings?.sizes?.h1?.fontSize).toBeDefined();
});
});
});
20 changes: 13 additions & 7 deletions ui/src/api/github-client.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import axios from 'axios';
import { useAuthStore } from '@/store';

export const gitHubClient = () => {
//TODO: Is this a good practice?
const { token } = useAuthStore.getState();

return axios.create({
export const gitHubClient = () =>
axios.create({
baseURL: 'https://api.github.com/',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});

const GithubLoginCredentials = {
clientId: import.meta.env.VITE_GITHUB_CLIENT_ID,
loginUrl: import.meta.env.VITE_GITHUB_CLIENT_USER_IDENTITY_URL,
redirectUri: import.meta.env.VITE_GITHUB_REDIRECT_URI,
scopes: import.meta.env.VITE_GITHUB_SCOPES,
};

export const githubLogin = () => {
const { loginUrl, clientId, redirectUri, scopes } = GithubLoginCredentials;
window.location.href = `${loginUrl}?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scopes}`;
};
2 changes: 2 additions & 0 deletions ui/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { apiClient } from './api-client';
export { githubLogin } from './github-client';

export * from './user';
export * from './repos';
export * from './oauth';
1 change: 1 addition & 0 deletions ui/src/api/oauth/github/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './use-oauth';
24 changes: 24 additions & 0 deletions ui/src/api/oauth/github/use-oauth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import axios from 'axios';
import { useQuery } from '@tanstack/react-query';

export const exchangeGithubCodeForToken = async (code: string | null) => {
const data = {
client_id: import.meta.env.VITE_GITHUB_CLIENT_ID,
client_secret: import.meta.env.VITE_GITHUB_CLIENT_SECRET,
code,
redirectUri: import.meta.env.VITE_GITHUB_REDIRECT_URI,
};
const response = await axios.post('/login/oauth/access_token', data, {
headers: {
Accept: 'application/json',
},
});
return response.data as OAuth;
};

export const useOAuth = ({ code }: { code: string | null }) =>
useQuery({
queryKey: ['Github', 'oauth', code],
queryFn: () => exchangeGithubCodeForToken(code),
retry: 1,
});
1 change: 1 addition & 0 deletions ui/src/api/oauth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './github';
5 changes: 5 additions & 0 deletions ui/src/api/oauth/oauth.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type OAuth = {
access_token: string;
scope: string;
token_type: string;
};
Loading

0 comments on commit d003469

Please sign in to comment.