From 54f22f3dbbf35b9f61522afa7dd9046ae10348fc Mon Sep 17 00:00:00 2001 From: Sri Krishna Chekuri Date: Thu, 16 May 2024 08:20:23 -0400 Subject: [PATCH 1/6] 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 --- ui/.eslintignore | 2 +- ui/.gitignore | 74 ++++++++++++ ui/.stylelintrc.json | 8 +- ui/package.json | 4 +- .../WithLoadingAndError.tests.tsx | 0 .../WithLoadingAndError.tsx | 38 ------- ui/src/HOC/WithLoadingAndError/index.ts | 0 ui/src/HOC/index.ts | 0 ui/src/__tests__/theme.test.ts | 35 ++++++ .../{Loading.tests.tsx => Loading.test.tsx} | 0 ui/src/providers/mantine-provider.tsx | 4 +- ui/src/theme.ts | 43 ++++++- ui/vite.config.mjs | 11 +- ui/yarn.lock | 105 +++++++++++++++++- 14 files changed, 271 insertions(+), 53 deletions(-) delete mode 100644 ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tests.tsx delete mode 100644 ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tsx delete mode 100644 ui/src/HOC/WithLoadingAndError/index.ts delete mode 100644 ui/src/HOC/index.ts create mode 100644 ui/src/__tests__/theme.test.ts rename ui/src/components/Loading/{Loading.tests.tsx => Loading.test.tsx} (100%) diff --git a/ui/.eslintignore b/ui/.eslintignore index 6805ef16..eaa4ba38 100644 --- a/ui/.eslintignore +++ b/ui/.eslintignore @@ -3,4 +3,4 @@ *.mjs *.d.ts *.d.mts -vite.config.ts \ No newline at end of file +vite.config.ts!/coverage/ diff --git a/ui/.gitignore b/ui/.gitignore index 87c91007..03029944 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -23,3 +23,77 @@ 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 diff --git a/ui/.stylelintrc.json b/ui/.stylelintrc.json index 971ae9cf..5b36a97d 100644 --- a/ui/.stylelintrc.json +++ b/ui/.stylelintrc.json @@ -24,5 +24,9 @@ "ignorePseudoClasses": ["global"] } ] - } -} \ No newline at end of file + }, + "ignoreFiles": [ + "coverage/**", + "node_modules/**" + ] +} diff --git a/ui/package.json b/ui/package.json index 69b4a61a..4f8eaa28 100644 --- a/ui/package.json +++ b/ui/package.json @@ -17,8 +17,9 @@ "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", @@ -50,6 +51,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", diff --git a/ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tests.tsx b/ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tests.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tsx b/ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tsx deleted file mode 100644 index db55a22c..00000000 --- a/ui/src/HOC/WithLoadingAndError/WithLoadingAndError.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { ComponentType, FC } from 'react'; -import { Alert } from '@mantine/core'; -import { Loading } from '@/components'; - -interface WithLoadingAndErrorProps { - isLoading: boolean; - error: string | null; -} - -// TODO: Not using this, as I dont want to get into prop drilling. Keeping it for reference, -// need to investigate other venues -/* eslint-disable @typescript-eslint/no-unused-vars */ -export const withLoadingAndError = ( - WrappedComponent: ComponentType -) => { - /* eslint-disable @typescript-eslint/no-unused-vars */ - const WithLoadingAndError: FC = ({ - isLoading, - error, - ...props - }) => { - if (isLoading) { - return ; - } - - if (error) { - return ; // You can style this or handle different types of errors differently - } - - return ; - }; -}; -/* eslint-enable @typescript-eslint/no-unused-vars */ -const ErrorComponent = () => ( - - Error! - -); diff --git a/ui/src/HOC/WithLoadingAndError/index.ts b/ui/src/HOC/WithLoadingAndError/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/src/HOC/index.ts b/ui/src/HOC/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/src/__tests__/theme.test.ts b/ui/src/__tests__/theme.test.ts new file mode 100644 index 00000000..60e09602 --- /dev/null +++ b/ui/src/__tests__/theme.test.ts @@ -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(); + }); + }); +}); diff --git a/ui/src/components/Loading/Loading.tests.tsx b/ui/src/components/Loading/Loading.test.tsx similarity index 100% rename from ui/src/components/Loading/Loading.tests.tsx rename to ui/src/components/Loading/Loading.test.tsx diff --git a/ui/src/providers/mantine-provider.tsx b/ui/src/providers/mantine-provider.tsx index 98aceae6..1ea3fcbb 100644 --- a/ui/src/providers/mantine-provider.tsx +++ b/ui/src/providers/mantine-provider.tsx @@ -1,7 +1,7 @@ -import { createTheme, MantineProvider } from '@mantine/core'; +import { MantineProvider } from '@mantine/core'; import React from 'react'; import { theme } from '@/theme'; export const CustomMantineProvider = ({ children }: { children: React.ReactNode }) => ( - {children} + {children} ); diff --git a/ui/src/theme.ts b/ui/src/theme.ts index 9868cfb8..fbe6de71 100644 --- a/ui/src/theme.ts +++ b/ui/src/theme.ts @@ -1,6 +1,43 @@ -import { createTheme } from '@mantine/core'; +import { createTheme, rem } from '@mantine/core'; -// TODO: LOOK INTO LIGHT DARK THEME export const theme = createTheme({ - /** Put your mantine theme override here */ + colors: { + deepBlue: [ + '#eef3ff', + '#dce4f5', + '#b9c7e2', + '#94a8d0', + '#748dc1', + '#5f7cb8', + '#5474b4', + '#44639f', + '#39588f', + '#2d4b81', + ], + + blue: [ + '#eef3ff', + '#dee2f2', + '#bdc2de', + '#98a0ca', + '#7a84ba', + '#6672b0', + '#5c68ac', + '#4c5897', + '#424e88', + '#364379', + ], + }, + + shadows: { + md: '1px 1px 3px rgba(0, 0, 0, .25)', + xl: '5px 5px 3px rgba(0, 0, 0, .25)', + }, + + headings: { + fontFamily: 'Roboto, sans-serif', + sizes: { + h1: { fontSize: rem(36) }, + }, + }, }); diff --git a/ui/vite.config.mjs b/ui/vite.config.mjs index d225fb8d..8066cdcd 100644 --- a/ui/vite.config.mjs +++ b/ui/vite.config.mjs @@ -9,4 +9,13 @@ export default defineConfig({ environment: 'jsdom', setupFiles: './vitest.setup.mjs', }, -}); \ No newline at end of file + coverage: { + provider: 'c8', + reporter: ['text', 'html'], + exclude: [ + '**/index.ts', + '**/node_modules/**', + '**/tests/**' + ] + } +}); diff --git a/ui/yarn.lock b/ui/yarn.lock index ac11e8cc..fea5439d 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.3.tgz#90749bde8b89cd41764224f5aac29cd4138f75ff" integrity sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ== -"@ampproject/remapping@^2.2.0": +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.2.1": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== @@ -161,7 +161,7 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.24.0", "@babel/parser@^7.24.4", "@babel/parser@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== @@ -221,6 +221,11 @@ "@babel/helper-validator-identifier" "^7.24.5" to-fast-properties "^2.0.0" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@csstools/css-parser-algorithms@^2.6.1": version "2.6.3" resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.3.tgz#b5e7eb2bd2a42e968ef61484f1490a8a4148a8eb" @@ -465,6 +470,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + "@jest/expect-utils@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" @@ -515,7 +525,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -1034,6 +1044,25 @@ "@types/babel__core" "^7.20.5" react-refresh "^0.14.0" +"@vitest/coverage-v8@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz#2f54ccf4c2d9f23a71294aba7f95b3d2e27d14e7" + integrity sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew== + dependencies: + "@ampproject/remapping" "^2.2.1" + "@bcoe/v8-coverage" "^0.2.3" + debug "^4.3.4" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^5.0.4" + istanbul-reports "^3.1.6" + magic-string "^0.30.5" + magicast "^0.3.3" + picocolors "^1.0.0" + std-env "^3.5.0" + strip-literal "^2.0.0" + test-exclude "^6.0.0" + "@vitest/expect@1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.0.tgz#0b3ba0914f738508464983f4d811bc122b51fb30" @@ -2396,7 +2425,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.1.3: +glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2548,6 +2577,11 @@ html-encoding-sniffer@^4.0.0: dependencies: whatwg-encoding "^3.1.1" +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + html-tags@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" @@ -2858,6 +2892,37 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.4.tgz#1947003c72a91b6310efeb92d2a91be8804d92c2" + integrity sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.23" + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + +istanbul-reports@^3.1.6: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -3159,6 +3224,22 @@ magic-string@^0.30.5: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" +magicast@^0.3.3: + version "0.3.4" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.4.tgz#bbda1791d03190a24b00ff3dd18151e7fd381d19" + integrity sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q== + dependencies: + "@babel/parser" "^7.24.4" + "@babel/types" "^7.24.0" + source-map-js "^1.2.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + mathml-tag-names@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" @@ -3214,7 +3295,7 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -3909,6 +3990,11 @@ semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.5.3: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + semver@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" @@ -4279,6 +4365,15 @@ table@^6.8.2: string-width "^4.2.3" strip-ansi "^6.0.1" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" From 1f3f7789e74cda2679a6584e726a3e0428cf0d33 Mon Sep 17 00:00:00 2001 From: Sri Krishna Chekuri Date: Fri, 17 May 2024 16:32:56 -0400 Subject: [PATCH 2/6] Includes a comprehensive test setup with mock data and support structure. (#12) setting up tests in the future will be easier. --- ui/.gitignore | 6 ++ ui/package.json | 3 + ui/src/api/user/github/use-user.ts | 1 - .../Header/ReposList/ReposList.test.tsx | 7 +- .../Header/UserMenu/UserMenu.test.tsx | 5 -- ui/src/components/NavBar/NavBar.tests.ts | 0 .../providers/auth-provider/auth-provider.tsx | 1 - ui/src/store/auth-store/auth-store.test.ts | 2 +- ui/test-utils/__mocks__/dynamic-store.mock.ts | 19 ++++++ ui/test-utils/__mocks__/index.ts | 3 + ui/test-utils/__mocks__/repo.mock.ts | 56 ++++++++++++++++ ui/test-utils/__mocks__/repos.mock.ts | 7 ++ ui/test-utils/__mocks__/user.mock.ts | 56 ++++++++++++++++ ui/test-utils/render.tsx | 64 ++++++++++++++----- ui/vite.config.mjs | 5 +- ui/yarn.lock | 5 ++ 16 files changed, 210 insertions(+), 30 deletions(-) delete mode 100644 ui/src/components/NavBar/NavBar.tests.ts create mode 100644 ui/test-utils/__mocks__/dynamic-store.mock.ts create mode 100644 ui/test-utils/__mocks__/index.ts create mode 100644 ui/test-utils/__mocks__/repo.mock.ts create mode 100644 ui/test-utils/__mocks__/repos.mock.ts create mode 100644 ui/test-utils/__mocks__/user.mock.ts diff --git a/ui/.gitignore b/ui/.gitignore index 03029944..999da65e 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -97,3 +97,9 @@ yarn-error.log* /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 diff --git a/ui/package.json b/ui/package.json index 4f8eaa28..a8e5114b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -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", @@ -38,6 +40,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", diff --git a/ui/src/api/user/github/use-user.ts b/ui/src/api/user/github/use-user.ts index b8c9fd9e..69a5ce19 100644 --- a/ui/src/api/user/github/use-user.ts +++ b/ui/src/api/user/github/use-user.ts @@ -8,7 +8,6 @@ export const getUserFn = async () => { return response.data as User; }; -// TODO: How to convert Github User to generic User type? export const useUser = () => useQuery({ queryKey: userQueryKeys.detail('me'), diff --git a/ui/src/components/Header/ReposList/ReposList.test.tsx b/ui/src/components/Header/ReposList/ReposList.test.tsx index 6b689049..6ddb9b4d 100644 --- a/ui/src/components/Header/ReposList/ReposList.test.tsx +++ b/ui/src/components/Header/ReposList/ReposList.test.tsx @@ -1,13 +1,8 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect } from 'vitest'; import { render, screen } from '@test-utils'; import { ReposList } from './ReposList'; import { useRepos } from '@/api'; -// Mock the API hook -vi.mock('@/api', () => ({ - useRepos: vi.fn(), -})); - describe('ReposList', () => { it('renders loading state correctly', () => { // @ts-ignore diff --git a/ui/src/components/Header/UserMenu/UserMenu.test.tsx b/ui/src/components/Header/UserMenu/UserMenu.test.tsx index 0bdb1480..71c3be41 100644 --- a/ui/src/components/Header/UserMenu/UserMenu.test.tsx +++ b/ui/src/components/Header/UserMenu/UserMenu.test.tsx @@ -4,11 +4,6 @@ import { render, screen } from '@test-utils'; import { UserMenu } from './UserMenu'; import { useUser } from '@/api'; -// Mock the API hook and store -vi.mock('@/api', () => ({ - useUser: vi.fn(), -})); - describe('UserMenu', () => { it('renders loading state correctly', () => { // @ts-ignore diff --git a/ui/src/components/NavBar/NavBar.tests.ts b/ui/src/components/NavBar/NavBar.tests.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/src/providers/auth-provider/auth-provider.tsx b/ui/src/providers/auth-provider/auth-provider.tsx index 94c8abe5..4bd1bd12 100644 --- a/ui/src/providers/auth-provider/auth-provider.tsx +++ b/ui/src/providers/auth-provider/auth-provider.tsx @@ -63,7 +63,6 @@ export const AuthProvider: React.FC = ({ children }) => { - {/*TODO: Handle Error State*/} {token && username ? children : } ); diff --git a/ui/src/store/auth-store/auth-store.test.ts b/ui/src/store/auth-store/auth-store.test.ts index 196aeda3..f73a35ae 100644 --- a/ui/src/store/auth-store/auth-store.test.ts +++ b/ui/src/store/auth-store/auth-store.test.ts @@ -1,5 +1,5 @@ // tests for src/store/auth-store.ts -import { act } from 'react-dom/test-utils'; +import { act } from 'react'; import { renderHook } from '@testing-library/react'; import { useAuthStore } from '@/store/auth-store'; diff --git a/ui/test-utils/__mocks__/dynamic-store.mock.ts b/ui/test-utils/__mocks__/dynamic-store.mock.ts new file mode 100644 index 00000000..7f118f83 --- /dev/null +++ b/ui/test-utils/__mocks__/dynamic-store.mock.ts @@ -0,0 +1,19 @@ +import { vi } from 'vitest'; + +export const createDynamicMockStore = (initialState: any) => + new Proxy(initialState, { + get: (target, prop, receiver) => { + // Automatically create a mock function if the property is not in the state and is a function call + if (typeof target[prop] === 'undefined') { + target[prop] = vi.fn(() => { + // eslint-disable-next-line no-console + console.log(`Called ${String(prop)} with no predefined behavior.`); + }); + } + return Reflect.get(target, prop, receiver); + }, + set: (target, prop, value) => { + target[prop] = value; + return true; + }, + }); diff --git a/ui/test-utils/__mocks__/index.ts b/ui/test-utils/__mocks__/index.ts new file mode 100644 index 00000000..41db9682 --- /dev/null +++ b/ui/test-utils/__mocks__/index.ts @@ -0,0 +1,3 @@ +export * from './user.mock'; +export * from './repo.mock'; +export * from './repos.mock'; diff --git a/ui/test-utils/__mocks__/repo.mock.ts b/ui/test-utils/__mocks__/repo.mock.ts new file mode 100644 index 00000000..dc4ff8e1 --- /dev/null +++ b/ui/test-utils/__mocks__/repo.mock.ts @@ -0,0 +1,56 @@ +import { faker } from '@faker-js/faker'; + +const createSecurityStatusMock = (): SecurityStatus => ({ + status: faker.helpers.arrayElement(['enabled', 'disabled']), +}); + +const createSecurityAndAnalysisMock = (): SecurityAndAnalysis => ({ + advanced_security: createSecurityStatusMock(), + secret_scanning: createSecurityStatusMock(), + secret_scanning_push_protection: createSecurityStatusMock(), +}); + +const createPermissionsMock = (): Permissions => + { + admin: faker.datatype.boolean(), + push: faker.datatype.boolean(), + pull: faker.datatype.boolean(), + }; + +const createOwnerMock = (): Owner => ({ + login: faker.internet.userName(), + id: faker.number.int(), + node_id: faker.string.uuid(), + avatar_url: faker.image.avatar(), + gravatar_id: '', + url: faker.internet.url(), + html_url: faker.internet.url(), + followers_url: faker.internet.url(), + following_url: faker.internet.url(), + gists_url: faker.internet.url(), + starred_url: faker.internet.url(), + subscriptions_url: faker.internet.url(), + organizations_url: faker.internet.url(), + repos_url: faker.internet.url(), + events_url: faker.internet.url(), + received_events_url: faker.internet.url(), + type: 'User', + site_admin: faker.datatype.boolean(), +}); + +export const createRepoMock = (): Repos => + { + id: faker.number.int(), + node_id: faker.string.uuid(), + name: faker.company.name(), + full_name: `${faker.company.name()}/${faker.internet.userName()}`, + owner: createOwnerMock(), + private: faker.datatype.boolean(), + html_url: faker.internet.url(), + description: faker.lorem.sentence(), + fork: faker.datatype.boolean(), + url: faker.internet.url(), + permissions: createPermissionsMock(), + security_and_analysis: createSecurityAndAnalysisMock(), + // Populate other URLs and properties as needed... + }; diff --git a/ui/test-utils/__mocks__/repos.mock.ts b/ui/test-utils/__mocks__/repos.mock.ts new file mode 100644 index 00000000..036f229f --- /dev/null +++ b/ui/test-utils/__mocks__/repos.mock.ts @@ -0,0 +1,7 @@ +import { createRepoMock } from './repo.mock'; + +export const useReposMock = () => ({ + data: Array.from({ length: 10 }, createRepoMock), + isLoading: false, + isError: false, +}); diff --git a/ui/test-utils/__mocks__/user.mock.ts b/ui/test-utils/__mocks__/user.mock.ts new file mode 100644 index 00000000..cd708181 --- /dev/null +++ b/ui/test-utils/__mocks__/user.mock.ts @@ -0,0 +1,56 @@ +import { faker } from '@faker-js/faker'; + +export const createPlanMock = (): Plan => ({ + name: faker.company.name(), + space: faker.number.int({ min: 1000, max: 10000 }), + private_repos: faker.number.int({ max: 100 }), + collaborators: faker.number.int({ max: 10 }), +}); + +export const createUserMock = (): User => ({ + login: faker.internet.userName(), + id: faker.number.int(), + node_id: faker.string.uuid(), + avatar_url: faker.image.avatar(), + gravatar_id: '', + url: faker.internet.url(), + html_url: faker.internet.url(), + followers_url: faker.internet.url(), + following_url: faker.internet.url(), + gists_url: faker.internet.url(), + starred_url: faker.internet.url(), + subscriptions_url: faker.internet.url(), + organizations_url: faker.internet.url(), + repos_url: faker.internet.url(), + events_url: faker.internet.url(), + received_events_url: faker.internet.url(), + type: 'User', + site_admin: faker.datatype.boolean(), + name: faker.person.fullName(), + company: faker.company.name(), + blog: faker.internet.url(), + location: faker.location.secondaryAddress(), + email: faker.internet.email(), + hireable: faker.datatype.boolean(), + bio: faker.lorem.sentence(), + twitter_username: faker.internet.userName(), + public_repos: faker.number.int({ max: 100 }), + public_gists: faker.number.int({ max: 100 }), + followers: faker.number.int({ max: 1000 }), + following: faker.number.int({ max: 1000 }), + created_at: faker.date.past().toISOString(), + updated_at: faker.date.recent().toISOString(), + private_gists: faker.number.int({ max: 100 }), + total_private_repos: faker.number.int({ max: 100 }), + owned_private_repos: faker.number.int({ max: 100 }), + disk_usage: faker.number.int({ max: 10000 }), + collaborators: faker.number.int({ max: 10 }), + two_factor_authentication: faker.datatype.boolean(), + plan: createPlanMock(), +}); + +export const useUserMock = () => ({ + data: createUserMock(), + isLoading: false, + isError: false, +}); diff --git a/ui/test-utils/render.tsx b/ui/test-utils/render.tsx index 87f49c3e..1ef695be 100644 --- a/ui/test-utils/render.tsx +++ b/ui/test-utils/render.tsx @@ -2,24 +2,58 @@ import { render as testingLibraryRender } from '@testing-library/react'; import React from 'react'; import { vi } from 'vitest'; import { AppProvider } from '@/providers'; +import { createDynamicMockStore } from './__mocks__/dynamic-store.mock'; +import { createUserMock, useReposMock, useUserMock } from './__mocks__'; export function render(ui: React.ReactNode) { - vi.mock('@/store', () => ({ - useAuthStore: vi.fn(() => ({ - token: 'mock-token', - username: 'mock-username', - openModal: vi.fn(), - closeModal: vi.fn(), - })), - })); + /* + * Any updates to the store should be replicated here. + * */ + vi.mock('@/store', () => { + const useAuthStore = () => + createDynamicMockStore({ + token: 'test-token', + isModalOpen: false, + username: 'test-username', + }); + return { useAuthStore }; + }); + + /* If additional methods are added to api client, this wrapper needs to be updated + * As api-client is an abstraction of the underlying GitHub client, extending the app to other git managers + * will be easy. And this wrapper doesn't have to be updated. + * */ + vi.mock('@/api/api-client', () => { + const mockAxiosInstance = { + get: vi.fn(() => Promise.resolve({ data: 'mocked get' })), + post: vi.fn(() => Promise.resolve({ data: 'mocked post' })), + put: vi.fn(() => Promise.resolve({ data: 'mocked put' })), + delete: vi.fn(() => Promise.resolve({ data: 'mocked delete' })), + patch: vi.fn(() => Promise.resolve({ data: 'mocked patch' })), + head: vi.fn(() => Promise.resolve({ data: 'mocked head' })), + options: vi.fn(() => Promise.resolve({ data: 'mocked options' })), + request: vi.fn(() => Promise.resolve({ data: 'mocked request' })), + interceptors: { + request: { use: vi.fn(), eject: vi.fn() }, + response: { use: vi.fn(), eject: vi.fn() }, + }, + defaults: { headers: { common: {} } }, + }; + return { + apiClient: mockAxiosInstance, + }; + }); - vi.mock('@/api/github-client', () => ({ - gitHubClient: vi.fn(() => ({ - get: vi.fn(() => Promise.resolve({ data: 'mocked data' })), - post: vi.fn(() => Promise.resolve({ data: 'mocked response' })), - // Add other methods as needed - })), - })); + vi.mock('@/api/user', () => { + const getUserFn = vi.fn(() => Promise.resolve(createUserMock())); + const useUser = vi.fn(() => useUserMock()); + return { getUserFn, useUser }; + }); + + vi.mock('@/api/repo', () => { + const useRepos = vi.fn(() => useReposMock()); + return { useRepos }; + }); return testingLibraryRender(<>{ui}, { wrapper: ({ children }: { children: React.ReactNode }) => {children}, diff --git a/ui/vite.config.mjs b/ui/vite.config.mjs index 8066cdcd..6f3fe7bc 100644 --- a/ui/vite.config.mjs +++ b/ui/vite.config.mjs @@ -12,10 +12,13 @@ export default defineConfig({ coverage: { provider: 'c8', reporter: ['text', 'html'], + // TODO: Exclude test files from coverage is not working exclude: [ '**/index.ts', '**/node_modules/**', - '**/tests/**' + '**/tests/**', + 'ui/test-utils/**', + '**/__mocks__/**', ] } }); diff --git a/ui/yarn.lock b/ui/yarn.lock index fea5439d..3cccfb00 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -415,6 +415,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@faker-js/faker@^8.4.1": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.4.1.tgz#5d5e8aee8fce48f5e189bf730ebd1f758f491451" + integrity sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg== + "@floating-ui/core@^1.0.0": version "1.6.1" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.1.tgz#a4e6fef1b069cda533cbc7a4998c083a37f37573" From fa2b80a683c1b42b8e6f05a06d1c9d436ab79660 Mon Sep 17 00:00:00 2001 From: Sri Krishna Chekuri Date: Wed, 22 May 2024 17:08:26 -0400 Subject: [PATCH 3/6] 9 tech debt setup public private routing (#13) * Working version of routing * Implemented routing, however tests for the login page needs to figured out. --- ui/.gitignore | 8 +++ ui/src/App.tsx | 8 +-- ui/src/api/github-client.ts | 10 +-- ui/src/api/repos/github/use-repos.ts | 6 +- ui/src/api/repos/index.ts | 2 +- ui/src/api/user/github/use-user.ts | 7 +- ui/src/components/Header/Header.tsx | 1 + .../Header/UserMenu/UserMenu.test.tsx | 2 +- ui/src/components/NavBar/NavBar.tsx | 1 + ui/src/pages/Login/Login.css | 11 +++ ui/src/pages/Login/Login.tsx | 55 +++++++++++++++ ui/src/pages/Login/index.ts | 1 + ui/src/pages/index.ts | 1 + ui/src/providers/app-provider.tsx | 6 +- .../auth-provider/auth-provider.test.tsx | 26 ------- .../providers/auth-provider/auth-provider.tsx | 69 ------------------- ui/src/providers/auth-provider/index.ts | 1 - ui/src/providers/index.ts | 3 + ui/src/providers/router-provider.tsx | 4 ++ ui/src/routes/index.ts | 1 + ui/src/routes/protected.tsx | 15 ++++ ui/src/routes/router.tsx | 18 +++++ ui/src/store/auth-store/auth-store.ts | 4 +- .../utils/__tests__/isAuthenticated.test.ts | 46 +++++++++++++ ui/src/utils/index.ts | 1 + ui/src/utils/isAuthenticated.ts | 10 +++ ui/test-utils/render.tsx | 49 ++++++------- 27 files changed, 223 insertions(+), 143 deletions(-) create mode 100644 ui/src/pages/Login/Login.css create mode 100644 ui/src/pages/Login/Login.tsx create mode 100644 ui/src/pages/Login/index.ts create mode 100644 ui/src/pages/index.ts delete mode 100644 ui/src/providers/auth-provider/auth-provider.test.tsx delete mode 100644 ui/src/providers/auth-provider/auth-provider.tsx delete mode 100644 ui/src/providers/auth-provider/index.ts create mode 100644 ui/src/providers/router-provider.tsx create mode 100644 ui/src/routes/index.ts create mode 100644 ui/src/routes/protected.tsx create mode 100644 ui/src/routes/router.tsx create mode 100644 ui/src/utils/__tests__/isAuthenticated.test.ts create mode 100644 ui/src/utils/isAuthenticated.ts diff --git a/ui/.gitignore b/ui/.gitignore index 999da65e..4a1c9e52 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -103,3 +103,11 @@ yarn-error.log* /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 diff --git a/ui/src/App.tsx b/ui/src/App.tsx index a5b4d6b2..0e2d5eb8 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -1,11 +1,7 @@ import '@mantine/core/styles.css'; import React, { FC } from 'react'; import './App.css'; -import { AppLayout } from '@/layouts'; +// import { AppLayout } from '@/layouts'; import { AppProvider } from '@/providers'; -export const App: FC = () => ( - - - -); +export const App: FC = () => ; diff --git a/ui/src/api/github-client.ts b/ui/src/api/github-client.ts index b3e05713..eba13a3a 100644 --- a/ui/src/api/github-client.ts +++ b/ui/src/api/github-client.ts @@ -1,15 +1,9 @@ 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', }, }); -}; diff --git a/ui/src/api/repos/github/use-repos.ts b/ui/src/api/repos/github/use-repos.ts index ef00cb49..8bc57291 100644 --- a/ui/src/api/repos/github/use-repos.ts +++ b/ui/src/api/repos/github/use-repos.ts @@ -6,7 +6,11 @@ import { repoQueryKeys } from '../repo-query-keys'; export const getReposFn = async () => { const { username } = useAuthStore.getState(); - const response = await apiClient.get(`/users/${username || ''}/repos`); + const response = await apiClient.get(`/users/${username || ''}/repos`, { + headers: { + Authorization: `Bearer ${useAuthStore.getState().token}`, + }, + }); return response.data as Repos[]; }; diff --git a/ui/src/api/repos/index.ts b/ui/src/api/repos/index.ts index 7302c7ad..da45b74c 100644 --- a/ui/src/api/repos/index.ts +++ b/ui/src/api/repos/index.ts @@ -1 +1 @@ -export * from './github'; +export { useRepos } from './github'; diff --git a/ui/src/api/user/github/use-user.ts b/ui/src/api/user/github/use-user.ts index 69a5ce19..08a32484 100644 --- a/ui/src/api/user/github/use-user.ts +++ b/ui/src/api/user/github/use-user.ts @@ -1,9 +1,14 @@ import { useQuery } from '@tanstack/react-query'; import { apiClient } from '@/api'; import { userQueryKeys } from '../user-query-keys'; +import { useAuthStore } from '@/store'; export const getUserFn = async () => { - const response = await apiClient.get('/user'); + const response = await apiClient.get('/user', { + headers: { + Authorization: `Bearer ${useAuthStore.getState().token}`, + }, + }); return response.data as User; }; diff --git a/ui/src/components/Header/Header.tsx b/ui/src/components/Header/Header.tsx index 8e259dbb..2c663087 100644 --- a/ui/src/components/Header/Header.tsx +++ b/ui/src/components/Header/Header.tsx @@ -4,6 +4,7 @@ import { Container, Group } from '@mantine/core'; import { UserMenu } from './UserMenu'; import './Header.css'; +// TODO: To be moved to layouts. Repos List and User Menu will be moved to root level of components export const Header: FC = () => (
diff --git a/ui/src/components/Header/UserMenu/UserMenu.test.tsx b/ui/src/components/Header/UserMenu/UserMenu.test.tsx index 71c3be41..8f66d86e 100644 --- a/ui/src/components/Header/UserMenu/UserMenu.test.tsx +++ b/ui/src/components/Header/UserMenu/UserMenu.test.tsx @@ -1,5 +1,5 @@ // -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect } from 'vitest'; import { render, screen } from '@test-utils'; import { UserMenu } from './UserMenu'; import { useUser } from '@/api'; diff --git a/ui/src/components/NavBar/NavBar.tsx b/ui/src/components/NavBar/NavBar.tsx index be8f8b9a..7a212079 100644 --- a/ui/src/components/NavBar/NavBar.tsx +++ b/ui/src/components/NavBar/NavBar.tsx @@ -1,6 +1,7 @@ import './NavBar.css'; import { ReposList } from '@/components/Header/ReposList'; +// TODO: To be moved to Layouts export const NavBar = () => (