diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ab8bbe579..624a462aa 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -16,9 +16,10 @@ const tsconfigPath = require('./tsconfig.json') + module.exports = { parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'react', 'prettier', 'import', 'simple-import-sort'], + plugins: ['@typescript-eslint', 'react', 'prettier', 'import', 'simple-import-sort', '@tanstack/query'], env: { browser: true, es2021: true, @@ -42,6 +43,7 @@ module.exports = { 'airbnb', 'airbnb/hooks', 'prettier', + 'plugin:@tanstack/query/recommended' ], rules: { 'prettier/prettier': ['error'], diff --git a/package-lock.json b/package-lock.json index e9980ff5e..70f1111b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.18.1", + "version": "1.19.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.18.1", + "version": "1.19.0", "hasInstallScript": true, "license": "ISC", "dependencies": { @@ -21,7 +21,7 @@ "@lezer/highlight": "1.2.1", "@replit/codemirror-indentation-markers": "6.5.3", "@replit/codemirror-vscode-keymap": "6.0.2", - "@types/react-dates": "^21.8.6", + "@tanstack/react-query": "<5", "@uiw/codemirror-extensions-hyper-link": "4.23.10", "@uiw/codemirror-theme-github": "4.23.7", "@uiw/react-codemirror": "4.23.7", @@ -30,6 +30,7 @@ "codemirror-json-schema": "0.8.0", "dayjs": "^1.11.13", "fast-json-patch": "^3.1.1", + "focus-trap-react": "^10.3.1", "framer-motion": "^6.5.1", "jsonpath-plus": "^10.3.0", "marked": "^13.0.3", @@ -47,6 +48,8 @@ "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@laynezh/vite-plugin-lib-assets": "1.1.0", "@sentry/browser": "^7.119.1", + "@tanstack/eslint-plugin-query": "<5", + "@tanstack/react-query-devtools": "<5", "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.4", "@tippyjs/react": "^4.2.0", @@ -54,6 +57,7 @@ "@types/dompurify": "^3.0.5", "@types/json-schema": "^7.0.15", "@types/react": "17.0.39", + "@types/react-dates": "^21.8.6", "@types/react-dom": "17.0.13", "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "8.3.0", @@ -1273,16 +1277,20 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -3655,6 +3663,95 @@ "@svgr/core": "^6.0.0" } }, + "node_modules/@tanstack/eslint-plugin-query": { + "version": "4.39.1", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-4.39.1.tgz", + "integrity": "sha512-5YDX4mdRC0hllHKp531CnScFWZU7aFrJ1aTyyuaB6+z0/i0JfcKuckSTYaji3vUk82GALM90eWwHFVRAch+7tQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@tanstack/match-sorter-utils": { + "version": "8.19.4", + "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz", + "integrity": "sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-accents": "0.5.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-core": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.40.0.tgz", + "integrity": "sha512-7MJTtZkCSuehMC7IxMOCGsLvHS3jHx4WjveSrGsG1Nc1UQLjaFwwkpLA2LmPfvOAxnH4mszMOBFD6LlZE+aB+Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.40.1.tgz", + "integrity": "sha512-mgD07S5N8e5v81CArKDWrHE4LM7HxZ9k/KLeD3+NUD9WimGZgKIqojUZf/rXkfAMYZU9p0Chzj2jOXm7xpgHHQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "4.40.0", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.40.1.tgz", + "integrity": "sha512-g8g2CCDt91CNhkLsKLVXVBVQSUubExnBdprwwjY5FFM+ZBjv1WfCpGiX1UOezgjVhNxqoi1Is+iMYShdOMoI8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/match-sorter-utils": "^8.7.0", + "superjson": "^1.10.0", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^4.40.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@testing-library/dom": { "version": "8.20.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", @@ -4039,6 +4136,7 @@ "version": "21.8.6", "resolved": "https://registry.npmjs.org/@types/react-dates/-/react-dates-21.8.6.tgz", "integrity": "sha512-fDF322SOXAxstapv0/oruiPx9kY4DiiaEHYAVvXdPfQhi/hdaONsA9dFw5JBNPAWz7Niuwk+UUhxPU98h70TjA==", + "dev": true, "dependencies": { "@types/react": "*", "@types/react-outside-click-handler": "*", @@ -4058,6 +4156,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/@types/react-outside-click-handler/-/react-outside-click-handler-1.3.4.tgz", "integrity": "sha512-kLuYIa9nWk1n0ywJPbVWqOEIRg0mh3vumriCHbz6LUObJw4rXYx9inDm8G579BtnH8vC0wKfrTq5c2y/K/Xzww==", + "dev": true, "dependencies": { "@types/react": "*" } @@ -5459,6 +5558,22 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -7202,6 +7317,30 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/focus-trap": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.5.tgz", + "integrity": "sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==", + "license": "MIT", + "dependencies": { + "tabbable": "^6.2.0" + } + }, + "node_modules/focus-trap-react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-10.3.1.tgz", + "integrity": "sha512-PN4Ya9xf9nyj/Nd9VxBNMuD7IrlRbmaG6POAQ8VLqgtc6IY/Ln1tYakow+UIq4fihYYYFM70/2oyidE6bbiPgw==", + "license": "MIT", + "dependencies": { + "focus-trap": "^7.6.1", + "tabbable": "^6.2.0" + }, + "peerDependencies": { + "prop-types": "^15.8.1", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -8175,6 +8314,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -10736,6 +10888,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "dev": true, + "license": "MIT" + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -11586,6 +11745,19 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "peer": true }, + "node_modules/superjson": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.3.tgz", + "integrity": "sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11666,6 +11838,12 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", diff --git a/package.json b/package.json index a2571df7e..3740eefd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.18.1", + "version": "1.19.0", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", @@ -40,6 +40,8 @@ "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@laynezh/vite-plugin-lib-assets": "1.1.0", "@sentry/browser": "^7.119.1", + "@tanstack/eslint-plugin-query": "<5", + "@tanstack/react-query-devtools": "<5", "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.4", "@tippyjs/react": "^4.2.0", @@ -47,6 +49,7 @@ "@types/dompurify": "^3.0.5", "@types/json-schema": "^7.0.15", "@types/react": "17.0.39", + "@types/react-dates": "^21.8.6", "@types/react-dom": "17.0.13", "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "8.3.0", @@ -107,7 +110,7 @@ "@lezer/highlight": "1.2.1", "@replit/codemirror-indentation-markers": "6.5.3", "@replit/codemirror-vscode-keymap": "6.0.2", - "@types/react-dates": "^21.8.6", + "@tanstack/react-query": "<5", "@uiw/codemirror-extensions-hyper-link": "4.23.10", "@uiw/codemirror-theme-github": "4.23.7", "@uiw/react-codemirror": "4.23.7", @@ -116,6 +119,7 @@ "codemirror-json-schema": "0.8.0", "dayjs": "^1.11.13", "fast-json-patch": "^3.1.1", + "focus-trap-react": "^10.3.1", "framer-motion": "^6.5.1", "jsonpath-plus": "^10.3.0", "marked": "^13.0.3", diff --git a/src/Assets/IconV2/ic-bg-environment.svg b/src/Assets/IconV2/ic-bg-environment.svg new file mode 100644 index 000000000..1021bd3c6 --- /dev/null +++ b/src/Assets/IconV2/ic-bg-environment.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/Assets/IconV2/ic-link.svg b/src/Assets/IconV2/ic-link.svg new file mode 100644 index 000000000..9fc4b77de --- /dev/null +++ b/src/Assets/IconV2/ic-link.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-resize-handle.svg b/src/Assets/IconV2/ic-resize-handle.svg new file mode 100644 index 000000000..22275acc7 --- /dev/null +++ b/src/Assets/IconV2/ic-resize-handle.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Common/API/CoreAPI.ts b/src/Common/API/CoreAPI.ts index b4322d977..50be9fdd5 100644 --- a/src/Common/API/CoreAPI.ts +++ b/src/Common/API/CoreAPI.ts @@ -130,6 +130,50 @@ class CoreAPI { ) } + /** + * Merges multiple AbortSignals into a single AbortSignal that aborts + * as soon as any of the input signals abort. + * + * This is useful when you want to race multiple async cancellation signals, + * for example, to support both a global timeout and a user-triggered abort. + * + * @param signals - AbortSignals to merge. + * @returns An AbortSignal that aborts if any input signal aborts. + */ + private static mergeAbortSignals(...signals: (AbortSignal | undefined)[]): AbortSignal { + const controller = new AbortController() + + // If any signal is already aborted, abort immediately and don't add listeners + if (signals.some((s) => s?.aborted)) { + controller.abort() + return controller.signal + } + + const onAbort = () => controller.abort() + + // Keep track of listeners for cleanup later + const cleanupFns: (() => void)[] = [] + + signals.forEach((signal) => { + if (signal && !signal.aborted) { + signal.addEventListener('abort', onAbort) + cleanupFns.push(() => signal.removeEventListener('abort', onAbort)) + } + }) + + // Ensure cleanup happens when merged signal is aborted (by any means) + controller.signal.addEventListener( + 'abort', + () => { + cleanupFns.forEach((fn) => fn()) + }, + // This ensures the listener is only run once + { once: true }, + ) + + return controller.signal + } + private fetchInTime = ({ url, type, @@ -138,10 +182,13 @@ class CoreAPI { isMultipartRequest, }: FetchInTimeParamsType): Promise => { const controller = options?.abortControllerRef?.current ?? new AbortController() - const signal = options?.abortControllerRef?.current?.signal || options?.signal || controller.signal - const timeoutPromise: Promise = new Promise((resolve, reject) => { - const timeout = options?.timeout || this.timeout + const timeoutSignal = controller.signal + + const mergedSignal = CoreAPI.mergeAbortSignals(options?.signal, timeoutSignal) + const timeout = options?.timeout || this.timeout + + const timeoutPromise: Promise = new Promise((_, reject) => { setTimeout(() => { controller.abort() if (options?.abortControllerRef?.current) { @@ -165,12 +212,13 @@ class CoreAPI { }) }, timeout) }) + return Promise.race([ this.fetchAPI({ url, type, data, - signal, + signal: mergedSignal, preventAutoLogout: options?.preventAutoLogout || false, preventLicenseRedirect: options?.preventLicenseRedirect || false, shouldParseServerErrorForUnauthorizedUser: options?.shouldParseServerErrorForUnauthorizedUser, diff --git a/src/Common/API/QueryClientProvider.tsx b/src/Common/API/QueryClientProvider.tsx new file mode 100644 index 000000000..9753fffbc --- /dev/null +++ b/src/Common/API/QueryClientProvider.tsx @@ -0,0 +1,48 @@ +import { PropsWithChildren } from 'react' +import { + MutationCache, + QueryCache, + QueryClient, + QueryClientProvider as RQQueryClientProvider, +} from '@tanstack/react-query' +import { ReactQueryDevtools } from '@tanstack/react-query-devtools' + +import { showError } from '@Common/Helper' + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + cacheTime: 0, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: false, + meta: { showToastError: true }, + }, + mutations: { + cacheTime: 0, + retry: false, + meta: { showToastError: true }, + }, + }, + queryCache: new QueryCache({ + onError: (error, query) => { + if (query.meta.showToastError) { + showError(error) + } + }, + }), + mutationCache: new MutationCache({ + onError: (error, _variables, _context, mutation) => { + if (mutation.meta.showToastError) { + showError(error) + } + }, + }), +}) + +export const QueryClientProvider = ({ children }: PropsWithChildren<{}>) => ( + + + {children} + +) diff --git a/src/Common/API/index.ts b/src/Common/API/index.ts index a0c3caaa1..390297a28 100644 --- a/src/Common/API/index.ts +++ b/src/Common/API/index.ts @@ -9,4 +9,6 @@ const dashboardAPI = new CoreAPI({ export const { post, put, patch, get, trash } = dashboardAPI export { default as CoreAPI } from './CoreAPI' +export { QueryClientProvider } from './QueryClientProvider' +export * from './reactQueryHooks' export { abortPreviousRequests, getIsRequestAborted, handleRedirectToLicenseActivation } from './utils' diff --git a/src/Common/API/reactQueryHooks.ts b/src/Common/API/reactQueryHooks.ts new file mode 100644 index 000000000..2fe25109c --- /dev/null +++ b/src/Common/API/reactQueryHooks.ts @@ -0,0 +1,23 @@ +import { + QueryKey, + useMutation as rqUseMutation, + UseMutationOptions, + UseMutationResult, + useQuery as rqUseQuery, + useQueryClient, + UseQueryOptions, + UseQueryResult, +} from '@tanstack/react-query' + +import { ServerErrors } from '@Common/ServerError' +import { ResponseType } from '@Common/Types' + +export const useQuery = ( + options: UseQueryOptions, ServerErrors, TData, TQueryKey>, +): UseQueryResult => rqUseQuery(options) + +export const useMutation = ( + options: UseMutationOptions, ServerErrors, TVariables, TContext>, +): UseMutationResult, ServerErrors, TVariables, TContext> => rqUseMutation(options) + +export { useQueryClient } diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index c74a92f82..deefd5a8e 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -19,7 +19,7 @@ export const Host = window?.__ORCHESTRATOR_ROOT__ ?? '/orchestrator' export const DOCUMENTATION_HOME_PAGE = 'https://docs.devtron.ai' export const DEVTRON_HOME_PAGE = 'https://devtron.ai/' -export const DOCUMENTATION_VERSION = '/devtron/v0.7' +export const DOCUMENTATION_VERSION = '/devtron/v1.7' export const DISCORD_LINK = 'https://discord.devtron.ai/' export const DEFAULT_JSON_SCHEMA_URI = 'https://json-schema.org/draft/2020-12/schema' export const LICENSE_DASHBOARD_HOME_PAGE = 'https://license.devtron.ai/dashboard' @@ -80,7 +80,6 @@ export const URLS = { COMPARE_CLUSTERS: '/compare-clusters', APP_CONFIG: 'edit', GLOBAL_CONFIG: '/global-config', - GLOBAL_CONFIG_MANAGE_CATEGORIES: '/global-config/cluster-env/manage-categories', GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP, GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP_CREATE: `${GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP}/create`, // NOTE: using appId since we are re-using AppConfig component diff --git a/src/Common/Drawer/Drawer.tsx b/src/Common/Drawer/Drawer.tsx index d33d57acb..ca496f290 100644 --- a/src/Common/Drawer/Drawer.tsx +++ b/src/Common/Drawer/Drawer.tsx @@ -15,11 +15,11 @@ */ import { useRef, useEffect } from 'react' -import { preventBodyScroll } from '../../Shared' import { VisibleModal } from '../Modals/VisibleModal' import './Drawer.scss' +import { DTFocusTrapType } from '@Shared/Components/DTFocusTrap' -export interface DrawerProps { +export interface DrawerProps extends Pick { position: 'left' | 'right' | 'bottom' | 'top' children?: any backdrop?: boolean @@ -44,14 +44,13 @@ export const Drawer = ({ onEscape, onClose, disableTransition, + initialFocus = undefined, }: DrawerProps) => { const drawerRef = useRef(null) useEffect(() => { setTimeout(() => drawerRef.current?.classList?.add('show'), 1) - preventBodyScroll(true) return () => { drawerRef.current?.classList?.remove('show') - preventBodyScroll(false) } }, []) const style = {} @@ -64,8 +63,18 @@ export const Drawer = ({ style['--height'] = height } return ( - -