diff --git a/.eslintrc.cjs b/.eslintrc.cjs index b130e4b9..f0fbcafe 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -20,11 +20,11 @@ const config = { '@typescript-eslint', 'react-refresh', 'simple-import-sort', - 'import-newlines' + 'import-newlines', ], settings: { 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'] + '@typescript-eslint/parser': ['.ts', '.tsx'], }, 'import/resolver': { typescript: { @@ -66,7 +66,7 @@ const config = { 'import/no-cycle': ['error', { allowUnsafeDynamicCyclicDependency: true }], 'react/react-in-jsx-scope': 'off', - 'camelcase': 'off', + camelcase: 'off', 'react/jsx-indent': ['error', 4], 'react/jsx-indent-props': ['error', 4], @@ -80,7 +80,7 @@ const config = { 'react/require-default-props': ['warn', { ignoreFunctionalComponents: true }], 'simple-import-sort/imports': 'warn', 'simple-import-sort/exports': 'warn', - 'import-newlines/enforce': ['warn', 1] + 'import-newlines/enforce': ['warn', 1], }, overrides: [ { @@ -89,7 +89,7 @@ const config = { 'simple-import-sort/imports': [ 'error', { - 'groups': [ + groups: [ // side effect imports ['^\\u0000'], // packages `react` related packages come first @@ -101,12 +101,12 @@ const config = { ['^\\.\\.(?!/?$)', '^\\.\\./?$', '^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'], // style imports ['^.+\\.json$', '^.+\\.module.css$'], - ] - } - ] - } - } - ] + ], + }, + ], + }, + }, + ], }; module.exports = config; diff --git a/env.ts b/env.ts index fa920854..d925fa5a 100644 --- a/env.ts +++ b/env.ts @@ -1,5 +1,9 @@ -import { defineConfig, Schema } from '@julr/vite-plugin-validate-env'; +import { + defineConfig, + Schema, +} from '@julr/vite-plugin-validate-env'; export default defineConfig({ APP_TITLE: Schema.string.optional(), -}) + GRAPHQL_ENDPOINT: Schema.string.optional(), +}); diff --git a/package.json b/package.json index 2af9c5a3..3955cdeb 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,15 @@ "postinstall": "patch-package" }, "dependencies": { + "@apollo/client": "^3.11.8", "@togglecorp/fujs": "^2.0.0", + "@julr/vite-plugin-validate-env": "^1.1.1", + "graphql": "^16.9.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.11.1" }, "devDependencies": { - "@julr/vite-plugin-validate-env": "^1.1.1", "@types/node": "^20.1.3", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ddb2c4e..b78f6be3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,18 @@ importers: .: dependencies: + '@apollo/client': + specifier: ^3.11.8 + version: 3.11.8(@types/react@18.0.28)(graphql@16.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@julr/vite-plugin-validate-env': + specifier: ^1.1.1 + version: 1.1.1(vite@5.1.5(@types/node@20.1.3))(zod@3.23.8) '@togglecorp/fujs': specifier: ^2.0.0 version: 2.0.0 + graphql: + specifier: ^16.9.0 + version: 16.9.0 react: specifier: ^18.2.0 version: 18.2.0 @@ -21,9 +30,6 @@ importers: specifier: ^6.11.1 version: 6.11.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) devDependencies: - '@julr/vite-plugin-validate-env': - specifier: ^1.1.1 - version: 1.1.1(vite@5.1.5(@types/node@20.1.3))(zod@3.23.8) '@types/node': specifier: ^20.1.3 version: 20.1.3 @@ -148,6 +154,24 @@ packages: '@antfu/utils@0.7.10': resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} + '@apollo/client@3.11.8': + resolution: {integrity: sha512-CgG1wbtMjsV2pRGe/eYITmV5B8lXUCYljB2gB/6jWTFQcrvirUVvKg7qtFdjYkQSFbIffU1IDyxgeaN81eTjbA==} + peerDependencies: + graphql: ^15.0.0 || ^16.0.0 + graphql-ws: ^5.5.5 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 + subscriptions-transport-ws: ^0.9.0 || ^0.11.0 + peerDependenciesMeta: + graphql-ws: + optional: true + react: + optional: true + react-dom: + optional: true + subscriptions-transport-ws: + optional: true + '@babel/code-frame@7.25.7': resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==} engines: {node: '>=6.9.0'} @@ -623,6 +647,11 @@ packages: resolution: {integrity: sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -1068,6 +1097,26 @@ packages: '@vitest/utils@1.3.1': resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==} + '@wry/caches@1.0.1': + resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} + engines: {node: '>=8'} + + '@wry/context@0.7.4': + resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} + engines: {node: '>=8'} + + '@wry/equality@0.5.7': + resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} + engines: {node: '>=8'} + + '@wry/trie@0.4.3': + resolution: {integrity: sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==} + engines: {node: '>=8'} + + '@wry/trie@0.5.0': + resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} + engines: {node: '>=8'} + '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -2020,6 +2069,16 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql-tag@2.12.6: + resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql@16.9.0: + resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + gunzip-maybe@1.4.2: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} hasBin: true @@ -2071,6 +2130,9 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + html-encoding-sniffer@1.0.2: resolution: {integrity: sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==} @@ -2606,6 +2668,9 @@ packages: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} + optimism@0.18.0: + resolution: {integrity: sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==} + option-t@20.3.1: resolution: {integrity: sha512-umjR1qtje0FD7AJbPmrzaaYCmHkh9yWDWUfRtcN8P3o5pv/JYaAVsXu0t3sRj2/Ogcp6Q9jrGRKBWX5DyiQFMQ==} @@ -3025,6 +3090,17 @@ packages: resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} + rehackt@0.1.0: + resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==} + peerDependencies: + '@types/react': '*' + react: '*' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + request-promise-core@1.1.4: resolution: {integrity: sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==} engines: {node: '>=0.10.0'} @@ -3066,6 +3142,10 @@ packages: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true + response-iterator@0.2.6: + resolution: {integrity: sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==} + engines: {node: '>=0.8'} + restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} @@ -3343,6 +3423,10 @@ packages: svg-tags@1.0.0: resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -3425,6 +3509,10 @@ packages: peerDependencies: typescript: '>=4.2.0' + ts-invariant@0.10.3: + resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} + engines: {node: '>=8'} + tsconfck@2.1.2: resolution: {integrity: sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==} engines: {node: ^14.13.1 || ^16 || >=18} @@ -3775,6 +3863,12 @@ packages: resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} engines: {node: '>=12.20'} + zen-observable-ts@1.2.5: + resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==} + + zen-observable@0.8.15: + resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==} + zod-validation-error@3.4.0: resolution: {integrity: sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==} engines: {node: '>=18.0.0'} @@ -3793,6 +3887,29 @@ snapshots: '@antfu/utils@0.7.10': {} + '@apollo/client@3.11.8(@types/react@18.0.28)(graphql@16.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) + '@wry/caches': 1.0.1 + '@wry/equality': 0.5.7 + '@wry/trie': 0.5.0 + graphql: 16.9.0 + graphql-tag: 2.12.6(graphql@16.9.0) + hoist-non-react-statics: 3.3.2 + optimism: 0.18.0 + prop-types: 15.8.1 + rehackt: 0.1.0(@types/react@18.0.28)(react@18.2.0) + response-iterator: 0.2.6 + symbol-observable: 4.0.0 + ts-invariant: 0.10.3 + tslib: 2.8.0 + zen-observable-ts: 1.2.5 + optionalDependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + '@babel/code-frame@7.25.7': dependencies: '@babel/highlight': 7.25.7 @@ -4238,6 +4355,10 @@ snapshots: '@eslint/js@8.40.0': {} + '@graphql-typed-document-node/core@3.2.0(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -4685,6 +4806,26 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 + '@wry/caches@1.0.1': + dependencies: + tslib: 2.8.0 + + '@wry/context@0.7.4': + dependencies: + tslib: 2.8.0 + + '@wry/equality@0.5.7': + dependencies: + tslib: 2.8.0 + + '@wry/trie@0.4.3': + dependencies: + tslib: 2.8.0 + + '@wry/trie@0.5.0': + dependencies: + tslib: 2.8.0 + '@yarnpkg/lockfile@1.1.0': {} abab@2.0.6: {} @@ -5798,6 +5939,13 @@ snapshots: graphemer@1.4.0: {} + graphql-tag@2.12.6(graphql@16.9.0): + dependencies: + graphql: 16.9.0 + tslib: 2.8.0 + + graphql@16.9.0: {} + gunzip-maybe@1.4.2: dependencies: browserify-zlib: 0.1.4 @@ -5844,6 +5992,10 @@ snapshots: dependencies: function-bind: 1.1.2 + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + html-encoding-sniffer@1.0.2: dependencies: whatwg-encoding: 1.0.5 @@ -6371,6 +6523,13 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + optimism@0.18.0: + dependencies: + '@wry/caches': 1.0.1 + '@wry/context': 0.7.4 + '@wry/trie': 0.4.3 + tslib: 2.8.0 + option-t@20.3.1: {} optionator@0.8.3: @@ -6851,6 +7010,11 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 + rehackt@0.1.0(@types/react@18.0.28)(react@18.2.0): + optionalDependencies: + '@types/react': 18.0.28 + react: 18.2.0 + request-promise-core@1.1.4(request@2.88.2): dependencies: lodash: 4.17.21 @@ -6906,6 +7070,8 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + response-iterator@0.2.6: {} + restore-cursor@5.1.0: dependencies: onetime: 7.0.0 @@ -7260,6 +7426,8 @@ snapshots: svg-tags@1.0.0: {} + symbol-observable@4.0.0: {} + symbol-tree@3.2.4: {} synckit@0.8.8: @@ -7341,6 +7509,10 @@ snapshots: dependencies: typescript: 5.0.4 + ts-invariant@0.10.3: + dependencies: + tslib: 2.8.0 + tsconfck@2.1.2(typescript@5.0.4): optionalDependencies: typescript: 5.0.4 @@ -7704,6 +7876,12 @@ snapshots: yocto-queue@1.1.1: {} + zen-observable-ts@1.2.5: + dependencies: + zen-observable: 0.8.15 + + zen-observable@0.8.15: {} + zod-validation-error@3.4.0(zod@3.23.8): dependencies: zod: 3.23.8 diff --git a/src/configs/apollo.ts b/src/configs/apollo.ts new file mode 100644 index 00000000..19bad112 --- /dev/null +++ b/src/configs/apollo.ts @@ -0,0 +1,32 @@ +import { + ApolloClientOptions, + HttpLink, + InMemoryCache, + NormalizedCacheObject, +} from '@apollo/client'; + +const GRAPHQL_ENDPOINT = process.env.GRAPHQL_ENDPOINT as string; + +const link = new HttpLink({ + uri: GRAPHQL_ENDPOINT, + credentials: 'include', +}); + +const apolloOptions: ApolloClientOptions = { + link, + cache: new InMemoryCache(), + defaultOptions: { + watchQuery: { + fetchPolicy: 'network-only', + nextFetchPolicy: 'cache-only', + errorPolicy: 'all', + }, + query: { + fetchPolicy: 'network-only', + errorPolicy: 'all', + }, + }, +}; + +/** @knipignore */ +export default apolloOptions; diff --git a/src/index.tsx b/src/index.tsx index c0a09b89..bf4bec58 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,6 +2,12 @@ import './index.css'; import React from 'react'; import ReactDOM from 'react-dom/client'; +import { + ApolloClient, + ApolloProvider, +} from '@apollo/client'; + +import apolloOptions from '#configs/apollo'; import App from './App/index.tsx'; @@ -9,13 +15,17 @@ const webappRootId = 'webapp-root'; const webappRootElement = document.getElementById(webappRootId); +const apolloClient = new ApolloClient(apolloOptions); + if (!webappRootElement) { // eslint-disable-next-line no-console console.error(`Could not find html element with id '${webappRootId}'`); } else { ReactDOM.createRoot(webappRootElement).render( - + + + , ); } diff --git a/stylelint.config.cjs b/stylelint.config.cjs index c7574a69..85526c93 100644 --- a/stylelint.config.cjs +++ b/stylelint.config.cjs @@ -1,7 +1,7 @@ module.exports = { plugins: [ 'stylelint-no-unused-selectors', - 'stylelint-value-no-unknown-custom-properties' + 'stylelint-value-no-unknown-custom-properties', ], extends: [ 'stylelint-config-recommended', @@ -9,14 +9,14 @@ module.exports = { ], rules: { 'plugin/no-unused-selectors': { - "suffixesToStrip": [".module"], - "documents": [ - "{cssDir}/{cssName}.tsx", + suffixesToStrip: ['.module'], + documents: [ + '{cssDir}/{cssName}.tsx', ], }, 'csstools/value-no-unknown-custom-properties': [ true, { - importFrom: ['./src/index.css'] + importFrom: ['./src/index.css'], }, ], 'selector-pseudo-class-no-unknown': [ diff --git a/tsconfig.json b/tsconfig.json index dfc1ed97..ffc63db4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,8 @@ "compilerOptions": { "paths": { "#views/*": ["./src/views/*"], - "#utils/*": ["./src/utils/*"] + "#utils/*": ["./src/utils/*"], + "#configs/*": ["./src/configs/*"] }, "target": "ESNext",