diff --git a/.eslintignore b/.eslintignore index e036b2b342..4c62c958c8 100755 --- a/.eslintignore +++ b/.eslintignore @@ -1,31 +1,20 @@ - -# Ignoring the test files for the time beinggi -*.test.ts -*.test.tsx .eslintrc.js vite.config.mts scripts/ # The following files have eslint errors/warnings -src/Pages/GlobalConfigurations/Authorization/APITokens/__tests__/ApiTokens.test.tsx src/components/AppSelector/ChartSelector.tsx src/components/ApplicationGroup/AppGroup.service.ts src/components/ApplicationGroup/AppGroup.utils.ts src/components/ApplicationGroup/AppGroupAppFilter.components.tsx src/components/ApplicationGroup/AppGroupDetailsRoute.tsx -src/components/ApplicationGroup/AppGroupRoute.tsx src/components/ApplicationGroup/Constants.ts src/components/ApplicationGroup/CreateAppGroup.tsx src/components/ApplicationGroup/Details/EnvCDDetails/EnvCDDetails.tsx -src/components/ApplicationGroup/Details/EnvCDDetails/__test__/EnvCDDetails.test.tsx src/components/ApplicationGroup/Details/EnvCIDetails/EnvCIDetails.tsx -src/components/ApplicationGroup/Details/EnvCIDetails/__test__/EnvCIDetails.test.tsx -src/components/ApplicationGroup/Details/EnvironmentConfig/__test__/ApplicationRoutes.test.tsx -src/components/ApplicationGroup/Details/EnvironmentConfig/__test__/EnvConfig.test.tsx src/components/ApplicationGroup/Details/EnvironmentOverview/HibernateModal.tsx src/components/ApplicationGroup/Details/EnvironmentOverview/HibernateStatusListDrawer.tsx src/components/ApplicationGroup/Details/EnvironmentOverview/HibernateStatusRow.tsx -src/components/ApplicationGroup/Details/EnvironmentOverview/__test__/EnvironmentOverview.test.tsx src/components/ApplicationGroup/Details/TriggerView/BulkCDTrigger.tsx src/components/ApplicationGroup/Details/TriggerView/BulkCITrigger.tsx src/components/ApplicationGroup/Details/TriggerView/EnvTriggerView.tsx @@ -51,20 +40,12 @@ src/components/ClusterNodes/ClusterEvents.tsx src/components/ClusterNodes/ClusterManifest.tsx src/components/ClusterNodes/ClusterNodeEmptyStates.tsx src/components/ClusterNodes/NodeDetails.tsx -src/components/ClusterNodes/__tests__/ClusterManifest.test.tsx -src/components/ClusterNodes/__tests__/NodeList.test.tsx -src/components/Hotjar/Hotjar.tsx src/components/Jobs/ExpandedRow/ExpandedRow.tsx src/components/Jobs/JobDetails/JobDetails.tsx -src/components/Jobs/JobList/JobListView.tsx -src/components/Jobs/Jobs.tsx src/components/Jobs/JobsEmptyState.tsx src/components/Jobs/Service.ts src/components/Jobs/Utils.ts src/components/LogViewer/LogViewer.tsx -src/components/ResourceBrowser/ResourceList/__tests__/Sidebar.test.tsx -src/components/__mocks__/xterm-webfont.js -src/components/app/LogFilter.test.ts src/components/app/LogFilter.ts src/components/app/Overview/EnvironmentList.tsx src/components/app/Overview/Overview.tsx @@ -75,7 +56,6 @@ src/components/app/ResponsiveDrawer.tsx src/components/app/WebWorker.ts src/components/app/create/CreateApp.tsx src/components/app/create/validationRules.ts -src/components/app/details/AboutAppInfoModal.tsx src/components/app/details/AboutTagEditModal.tsx src/components/app/details/appDetails/AppMetrics.tsx src/components/app/details/appDetails/AppStatusCard.tsx @@ -83,7 +63,6 @@ src/components/app/details/appDetails/DeploymentStatusDetailModal.tsx src/components/app/details/appDetails/GraphsModal.tsx src/components/app/details/appDetails/IssuesCard.tsx src/components/app/details/appDetails/SourceInfo.tsx -src/components/app/details/appDetails/__tests__/GenericInfo.test.tsx src/components/app/details/appDetails/index.tsx src/components/app/details/appDetails/utils.tsx src/components/app/details/cIDetails/CIDetails.tsx @@ -101,7 +80,6 @@ src/components/app/details/testViewer/TestRunDetails.tsx src/components/app/details/testViewer/TestRunList.tsx src/components/app/details/triggerView/EmptyStateCIMaterial.tsx src/components/app/details/triggerView/MaterialSource.tsx -src/components/app/details/triggerView/__tests__/triggerview.test.tsx src/components/app/details/triggerView/ciWebhook.service.ts src/components/app/details/triggerView/config.ts src/components/app/details/triggerView/workflow.service.ts @@ -118,7 +96,6 @@ src/components/app/list-new/AppListService.ts src/components/app/list-new/GenericAppList.tsx src/components/app/list-new/HelmAppList.tsx src/components/app/list/TriggerUrl.tsx -src/components/app/list/__tests__/AppListView.test.tsx src/components/app/list/appList.modal.ts src/components/app/list/emptyView/Empty.tsx src/components/app/list/expandedRow/ExpandedRow.tsx @@ -136,7 +113,6 @@ src/components/charts/ChartGroupDeployments.tsx src/components/charts/ChartGroupDetails.tsx src/components/charts/ChartGroupUpdate.tsx src/components/charts/ChartHeaderFilters.tsx -src/components/charts/Charts.tsx src/components/charts/MultiChartSummary.tsx src/components/charts/chartValues/ChartValues.tsx src/components/charts/charts.service.ts @@ -200,7 +176,6 @@ src/components/common/DatePickers/Calender.tsx src/components/common/DatePickers/DayPickerRangeController.tsx src/components/common/DeprecatedUpdateWarn.tsx src/components/common/Description/GenericDescription.tsx -src/components/common/DynamicTabs/__tests__/DynamicTabs.test.tsx src/components/common/HiddenInput/HiddenInput.tsx src/components/common/List/List.tsx src/components/common/MultiSelect/MultiSelect.tsx @@ -219,7 +194,6 @@ src/components/common/helpers/time.ts src/components/common/helpers/utils.tsx src/components/common/helpers/workflowURL.ts src/components/common/hooks/FileReader.ts -src/components/common/hooks/__tests__/FileReader.test.tsx src/components/common/icons/Icons.tsx src/components/common/lineChart/lineChart.tsx src/components/common/navigation/Navigation.tsx @@ -227,7 +201,6 @@ src/components/dockerRegistry/Docker.tsx src/components/dockerRegistry/ManageRegistry.tsx src/components/dockerRegistry/service.tsx src/components/external-apps/ExternalAppService.ts -src/components/external-apps/ExternalApps.tsx src/components/externalArgoApps/ExternalArgoApp.tsx src/components/externalArgoApps/ExternalArgoAppDetail.tsx src/components/externalLinks/ExternalLinks.component.tsx @@ -239,7 +212,6 @@ src/components/externalLinks/ExternalLinksFilters.tsx src/components/gitOps/GitOpsConfiguration.tsx src/components/gitOps/UserGitRepConfiguration.tsx src/components/gitOps/UserGitRepo.tsx -src/components/gitOps/__tests__/GitOpsConfiguration.test.tsx src/components/gitOps/gitops.service.tsx src/components/gitOps/gitops.type.ts src/components/gitProvider/AddGitHostConfigModal.tsx @@ -269,19 +241,9 @@ src/components/scopedVariables/ScopedVariablesEditor.tsx src/components/scopedVariables/ScopedVariablesLoader.tsx src/components/scopedVariables/UploadScopedVariables.tsx src/components/scopedVariables/VariablesList.tsx -src/components/scopedVariables/__tests__/Descriptor.test.tsx -src/components/scopedVariables/__tests__/DescriptorSearchBar.test.tsx -src/components/scopedVariables/__tests__/SavedVariables.test.tsx -src/components/scopedVariables/__tests__/ScopedVariables.test.tsx -src/components/scopedVariables/__tests__/ScopedVariablesEditor.test.tsx -src/components/scopedVariables/__tests__/ScopedVariablesLoader.test.tsx -src/components/scopedVariables/__tests__/UploadScopedVariables.test.tsx -src/components/scopedVariables/__tests__/VariablesList.test.tsx -src/components/scopedVariables/__tests__/utils.test.tsx src/components/scopedVariables/utils.tsx src/components/security/AddCveModal.tsx src/components/security/DeleteCVEModal.tsx -src/components/security/SecurityPoliciesTab.tsx src/components/security/SecurityPolicyApp.tsx src/components/security/SecurityPolicyCluster.tsx src/components/security/SecurityPolicyEdit.tsx @@ -293,7 +255,6 @@ src/components/terminal/TerminalWrapper.tsx src/components/util/KeyValueFileInput.tsx src/components/v2/appDetails/ReleaseStatusEmptyState.tsx src/components/v2/appDetails/SyncError.component.tsx -src/components/v2/appDetails/__tests__/index.store.test.ts src/components/v2/appDetails/appDetails.api.ts src/components/v2/appDetails/ea/EAAppDetail.component.tsx src/components/v2/appDetails/k8Resource/FilterResource.tsx @@ -301,15 +262,12 @@ src/components/v2/appDetails/k8Resource/nodeDetail/EphemeralContainerDrawer.tsx src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/CustomLogsModal/CustomLogsModal.tsx src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/Terminal.component.tsx src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/terminal/TerminalWrapper.component.tsx -src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/terminal/__tests__/Terminal.component.test.tsx -src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/terminal/__tests__/TerminalWrapper.test.tsx src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/terminal/constants.ts src/components/v2/appDetails/k8Resource/nodeDetail/NodeDetailTabs/terminal/terminal.type.ts src/components/v2/appDetails/k8Resource/nodeDetail/nodeDetail.api.ts src/components/v2/appDetails/k8Resource/nodeDetail/nodeDetail.util.tsx src/components/v2/appDetails/k8Resource/nodeType/NodeTree.component.tsx src/components/v2/appDetails/k8Resource/nodeType/PodTabSection.tsx -src/components/v2/appDetails/k8Resource/nodeType/__tests__/NodeTree.component.test.ts src/components/v2/appDetails/k8Resource/nodeType/nodeType.util.ts src/components/v2/appDetails/k8Resource/nodeType/useNodeTreeReducer.ts src/components/v2/appDetails/sourceInfo/EnvironmentSelector.component.tsx @@ -364,4 +322,3 @@ src/services/service.types.ts src/util/MurmurHash3.ts src/util/Subject.ts src/util/Util.ts -src/util/__tests__/Subject.test.ts diff --git a/.nvmrc b/.nvmrc index 53d1c14db3..a3b7a31ee8 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v22 +v24.14.1 diff --git a/CLAUDE.md b/CLAUDE.md index 42d32bcd55..89d6aed9b6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,523 +2,110 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Project Overview - -**Dashboard** is the primary web frontend for the Devtron platform - a Kubernetes-native software delivery and operations platform. This is a React TypeScript single-page application (SPA) built with Vite that provides the complete user interface for managing Kubernetes clusters, applications, CI/CD pipelines, security, and infrastructure. - -- **License**: Apache 2.0 -- **Version**: 1.22.0 -- **Base Path**: `/dashboard` -- **Package Manager**: Yarn 4.9.2 -- **Private**: Yes (not published to npm) - ## Commands -### Development ```bash -yarn start # Start Vite dev server on port 3000 -yarn build # Production build with sourcemaps (8GB heap) +yarn install # Install dependencies (uses yarn v4) +yarn start # Dev server at http://localhost:3000 +yarn build # Production build (8 GB node heap) +yarn build-light # Production build without source maps +yarn lint # TypeScript check + ESLint (zero warnings allowed) +yarn lint-fix # Auto-fix ESLint issues +yarn test # Run tests with vitest +yarn test-coverage # Run tests with coverage report ``` -### Linting & Type Checking +To run a single test file: ```bash -yarn lint # TypeScript check + ESLint (max-warnings: 0, strict) -yarn lint-fix # Auto-fix ESLint issues -yarn tsc --noEmit # Run TypeScript type check only +yarn test path/to/file.test.tsx ``` +The dev server proxies `/orchestrator` to the `TARGET_URL` in `vite.config.mts` (defaults to `https://devtron-ent-7.devtron.info/`). To point at a different backend, set `VITE_TARGET_URL` in a `.env.secrets` file. + +Husky runs TypeScript compilation and lint-staged before every commit. Failing either blocks the commit. + ## Architecture -### Directory Structure +### Entry & Routing -**Total Size**: 17MB | 1,217 TS/TSX files | 770 TSX files +- **`src/index.tsx`** — bootstraps the app. Initializes Sentry, sets `window._env_` defaults (runtime config), wraps everything in `QueryClientProvider`, `ThemeProvider`, `UserEmailProvider`, and `RouterProvider`. +- **`src/App.tsx`** — validates the auth token, then renders `NavigationRoutes` (lazy) or redirects to login. +- **`src/components/common/navigation/NavigationRoutes.tsx`** — the main shell. Fetches server mode, user preferences, environment data, and server info on mount. Provides `MainContextProvider` with global state. Renders the `Navigation` sidebar and the route tree. +- **`src/components/common/navigation/NavRoutes.components.tsx`** — defines sub-routers for Devtron apps, jobs, external apps, etc. -``` -src/ -├── assets/ # Static assets -│ ├── icons/ # SVG icons -│ ├── img/ # PNG/JPG images -│ ├── logo/ # Brand logos -│ ├── gif/ # Animated GIFs -│ └── fonts/ # Custom fonts -│ -├── components/ # 37 feature-based component directories -│ ├── common/ # Shared UI components -│ │ ├── Banner/ -│ │ ├── DynamicTabs/ -│ │ ├── List/ -│ │ ├── navigation/ # Navigation & routing -│ │ ├── Select/ -│ │ ├── SidePanel/ -│ │ └── ... -│ ├── login/ # Login/SSO components -│ ├── app/ # Application-related components -│ ├── ciPipeline/ # CI pipeline configuration -│ ├── cdPipeline/ # CD pipeline configuration -│ ├── ResourceBrowser/ # Kubernetes resource browser -│ ├── workflowEditor/ # Workflow/pipeline editor -│ ├── security/ # Security-related components -│ ├── ClusterNodes/ # Cluster node monitoring -│ ├── Jobs/ # Job management -│ ├── ApplicationGroup/ # App grouping -│ ├── bulkEdits/ # Bulk operations -│ ├── globalConfigurations/ # Global settings -│ ├── gitProvider/ # Git provider integration -│ ├── dockerRegistry/ # Docker registry config -│ ├── chartRepo/ # Helm chart repository -│ ├── externalArgoApps/ # External ArgoCD apps -│ ├── gitOps/ # GitOps configuration -│ ├── notifications/ # Notification system -│ ├── hyperion/ # Advanced features -│ ├── material/ # Material resource management -│ ├── v2/ # V2 components (redesigned) -│ ├── __mocks__/ # Mock data for testing -│ └── util/ # Component utilities -│ -├── Pages/ # Legacy page-level components (v1) -│ ├── App/ -│ ├── Applications/ -│ ├── ChartStore/ -│ ├── GlobalConfigurations/ -│ ├── License/ -│ ├── Releases/ -│ └── Shared/ -│ -├── Pages-Devtron-2.0/ # Redesigned pages (v2, domain-driven) -│ ├── ApplicationManagement/ -│ ├── Automation&Enablement/ -│ ├── CostVisibility/ -│ ├── GlobalConfiguration/ -│ ├── GlobalOverview/ -│ ├── InfrastructureManagement/ -│ ├── SecurityCenter/ -│ ├── SoftwareReleaseManagement/ -│ └── Shared/ -│ -├── config/ # Configuration files -│ ├── constants.ts # API routes, constants (ROUTES object, API paths) -│ ├── constantMessaging.ts # User-facing messages -│ ├── routes.ts # URL routes and path constants -│ └── utils.tsx # Config utilities -│ -├── services/ # API services -│ ├── service.ts # Main API calls (validateToken, cluster, app, CI/CD) -│ ├── fetchWithFullRoute.ts -│ └── service.types.ts # Service type definitions -│ -├── util/ # Utilities -│ ├── Subject.ts # Custom pub/sub implementation (NOT RxJS) -│ ├── MurmurHash3.ts # Hash function -│ └── Util.ts # Helper utilities -│ -├── css/ # Global styles -│ ├── application.scss # Main stylesheet -│ ├── base.scss # Base styles -│ ├── forms.scss # Form styles -│ ├── themeTokens.scss # Design tokens -│ ├── themeUtils.scss # Theme utilities -│ ├── mixins.scss # SCSS mixins -│ ├── formulae.scss # Formulas/calculations -│ ├── iconTheming.scss # Icon theming -│ └── whiteCard.scss # Card component styles -│ -├── index.tsx # App entry point (ReactDOM.render) -├── App.tsx # Root component (routing, auth, error handling) -├── vite-env.d.ts # Vite type definitions -├── custom.d.ts # Custom type definitions -└── setupTests.js # Test setup -``` +### Two-tier page organization -### Path Aliases +The codebase has a legacy and a new page structure running side by side: -TypeScript path aliases are configured in [tsconfig.json](tsconfig.json): +- **`src/components/`** — legacy component tree (apps, CI/CD pipelines, cluster nodes, global config, resource browser, etc.) +- **`src/Pages/`** — newer page modules: `App`, `Applications`, `ChartStore`, `GlobalConfigurations`, `Releases`, `Shared` +- **`src/Pages-Devtron-2.0/`** — Devtron 2.0 domain routers: `ApplicationManagement`, `Automation&Enablement`, `InfrastructureManagement`, `SecurityCenter`, `Shared` -```typescript -@Icons/* → ./src/assets/icons/* -@Images/* → ./src/assets/img/* -@Components/* → ./src/components/* -@Config/* → ./src/config/* -@Pages/* → ./src/Pages/* -@PagesDevtron2.0/* → ./src/Pages-Devtron-2.0/* -@Services/* → ./src/services/* -``` +New features should go in `src/Pages/` or `src/Pages-Devtron-2.0/`. -**Always use these aliases instead of relative paths** when importing across directories. - -### Build Configuration - -The application uses Vite with manual chunk splitting for optimal bundle loading ([vite.config.mts](vite.config.mts)): - -**Manual Chunks:** -- `@moment` - moment, moment-timezone -- `@react-select` - react-select -- `@react-dates` - react-dates -- `@react-virtualized` - react-virtualized -- `@react-mde` - react-mde -- `@rjsf` - React JSON Schema Form -- `@code-editor` - CodeMirror -- `@rxjs` - rxjs -- `@sentry` - error tracking -- `@react-router` - routing -- `@devtron-common-*` - Chunks from devtron-fe-common-lib - -**Key Plugins:** -- React plugin (JSX/TSX support) -- SVGR (SVG as React components) -- Vite PWA (service worker, caching strategies, offline support) -- Compression (Brotli) -- TsConfig paths resolver -- Node globals polyfill -- Custom react-virtualized WindowScroller fix -- Custom HTML transformation (moves scripts to body end) - -**Dev Server Proxy:** -- `/orchestrator` → proxied to target URL -- `/proxy` → proxied to target URL -- `/grafana` → proxied to target URL -- **Default Target**: https://staging.devtron.info/ - -**Build Settings:** -- Node heap: 8GB for production builds -- Sourcemaps: Enabled by default (disable with build-light) -- Target: Modern browsers -- Asset inline limit: 0 (no inlining) - -When adding new large dependencies, consider adding them to the manual chunks configuration to optimize bundle loading. - -## Code Standards - -### Routing & Navigation - -- **Router**: React Router v5 (history-based, not v6) -- **Routes Configuration**: Defined in [src/config/routes.ts](src/config/routes.ts) -- **Navigation Component**: [src/components/common/navigation/NavigationRoutes.tsx](src/components/common/navigation/NavigationRoutes.tsx) -- **Lazy Loading**: Use React.lazy() and Suspense for route-based code splitting - -```typescript -import { lazy, Suspense } from 'react' - -const MyPage = lazy(() => import('@Pages/MyPage')) - -// In routing -}> - - -``` +### TypeScript path aliases -### Component Patterns - -- **Function components**: Use arrow functions for all components (enforced by ESLint) - ```typescript - // ✅ DO - export const MyComponent = () => { ... } - - // ❌ DON'T - export function MyComponent() { ... } - ``` - -- **TypeScript**: Strict mode is disabled, but type safety is encouraged -- **Styling**: BEM naming convention, external SCSS files (no inline styles) - -### State Management - -1. **Local State**: React hooks (useState, useEffect, useReducer) -2. **Context API**: - - ThemeProvider (from common-lib) - - UserEmailProvider (from common-lib) - - UseRegisterShortcutProvider (from common-lib) - - Custom contexts for specific features -3. **Data Fetching**: - - Custom `useAsync` hook (from common-lib) for simple async operations - - React Query (`@tanstack/react-query`) for complex data management - - Direct API calls via [src/services/service.ts](src/services/service.ts) -4. **Pub/Sub Pattern**: Custom Subject class in [src/util/Subject.ts](src/util/Subject.ts) - - **IMPORTANT**: This is NOT RxJS, it's a lightweight custom implementation - -### Import Order - -ESLint enforces a specific import order (configured in [.eslintrc.js](.eslintrc.js)): - -1. React and external packages (`react`, `@?\\w`) -2. Devtron packages (`@devtron-labs`) -3. Internal path aliases (`@Components/*`, `@Config/*`, `@Services/*`, etc.) -4. Side effect imports -5. Relative imports (`../`, `./`) -6. Style imports (`.css`, `.scss`) - -The `simple-import-sort` plugin will auto-fix import order on save. - -### Best Practices (from README) - -- **Single state per page**: Keep state management minimal -- **Pure functions**: Components should be pure where possible -- **BEM naming**: CSS class naming convention -- **No inline styles**: Use external stylesheets -- **Reusable components**: Extract components early -- **Heavy lifting in child components**: Not in parent containers -- **Parsing and error handling in services**: Not in components -- **No conditional rendering in JSX**: Use helper functions instead -- **No CSS IDs**: Use classes instead -- **Flexbox over float**: Modern CSS layout - -### Pre-commit Hooks - -The pre-commit hook ([.husky/pre-commit](.husky/pre-commit)) enforces: - -1. **TypeScript check**: `yarn tsc --noEmit` must pass (max-warnings: 0, strict) -2. **Lint-staged**: ESLint check on staged files only - -## Common Tasks - -### Adding a New Page - -1. **Choose directory structure**: - - `src/Pages/` for legacy pages - - `src/Pages-Devtron-2.0/` for redesigned pages (preferred) - -2. **Create page component**: - ```typescript - // src/Pages-Devtron-2.0/MyFeature/MyPage.tsx - export const MyPage = () => { - return
My Page Content
- } - ``` - -3. **Add route** in [src/config/routes.ts](src/config/routes.ts): - ```typescript - export const URLS = { - MY_FEATURE: '/my-feature', - } - ``` - -4. **Register in router** (NavigationRoutes.tsx or App.tsx): - ```typescript - import { MyPage } from '@PagesDevtron2.0/MyFeature' - - - - - ``` - -### Adding a New Component - -1. **Create component directory** under `src/components/`: - ``` - MyFeature/ - ├── MyFeature.tsx - ├── MyFeature.scss - ├── service.ts - ├── types.ts - └── constants.ts - ``` - -2. **Use common-lib components** where possible: - ```typescript - import { - Button, - Icon, - Progressing, - ErrorScreenManager, - } from '@devtron-labs/devtron-fe-common-lib' - ``` - -### API Service Pattern - -All API calls should be in dedicated service files: - -```typescript -// src/services/service.ts or component-specific service.ts -import { get, post, put, ResponseType } from '@devtron-labs/devtron-fe-common-lib' -import { ROUTES } from '@Config/constants' - -export const fetchApplications = () => { - return get(ROUTES.APP_LIST) -} - -export const updateApplication = (payload) => { - return put(`${ROUTES.APP}/${payload.id}`, payload) -} -``` +Defined in `tsconfig.json`: -### Using React Query +| Alias | Path | +|---|---| +| `@Icons/*` | `src/assets/icons/*` | +| `@Images/*` | `src/assets/img/*` | +| `@Components/*` | `src/components/*` | +| `@Config/*` | `src/config/*` | +| `@Pages/*` | `src/Pages/*` | +| `@PagesDevtron2.0/*` | `src/Pages-Devtron-2.0/*` | +| `@Services/*` | `src/services/*` | -```typescript -import { useQuery, useMutation } from '@tanstack/react-query' -import { fetchApplications } from '@Services/service' +### Shared libraries -// In component -const { data, isLoading, error } = useQuery({ - queryKey: ['applications'], - queryFn: fetchApplications, -}) +Two npm packages supply the majority of shared UI/logic: -const mutation = useMutation({ - mutationFn: updateApplication, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['applications'] }) - }, -}) -``` +- **`@devtron-labs/devtron-fe-common-lib`** — OSS shared components, hooks, utilities, route constants (`ROUTER_URLS`, `BASE_ROUTES`), API helpers (`get`, `post`, `trash`), and context providers. Import from this package directly. +- **`@devtron-labs/devtron-fe-lib`** (optional enterprise library, loaded via `node_modules` if present) — enterprise-only components. **Never import directly.** Always use `importComponentFromFELibrary` from `src/components/common/helpers/Helpers.tsx`. -### Authentication & Token Handling +### `importComponentFromFELibrary` pattern -- **Token validation**: Called on app load via `validateToken()` in [src/services/service.ts](src/services/service.ts) -- **Token storage**: Cookie named `argocd.token` -- **SSO support**: `getSSOConfigList()` service call -- **K8S_CLIENT mode**: Conditional auth bypass for Kubernetes client mode -- **Error handling**: ErrorBoundary wraps routing, Sentry integration for production +Enterprise features are feature-flagged at the import level: -### Environment Configuration +```ts +const LicenseInfoDialog = importComponentFromFELibrary('LicenseInfoDialog', null, 'function') +// Then guard usage: +if (LicenseInfoDialog) { ... } +``` -**Runtime config** via `window._env_` (customEnv interface from common-lib): +This returns `null` when the enterprise lib is absent, keeping OSS builds working. -```typescript -// Access feature flags -if (window._env_.FEATURE_SOFTWARE_DISTRIBUTION_HUB_ENABLE) { - // render SDH feature -} +### Server modes -// Access API endpoints -const orchestratorUrl = window._env_.ORCHESTRATOR_ROOT -``` +`SERVER_MODE.FULL` — full Devtron install with CI/CD module. +`SERVER_MODE.EA_ONLY` — external apps only (no CI/CD). +`window._env_.K8S_CLIENT` — pure Kubernetes client mode (no auth, no CI/CD). -**Global window config** (set in [index.tsx](index.tsx)): -```typescript -window.__BASE_URL__ // Default: /dashboard -window.__ORCHESTRATOR_ROOT__ // Default: orchestrator -window._env_ // Runtime environment config -``` +Routes and UI sections are conditionally rendered based on server mode. -### Analytics & Monitoring - -**Error Tracking (Sentry)**: -```typescript -// Conditional in production -if (window._env_.SENTRY_ENABLED) { - Sentry.init({ - dsn: window._env_.SENTRY_DSN, - environment: window._env_.SENTRY_ENV, - }) -} -``` +### Runtime configuration -**Google Analytics (GA4)**: -```typescript -import ReactGA from 'react-ga4' +`window._env_` holds all runtime feature flags and config (set by the backend at serve time). Defaults are declared at the bottom of `src/index.tsx`. See `config.md` for the full list of supported keys. -ReactGA.event({ - category: 'User', - action: 'Clicked Button', -}) -``` +### Service layer -**Google Tag Manager (GTM)**: -```typescript -import TagManager from 'react-gtm-module' +- **`src/services/service.ts`** — global API calls (auth, app list, cluster list, login tracking). +- Component-level services live alongside their component (e.g., `src/components/app/service.ts`). +- All HTTP calls use `get`/`post`/`trash` from `devtron-fe-common-lib`, which wrap fetch and normalize errors. -TagManager.initialize({ gtmId: window._env_.GTM_ID }) -``` +### State management -### Working with Icons +- **`MainContextProvider`** (from `devtron-fe-common-lib`) — global context with `serverMode`, `isSuperAdmin`, `installedModuleMap`, feature flags, and more. Access via `useMainContext()`. +- Local component state is preferred; lift state only when needed. +- One stateful "page" component per view; child components should be pure/presentational. -```typescript -// SVG as React component (via SVGR) -import { ReactComponent as MyIcon } from '@Icons/my-icon.svg' +### CSS conventions -// Using Icon component from common-lib -import { Icon } from '@devtron-labs/devtron-fe-common-lib' +- SCSS modules for component styles; global styles in `src/css/`. +- BEM naming for CSS classes. +- No IDs for CSS; no `float`; use flexbox. - -``` +### Build chunking -### PWA & Service Workers - -- **Config**: [vite.config.mts](vite.config.mts) (Vite PWA plugin) -- **Caching Strategies**: Network-first for API calls, cache-first for assets -- **Offline Support**: Service worker enabled in production builds -- **Manifest**: Auto-generated by Vite PWA plugin - -## Key Dependencies - -**UI Framework:** -- React 17.0.2 (not React 18) -- React DOM 17.0.2 -- React Router DOM 5.3.4 (v5, not v6) - -**Component Libraries:** -- @devtron-labs/devtron-fe-common-lib (1.22.8-beta-4) - Primary component library -- @devtron-labs/devtron-fe-lib - Secondary feature library -- react-select 5.8.0 -- react-dates 21.8.0 -- @rjsf/core 5.13.3 (React JSON Schema Forms) - -**State & Data:** -- @tanstack/react-query - Data fetching and caching -- RxJS 7.5.4 (minimal usage) - -**Date/Time:** -- dayjs 1.11.8 (preferred) -- moment 2.29.4 (legacy) - -**Code Editor:** -- @uiw/react-codemirror (via common-lib) -- CodeMirror 6 extensions - -**Terminal:** -- xterm 4.19.0 (cluster terminal emulation) - -**Markdown:** -- marked (rendering) -- react-mde 11.5.0 (editor) -- dompurify (sanitization) - -**Analytics & Monitoring:** -- @sentry/react 7.119.1 -- react-ga4 1.4.1 -- react-gtm-module 2.0.11 - -**Utilities:** -- yaml 2.4.1 -- jsonpath-plus -- fast-json-patch -- dompurify - -**Build Tools:** -- Vite 6.3.5 -- TypeScript 5.5.4 -- ESLint 8.57.1 + Prettier 3.1.2 -- Sass - -## Testing - -**Framework**: -- Vitest (configured, see [vite.config.mts](vite.config.mts)) -- @testing-library/react 12.1.4 -- @testing-library/jest-dom 5.16.2 -- Jest (legacy, available for coverage) - -**Setup**: [setupTests.js](setupTests.js) - -**CI**: GitHub Actions in `.github/workflows/ci.yml` - -## Notable Architecture Decisions - -1. **Vite over Webpack**: Faster dev server and build performance -2. **React 17.0.2**: Mature version (not React 18 yet) -3. **React Router v5**: Legacy routing (not v6) -4. **Custom Subject class**: Lightweight pub/sub without RxJS dependency -5. **Common library dependency**: Heavy reliance on `@devtron-labs/devtron-fe-common-lib` for UI primitives -6. **Dual page structure**: Legacy Pages (v1) and Pages-Devtron-2.0 (redesigned v2) coexist -7. **Service-layer abstraction**: All API calls in dedicated service files -8. **TypeScript without strict mode**: More flexible but less type-safe -9. **Feature flag-driven development**: Extensive use of `window._env_` for conditional features -10. **Manual chunk splitting**: Optimized bundle loading for large dependencies - -## Relationship to Other Repositories - -- **Depends on**: - - `@devtron-labs/devtron-fe-common-lib` (core UI components) - - `@devtron-labs/devtron-fe-lib` (domain-specific features) -- **Purpose**: Primary web application for Devtron platform -- **Type**: SPA (Single Page Application) - not a library -- **Deployment**: Serves as the frontend for Kubernetes-native CI/CD platform +`vite.config.mts` manually splits vendor chunks: `@moment`, `@react-select`, `@react-virtualized`, `@rjsf`, `@react-mde`, `@code-editor`, `@rxjs`, `@sentry`, `@react-router`, and granular chunks per `devtron-fe-common-lib` dist file. diff --git a/Dockerfile b/Dockerfile index 7a2d96a844..ca8cc97c8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22-alpine AS builder +FROM node:24-alpine AS builder WORKDIR /app diff --git a/config.md b/config.md index 64997ab9aa..3907e461f6 100644 --- a/config.md +++ b/config.md @@ -18,7 +18,8 @@ | ENABLE_CHART_SEARCH_IN_HELM_DEPLOY | "true" | Enable chart search in Helm deploy | | ENABLE_EXTERNAL_ARGO_CD | "true" | Enable External Argo CD | | ENABLE_SCOPED_VARIABLES | "false" | For enabling scoped variable from UI, also need to enable it in backend. | -| FORCE_SECURITY_SCANNING | "false" | Force security scanning | +| FORCE_SECURITY_SCANNING | "false" | Force security | +| scanning | | | GA_ENABLED | "true" | Enable Google Analytics (GA) | | GA_TRACKING_ID | G-XXXXXXXX | Google Analytics tracking ID | | GLOBAL_API_TIMEOUT | 60000 | Default timeout for all API requests in DASHBOARD | diff --git a/package.json b/package.json index 1b110119d0..e6d1f70d83 100644 --- a/package.json +++ b/package.json @@ -4,42 +4,35 @@ "private": true, "homepage": "/dashboard", "dependencies": { - "@devtron-labs/devtron-fe-common-lib": "1.23.6", + "@devtron-labs/devtron-fe-common-lib": "4.0.3", "@esbuild-plugins/node-globals-polyfill": "0.2.3", - "@rjsf/core": "^5.13.3", - "@rjsf/utils": "^5.13.3", - "@rjsf/validator-ajv8": "^5.13.3", "@sentry/browser": "7.119.1", "@sentry/integrations": "7.50.0", "@sentry/tracing": "7.50.0", "@tippyjs/react": "4.2.6", "@typeform/embed-react": "2.20.0", + "@xterm/addon-fit": "^0.11.0", + "@xterm/xterm": "^6.0.0", "command-line-parser": "^0.2.10", "compute-histogram": "^0.9.11", - "dayjs": "^1.11.8", - "dompurify": "^3.2.4", + "dayjs": "^1.11.13", + "dompurify": "^3.3.3", "fast-json-patch": "^3.1.1", "jsonpath-plus": "^10.3.0", "moment": "^2.29.4", "query-string": "^7.1.1", - "react": "^17.0.2", - "react-dates": "^21.8.0", - "react-dom": "^17.0.2", - "react-ga4": "^1.4.1", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "react-ga4": "3.0.1", "react-gtm-module": "^2.0.11", - "react-mde": "^11.5.0", - "react-router-dom": "^5.3.4", + "react-router-dom": "6.30.3", "react-select": "5.8.0", "react-virtualized": "^9.22.5", "rollup-plugin-node-polyfills": "0.2.1", - "rxjs": "^7.5.4", + "rxjs": "^7.8.1", "sockjs-client": "1.6.1", "tippy.js": "^6.3.7", - "xterm": "^4.19.0", - "xterm-addon-fit": "^0.5.0", - "xterm-addon-search": "^0.9.0", - "xterm-webfont": "^2.0.0", - "yaml": "^2.4.1" + "yaml": "^2.8.3" }, "scripts": { "prepare": "husky install", @@ -54,8 +47,6 @@ "test": "vitest test", "test-coverage:watch": "npm run test -- --coverage", "test-coverage": "npm run test -- --coverage --watchAll=false", - "test:ci": "jest --watchAll=false --ci --json --coverage --testLocationInResults --outputFile=report.json", - "jest": "jest", "lint-staged": "lint-staged", "postinstall": "patch-package" }, @@ -68,34 +59,27 @@ "devDependencies": { "@playwright/test": "^1.32.1", "@sentry/cli": "^2.2.0", - "@tanstack/eslint-plugin-query": "<5", - "@testing-library/jest-dom": "^5.16.2", - "@testing-library/react": "^12.1.4", - "@types/jest": "^27.4.1", - "@types/node": "20.11.0", - "@types/react": "17.0.39", - "@types/react-dates": "^21.8.6", - "@types/react-dom": "17.0.13", - "@types/react-router-dom": "^5.3.3", + "@tanstack/eslint-plugin-query": "^5.91.4", + "@types/node": "^25.5.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", "@types/react-transition-group": "^4.4.4", "@types/recompose": "^0.30.10", "@typescript-eslint/eslint-plugin": "8.3.0", "@typescript-eslint/parser": "8.3.0", - "@vitejs/plugin-react": "4.5.2", + "@vitejs/plugin-react": "6.0.1", "env-cmd": "10.1.0", "eslint": "^8.57.1", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-prettier": "^5.1.2", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-simple-import-sort": "^12.1.1", "husky": "^7.0.4", - "jest-extended": "^2.0.0", - "jest-junit": "^13.0.0", "json-schema": "^0.4.0", "lint-staged": "12.5.0", "mock-socket": "^9.2.1", @@ -103,39 +87,30 @@ "postinstall-postinstall": "^2.1.0", "prettier": "^3.1.1", "react-draggable": "^4.4.5", - "react-test-render": "^1.1.2", "sass": "^1.69.7", "sharp": "^0.33.5", "svgo": "^3.3.2", - "ts-jest": "29.2.5", "ts-node": "10.9.2", "typescript": "5.5.4", - "vite": "6.3.5", - "vite-plugin-compression2": "2.0.1", - "vite-plugin-pwa": "^0.21.1", + "vite": "8.0.8", + "vite-plugin-compression2": "2.4.0", + "vite-plugin-pwa": "1.2.0", "vite-plugin-require-transform": "1.0.21", - "vite-plugin-svgr": "^2.4.0", - "vite-tsconfig-paths": "5.0.1" - }, - "jest": { - "collectCoverageFrom": [ - "**/*.{ts,tsx,js,jsx}", - "!**/?(*.)+(mock).+(ts|js)", - "!**/node_modules/**", - "!**/coverage/**", - "!**/serviceWorker.ts", - "!**/index.tsx", - "!**/setupProxy.js" - ], - "setupFilesAfterEnv": [ - "jest-extended" - ] + "vite-plugin-svgr": "4.5.0" }, "resolutions": { "nanoid": "^3.3.8", "rollup": "^4.22.4", "path-to-regexp": "^1.9.0", - "cross-spawn": "^7.0.5" + "cross-spawn": "^7.0.5", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "@emotion/react": "^11.14.0" }, - "packageManager": "yarn@4.9.2" + "packageManager": "yarn@4.9.2", + "overrides": { + "vite-plugin-svgr": { + "vite": "8.0.8" + } + } } diff --git a/src/App.tsx b/src/App.tsx index dd34a2076d..cb994283c4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,18 +15,19 @@ */ import { lazy, Suspense, useEffect, useState } from 'react' -import { Redirect, Route, Switch, useHistory, useLocation } from 'react-router-dom' +import { Route, Routes, useLocation, useNavigate } from 'react-router-dom' import { API_STATUS_CODES, APPROVAL_MODAL_TYPE, + BASE_ROUTES, BreadcrumbStore, DevtronProgressing, ErrorScreenManager, getUrlWithSearchParams, + ROUTER_URLS, setGlobalAPITimeout, showError, - URLS as CommonURLS, useUserEmail, } from '@devtron-labs/devtron-fe-common-lib' @@ -36,7 +37,6 @@ import ActivateLicense from '@Pages/License/ActivateLicense' import { ErrorBoundary, getApprovalModalTypeFromURL, importComponentFromFELibrary } from './components/common' import { validateToken } from './services/service' -import { URLS } from './config' import './css/application.scss' @@ -53,14 +53,14 @@ const App = () => { const { setEmail } = useUserEmail() const location = useLocation() - const { push } = useHistory() + const navigate = useNavigate() const isDirectApprovalNotification = location.pathname && location.pathname.includes('approve') && location.search && location.search.includes(`?token=${approvalToken}`) - const customThemeClassName = location.pathname.startsWith(CommonURLS.NETWORK_STATUS_INTERFACE) + const customThemeClassName = location.pathname.startsWith(ROUTER_URLS.NETWORK_STATUS_INTERFACE.ROOT) ? 'custom-theme-override' : '' @@ -68,32 +68,29 @@ const App = () => { if (location.search) { const continueUrl = new URLSearchParams(location.search).get('continue') if (continueUrl) { - push(continueUrl) + navigate(continueUrl) } } } const toastEligibleRoutes: VersionUpdateProps['toastEligibleRoutes'] = [ { - path: `/${approvalType?.toLowerCase()}/approve`, - exact: true, + path: `${approvalType?.toLowerCase()}/approve`, condition: isDirectApprovalNotification && GenericDirectApprovalModal, component: , eligibleLocation: `/${approvalType?.toLowerCase()}/approve`, }, { - path: CommonURLS.LICENSE_AUTH, - exact: false, + path: BASE_ROUTES.LICENSE_AUTH, condition: true, component: , - eligibleLocation: CommonURLS.LICENSE_AUTH, + eligibleLocation: ROUTER_URLS.LICENSE_AUTH, }, { - path: URLS.LOGIN, - exact: false, + path: `${BASE_ROUTES.LOGIN.ROOT}/*`, condition: !window._env_.K8S_CLIENT, component: , - eligibleLocation: URLS.LOGIN_SSO || URLS.LOGIN_ADMIN, + eligibleLocation: ROUTER_URLS.LOGIN.SSO || ROUTER_URLS.LOGIN.ADMIN, }, ] @@ -122,11 +119,11 @@ const App = () => { } catch (err: any) { // push to login without breaking search if (err?.code === API_STATUS_CODES.UNAUTHORIZED) { - const loginPath = URLS.LOGIN_SSO - if (location.pathname.includes(URLS.LOGIN_SSO)) { - push(`${loginPath}${location.search}`) + const loginPath = ROUTER_URLS.LOGIN.SSO + if (location.pathname.includes(loginPath)) { + navigate(`${loginPath}${location.search}`) } else { - push(getUrlWithSearchParams(loginPath, { continue: `${location.pathname}${location.search}` })) + navigate(getUrlWithSearchParams(loginPath, { continue: `${location.pathname}${location.search}` })) } } else { setErrorPage(true) @@ -140,7 +137,7 @@ const App = () => { useEffect(() => { // If not K8S_CLIENT then validateToken otherwise directly redirect // No need to validate token if on license auth page - if (!window._env_.K8S_CLIENT && location.pathname !== CommonURLS.LICENSE_AUTH) { + if (!window._env_.K8S_CLIENT && location.pathname !== ROUTER_URLS.LICENSE_AUTH) { // By Passing validations for direct email approval notifications if (isDirectApprovalNotification) { redirectToDirectApprovalNotification() @@ -156,32 +153,6 @@ const App = () => { setGlobalAPITimeout(window._env_.GLOBAL_API_TIMEOUT) }, []) - useEffect(() => { - // Mapping few commonly used old routes to new routes - const parts = location.pathname.split('/').filter((part) => part) - - if (parts?.[0] === 'app') { - if (Number.isNaN(Number(parts?.[1]))) { - return - } - - const pageHeaderTab = parts?.[2] - - if ( - pageHeaderTab === CommonURLS.APP_DETAILS || - pageHeaderTab === CommonURLS.APP_TRIGGER || - pageHeaderTab === URLS.APP_CI_DETAILS || - pageHeaderTab === URLS.APP_CD_DETAILS || - pageHeaderTab === URLS.APP_DEPLOYMENT_METRICS || - pageHeaderTab === CommonURLS.APP_CONFIG - ) { - parts[0] = URLS.APPLICATION_MANAGEMENT_APP - const newPath = parts.join('/') - push(newPath) - } - } - }, [location]) - const renderRoutesWithErrorBoundary = () => errorPage ? (
@@ -190,17 +161,14 @@ const App = () => { ) : ( - - {toastEligibleRoutes.map(({ exact, path, condition, component }) => - condition ? ( - - {component} - - ) : null, - )} - } /> - - + + {toastEligibleRoutes + .filter(({ condition }) => condition) + .map(({ path, component }) => ( + + ))} + } /> + ) diff --git a/src/Pages-Devtron-2.0/ApplicationManagement/ApplicationManagementRouter.tsx b/src/Pages-Devtron-2.0/ApplicationManagement/ApplicationManagementRouter.tsx new file mode 100644 index 0000000000..3876803fc0 --- /dev/null +++ b/src/Pages-Devtron-2.0/ApplicationManagement/ApplicationManagementRouter.tsx @@ -0,0 +1,46 @@ +import { lazy } from 'react' +import { Navigate, Route, Routes } from 'react-router-dom' + +import { BASE_ROUTES } from '@devtron-labs/devtron-fe-common-lib' + +import { importComponentFromFELibrary } from '@Components/common' +import { DevtronAppRouter } from '@Components/common/navigation/NavRoutes.components' +import AppConfig from '@Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig' +import { OffendingPipelineModalAppView } from '@Pages/GlobalConfigurations/PluginPolicy/OffendingPipelineModal' + +import { Configurations } from './Configurations' +import { ApplicationManagementOverview } from './Overview' + +const BulkEdit = lazy(() => import('@Components/bulkEdits/BulkEdits')) +const AppGroupRoute = lazy(() => import('@Components/ApplicationGroup/AppGroupRoute')) + +const DevtronAppTemplates = importComponentFromFELibrary('DevtronAppTemplates', null, 'function') +const Policies = importComponentFromFELibrary('Policies', null, 'function') + +const ApplicationManagementRouter = ({ isSuperAdmin }: { isSuperAdmin: boolean }) => ( + + } /> + } /> + } + /> + } /> + {DevtronAppTemplates && window._env_.FEATURE_APPLICATION_TEMPLATES_ENABLE && ( + } + /> + )} + } /> + {Policies && ( + } + /> + )} + } /> + +) + +export default ApplicationManagementRouter diff --git a/src/Pages-Devtron-2.0/ApplicationManagement/Configurations/ConfigurationsRouter.tsx b/src/Pages-Devtron-2.0/ApplicationManagement/Configurations/ConfigurationsRouter.tsx index 3ccc540283..07e3628b79 100644 --- a/src/Pages-Devtron-2.0/ApplicationManagement/Configurations/ConfigurationsRouter.tsx +++ b/src/Pages-Devtron-2.0/ApplicationManagement/Configurations/ConfigurationsRouter.tsx @@ -1,26 +1,26 @@ import { lazy } from 'react' -import { Redirect, Route, Switch, useLocation } from 'react-router-dom' +import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom' import { + BASE_ROUTES, BreadCrumb, DOCUMENTATION, getApplicationManagementBreadcrumb, noop, PageHeader, + ROUTER_URLS, SERVER_MODE, SideNavigation, - URLS as COMMON_URLS, useBreadcrumb, useMainContext, } from '@devtron-labs/devtron-fe-common-lib' +import GitOpsConfiguration from '@Components/gitOps/GitOpsConfiguration' import { APPLICATION_MANAGEMENT_CONFIGURATIONS } from '@Components/Navigation' import { AddNotification } from '@Components/notifications/AddNotification' -import { URLS } from '@Config/routes' import './styles.scss' -const GitOpsConfiguration = lazy(() => import('@Components/gitOps/GitOpsConfiguration')) const GitProvider = lazy(() => import('@Components/gitProvider/GitProvider')) const DeploymentChartsRouter = lazy(() => import('@Pages/GlobalConfigurations/DeploymentCharts')) @@ -31,18 +31,20 @@ const BuildInfra = lazy(() => ) export const Configurations = () => { - const { pathname } = useLocation() + const location = useLocation() + const navigate = useNavigate() const { featureGitOpsFlags: isFeatureGitOpsEnabled, serverMode, isSuperAdmin } = useMainContext() const getDefaultRoute = () => { if (isFeatureGitOpsEnabled) { - return URLS.APPLICATION_MANAGEMENT_CONFIGURATIONS_GITOPS + return BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.GITOPS } - return URLS.APPLICATION_MANAGEMENT_CONFIGURATIONS_GIT_ACCOUNTS + return BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.GIT_ACCOUNTS } const { breadcrumbs } = useBreadcrumb( + ROUTER_URLS.APPLICATION_MANAGEMENT_CONFIGURATIONS.ROOT, { alias: { ...getApplicationManagementBreadcrumb(), @@ -51,10 +53,12 @@ export const Configurations = () => { }, }, }, - [pathname], + [], ) - const renderBreadcrumbs = () => + const renderBreadcrumbs = () => ( + + ) return ( <> @@ -64,56 +68,57 @@ export const Configurations = () => {
- + {isFeatureGitOpsEnabled && ( - {(props) => } - + key={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.GITOPS} + path={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.GITOPS} + element={} + /> )} } + key={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.GIT_ACCOUNTS} + path={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.GIT_ACCOUNTS} + element={} /> - - + key={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.DEPLOYMENT_CHARTS.ROOT} + path={`${BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.DEPLOYMENT_CHARTS.ROOT}/*`} + element={} + /> - {(props) => } - + key={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.NOTIFICATIONS_ADD_NEW} + path={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.NOTIFICATIONS_ADD_NEW} + element={} + /> - {(props) => } - - {...serverMode !== SERVER_MODE.EA_ONLY && window._env_.ENABLE_SCOPED_VARIABLES + key={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.NOTIFICATIONS} + path={`${BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.NOTIFICATIONS}/*`} + element={ + + } + /> + {...serverMode === SERVER_MODE.FULL && window._env_.ENABLE_SCOPED_VARIABLES ? [ - - , - - - , + key={BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.SCOPED_VARIABLES.ROOT} + path={`${BASE_ROUTES.APPLICATION_MANAGEMENT.CONFIGURATIONS.SCOPED_VARIABLES.ROOT}/*`} + element={} + />, ] : []} - - + } + /> + } /> +
diff --git a/src/Pages-Devtron-2.0/ApplicationManagement/Overview/BuildDeploymentMetrics/PipelineTriggerInsights.tsx b/src/Pages-Devtron-2.0/ApplicationManagement/Overview/BuildDeploymentMetrics/PipelineTriggerInsights.tsx index 4331317478..f393434ecf 100644 --- a/src/Pages-Devtron-2.0/ApplicationManagement/Overview/BuildDeploymentMetrics/PipelineTriggerInsights.tsx +++ b/src/Pages-Devtron-2.0/ApplicationManagement/Overview/BuildDeploymentMetrics/PipelineTriggerInsights.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useState } from 'react' +import { generatePath } from 'react-router-dom' import { Chart, @@ -8,13 +9,13 @@ import { getSelectPickerOptionByValue, OVERVIEW_PAGE_SIZE_OPTIONS, Pagination, + ROUTER_URLS, SectionEmptyState, SelectPicker, SelectPickerOptionType, SelectPickerVariantType, SortingOrder, TabGroup, - URLS, useStateFilters, } from '@devtron-labs/devtron-fe-common-lib' @@ -98,7 +99,14 @@ const PipelineTriggerInsights = () => { // For build pipelines pipelineId is required and for deployment pipelines envId is required if (appId && !!(isBuildTriggerInsights ? pipelineId : envId)) { - const url = `${window.__BASE_URL__}${URLS.APPLICATION_MANAGEMENT_APP}/${appId}/${isBuildTriggerInsights ? URLS.APP_CI_DETAILS : URLS.CD_DETAILS}/${isBuildTriggerInsights ? pipelineId : envId}` + const url = `${window.__BASE_URL__}${generatePath( + isBuildTriggerInsights + ? ROUTER_URLS.DEVTRON_APP_DETAILS.CI_DETAILS + : ROUTER_URLS.DEVTRON_APP_DETAILS.CD_DETAILS, + { + appId: String(appId), + }, + )}/${isBuildTriggerInsights ? pipelineId : envId}` getHandleOpenURL(url)() } } diff --git a/src/Pages-Devtron-2.0/ApplicationManagement/Overview/OverviewPageHeader.tsx b/src/Pages-Devtron-2.0/ApplicationManagement/Overview/OverviewPageHeader.tsx index 35e733f7ef..ba9b744cd0 100644 --- a/src/Pages-Devtron-2.0/ApplicationManagement/Overview/OverviewPageHeader.tsx +++ b/src/Pages-Devtron-2.0/ApplicationManagement/Overview/OverviewPageHeader.tsx @@ -4,11 +4,13 @@ import { DOCUMENTATION, getApplicationManagementBreadcrumb, PageHeader, + ROUTER_URLS, useBreadcrumb, } from '@devtron-labs/devtron-fe-common-lib' const OverviewPageHeader = () => { const { breadcrumbs } = useBreadcrumb( + ROUTER_URLS.APPLICATION_MANAGEMENT_OVERVIEW, { alias: { ...getApplicationManagementBreadcrumb(), @@ -20,7 +22,9 @@ const OverviewPageHeader = () => { [], ) - const renderBreadcrumbs = () => + const renderBreadcrumbs = () => ( + + ) return } diff --git a/src/Pages-Devtron-2.0/ApplicationManagement/Overview/constants.ts b/src/Pages-Devtron-2.0/ApplicationManagement/Overview/constants.ts index 936d8f91c6..937af34427 100644 --- a/src/Pages-Devtron-2.0/ApplicationManagement/Overview/constants.ts +++ b/src/Pages-Devtron-2.0/ApplicationManagement/Overview/constants.ts @@ -1,6 +1,5 @@ -import { getUrlWithSearchParams, MetricsInfoCardProps, URLS as COMMON_URLS } from '@devtron-labs/devtron-fe-common-lib' +import { getUrlWithSearchParams, MetricsInfoCardProps, ROUTER_URLS } from '@devtron-labs/devtron-fe-common-lib' -import { URLS } from '@Config/routes' import { TIME_WINDOW } from '@PagesDevtron2.0/Shared/types' import { GlanceMetricKeys, WorkflowOverviewMetricKeys } from './types' @@ -12,19 +11,19 @@ export const GLANCE_METRICS_CARDS_CONFIG: Record< [GlanceMetricKeys.PROJECTS]: { iconName: 'ic-bg-project', metricTitle: 'Projects', - redirectionLink: COMMON_URLS.GLOBAL_CONFIG_PROJECTS, + redirectionLink: ROUTER_URLS.GLOBAL_CONFIG_PROJECTS, tooltipContent: 'Number of projects', }, [GlanceMetricKeys.YOUR_APPLICATIONS]: { iconName: 'ic-devtron-app', metricTitle: 'Devtron Applications', - redirectionLink: COMMON_URLS.APPLICATION_MANAGEMENT_APP, + redirectionLink: ROUTER_URLS.DEVTRON_APP_LIST, tooltipContent: 'Micro-services deployed using Kubernetes-native CI/CD with Devtron.', }, [GlanceMetricKeys.ENVIRONMENTS]: { iconName: 'ic-bg-environment', metricTitle: 'Environments', - redirectionLink: getUrlWithSearchParams(URLS.GLOBAL_CONFIG_CLUSTER, { + redirectionLink: getUrlWithSearchParams(ROUTER_URLS.GLOBAL_CONFIG_CLUSTER_ENV, { selectedTab: 'environments', }), tooltipContent: 'Environments created on Devtron', diff --git a/src/Pages-Devtron-2.0/ApplicationManagement/index.ts b/src/Pages-Devtron-2.0/ApplicationManagement/index.ts index fa99c203f1..926a0b165d 100644 --- a/src/Pages-Devtron-2.0/ApplicationManagement/index.ts +++ b/src/Pages-Devtron-2.0/ApplicationManagement/index.ts @@ -1 +1 @@ -export { Configurations as ApplicationManagementConfigurationsRouter } from './Configurations' +export { default as ApplicationManagementRouter } from './ApplicationManagementRouter' diff --git a/src/Pages-Devtron-2.0/CostVisibility/Overview/Overview.tsx b/src/Pages-Devtron-2.0/CostVisibility/Overview/Overview.tsx deleted file mode 100644 index a39a994aeb..0000000000 --- a/src/Pages-Devtron-2.0/CostVisibility/Overview/Overview.tsx +++ /dev/null @@ -1 +0,0 @@ -export const Overview = () =>
Overview
diff --git a/src/Pages-Devtron-2.0/CostVisibility/Overview/index.ts b/src/Pages-Devtron-2.0/CostVisibility/Overview/index.ts deleted file mode 100644 index bb81fdde18..0000000000 --- a/src/Pages-Devtron-2.0/CostVisibility/Overview/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Overview' diff --git a/src/Pages-Devtron-2.0/CostVisibility/index.ts b/src/Pages-Devtron-2.0/CostVisibility/index.ts deleted file mode 100644 index bb81fdde18..0000000000 --- a/src/Pages-Devtron-2.0/CostVisibility/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Overview' diff --git a/src/Pages-Devtron-2.0/GlobalConfiguration/Overview/Overview.tsx b/src/Pages-Devtron-2.0/GlobalConfiguration/Overview/Overview.tsx deleted file mode 100644 index a39a994aeb..0000000000 --- a/src/Pages-Devtron-2.0/GlobalConfiguration/Overview/Overview.tsx +++ /dev/null @@ -1 +0,0 @@ -export const Overview = () =>
Overview
diff --git a/src/Pages-Devtron-2.0/GlobalConfiguration/Overview/index.ts b/src/Pages-Devtron-2.0/GlobalConfiguration/Overview/index.ts deleted file mode 100644 index bb81fdde18..0000000000 --- a/src/Pages-Devtron-2.0/GlobalConfiguration/Overview/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Overview' diff --git a/src/Pages-Devtron-2.0/GlobalConfiguration/index.ts b/src/Pages-Devtron-2.0/GlobalConfiguration/index.ts deleted file mode 100644 index bb81fdde18..0000000000 --- a/src/Pages-Devtron-2.0/GlobalConfiguration/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Overview' diff --git a/src/Pages-Devtron-2.0/GlobalOverview/GlobalOverview.tsx b/src/Pages-Devtron-2.0/GlobalOverview/GlobalOverview.tsx deleted file mode 100644 index 4b2fc725b9..0000000000 --- a/src/Pages-Devtron-2.0/GlobalOverview/GlobalOverview.tsx +++ /dev/null @@ -1 +0,0 @@ -export const GlobalOverview = () =>
GlobalOverview
diff --git a/src/Pages-Devtron-2.0/GlobalOverview/index.ts b/src/Pages-Devtron-2.0/GlobalOverview/index.ts deleted file mode 100644 index 10a9fe84b2..0000000000 --- a/src/Pages-Devtron-2.0/GlobalOverview/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './GlobalOverview' diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/InfrastructureManagementRouter.tsx b/src/Pages-Devtron-2.0/InfrastructureManagement/InfrastructureManagementRouter.tsx new file mode 100644 index 0000000000..9de872b010 --- /dev/null +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/InfrastructureManagementRouter.tsx @@ -0,0 +1,49 @@ +import { lazy } from 'react' +import { Route, Routes } from 'react-router-dom' + +import { BASE_ROUTES } from '@devtron-labs/devtron-fe-common-lib' + +import { importComponentFromFELibrary } from '@Components/common' +import { InfraAppsRouter } from '@Components/common/navigation/NavRoutes.components' +import ResourceBrowserRouter from '@Components/ResourceBrowser/ResourceBrowserRouter' + +import { InfraOverview } from './Overview' + +const Charts = lazy(() => import('@Components/charts/Charts')) +const ResourceWatcherRouter = importComponentFromFELibrary('ResourceWatcherRouter') + +const INFRASTRUCTURE_MANAGEMENT_ROUTES = BASE_ROUTES.INFRASTRUCTURE_MANAGEMENT + +const InfrastructureManagementRouter = ({ isSuperAdmin }: { isSuperAdmin: boolean }) => ( + + } + /> + } + /> + } + /> + } + /> + {window._env_.FEATURE_RESOURCE_WATCHER_ENABLE && ResourceWatcherRouter && ( + } + /> + )} + +) + +export default InfrastructureManagementRouter diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/CapacityAndResources.tsx b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/CapacityAndResources.tsx index 8617fca20b..9591f9d504 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/CapacityAndResources.tsx +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/CapacityAndResources.tsx @@ -5,7 +5,7 @@ import { getSelectPickerOptionByValue, OVERVIEW_PAGE_SIZE_OPTIONS_SMALL, Pagination, - RESOURCE_BROWSER_ROUTES, + ROUTER_URLS, SelectPicker, SelectPickerOptionType, SelectPickerVariantType, @@ -23,8 +23,8 @@ const ClusterNameCellComponent = ({ clusterId, clusterName, }: Pick) => { - const path = generatePath(RESOURCE_BROWSER_ROUTES.OVERVIEW, { - clusterId, + const path = generatePath(ROUTER_URLS.RESOURCE_BROWSER.CLUSTER_DETAILS.OVERVIEW, { + clusterId: String(clusterId), }) return ( diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/ClusterNodeHealth.tsx b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/ClusterNodeHealth.tsx index 53843c31b3..8a33065b03 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/ClusterNodeHealth.tsx +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/ClusterNodeHealth.tsx @@ -1,10 +1,11 @@ -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { Chart, ChartColorKey, ChartProps, noop, + ROUTER_URLS, SectionEmptyState, useMainContext, } from '@devtron-labs/devtron-fe-common-lib' @@ -72,7 +73,7 @@ const ClusterNodeHealthCard = ({ } const ClusterNodeHealth = ({ clusterNodeHealth }: ClusterNodeHealthProps) => { - const { push, location } = useHistory() + const navigate = useNavigate() const { setTempAppWindowConfig } = useMainContext() const getChartClickHandler: (key: ClusterNodeHealthStatusKeys) => ChartProps['onChartClick'] = (key) => { @@ -89,11 +90,11 @@ const ClusterNodeHealth = ({ clusterNodeHealth }: ClusterNodeHealthProps) => { customCloseConfig: { icon: null, beforeClose: () => { - push(location.pathname) + navigate(ROUTER_URLS.INFRASTRUCTURE_MANAGEMENT_OVERVIEW) }, }, }) - push({ search: searchParams.toString() }) + navigate({ search: searchParams.toString() }) } case ClusterNodeHealthStatusKeys.NODE_SCHEDULING_BREAKDOWN: return (datasetName) => { @@ -108,17 +109,17 @@ const ClusterNodeHealth = ({ clusterNodeHealth }: ClusterNodeHealthProps) => { customCloseConfig: { icon: null, beforeClose: () => { - push(location.pathname) + navigate(ROUTER_URLS.INFRASTRUCTURE_MANAGEMENT_OVERVIEW) }, }, }) - push({ search: searchParams.toString() }) + navigate({ search: searchParams.toString() }) } case ClusterNodeHealthStatusKeys.CLUSTER_STATUS_BREAKDOWN: return (datasetName) => { const clusterFilter = getClusterFilterTypeFromLabel(datasetName) - return push(getClusterListingUrl(clusterFilter)) + return navigate(getClusterListingUrl(clusterFilter)) } default: return noop diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeCount.tsx b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeCount.tsx index b17f027bc8..4a72bdcdad 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeCount.tsx +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeCount.tsx @@ -1,5 +1,5 @@ import { useMemo, useState } from 'react' -import { generatePath, useHistory } from 'react-router-dom' +import { generatePath, useNavigate } from 'react-router-dom' import { ButtonComponentType, @@ -15,7 +15,7 @@ import { numberComparatorBySortOrder, OVERVIEW_PAGE_SIZE_OPTIONS, Pagination, - RESOURCE_BROWSER_ROUTES, + ROUTER_URLS, SelectPicker, SelectPickerOptionType, SelectPickerVariantType, @@ -33,7 +33,7 @@ import { getClusterNodeTooltipContent } from './utils' const NodeCounts = ({ nodeDistribution }: NodeCountsProps) => { const { setTempAppWindowConfig } = useMainContext() - const { push, location } = useHistory() + const navigate = useNavigate() const { offset, pageSize, changePage, changePageSize } = useStateFilters({ defaultPageSize: OVERVIEW_PAGE_SIZE_OPTIONS[0].value, }) @@ -65,21 +65,21 @@ const NodeCounts = ({ nodeDistribution }: NodeCountsProps) => { component: , customCloseConfig: { beforeClose: () => { - push(location.pathname) + navigate(ROUTER_URLS.INFRASTRUCTURE_MANAGEMENT_OVERVIEW) }, icon: null, }, }) - push({ search: searchParams.toString() }) + navigate({ search: searchParams.toString() }) } const handleRedirectToCluster: ChartProps['onChartClick'] = (_, idx) => { - const path = generatePath(RESOURCE_BROWSER_ROUTES.K8S_RESOURCE_LIST, { - clusterId: nodeDistribution[NodeDistributionKeys.BY_CLUSTERS][idx].clusterId, + const path = generatePath(ROUTER_URLS.RESOURCE_BROWSER.CLUSTER_DETAILS.K8S_RESOURCE_LIST, { + clusterId: String(nodeDistribution[NodeDistributionKeys.BY_CLUSTERS][idx].clusterId), kind: 'node', group: K8S_EMPTY_GROUP, }) - push(path) + navigate(path) } const { xAxisLabels, yAxisValues } = useMemo(() => { diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeViewGroupList.tsx b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeViewGroupList.tsx index 2d82e86a98..bf1f01b5f7 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeViewGroupList.tsx +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/ClusterAndNodes/NodeViewGroupList.tsx @@ -1,5 +1,5 @@ import { useCallback, useMemo } from 'react' -import { generatePath, Link, useHistory } from 'react-router-dom' +import { generatePath, Link, useNavigate } from 'react-router-dom' import { ExportToCsv, @@ -8,7 +8,7 @@ import { Icon, noop, PaginationEnum, - RESOURCE_BROWSER_ROUTES, + ROUTER_URLS, SearchBar, SelectPicker, SelectPickerOptionType, @@ -66,7 +66,10 @@ const NodeNameCellComponent = ({ row }: TableCellComponentProps @@ -236,7 +239,7 @@ const NodeViewGroupListWrapper = ({ } const NodeViewGroupList = ({ nodeViewGroupType }: { nodeViewGroupType: NodeViewGroupType }) => { - const { push } = useHistory() + const navigate = useNavigate() const getRows: TableProps['getRows'] = useCallback( async ( { @@ -282,7 +285,7 @@ const NodeViewGroupList = ({ nodeViewGroupType }: { nodeViewGroupType: NodeViewG ) const clearFilters = () => { - push({ search: '' }) + navigate({ search: '' }) } return ( diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/Overview.tsx b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/Overview.tsx index 6c43bbf023..fed864f38f 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/Overview.tsx +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/Overview.tsx @@ -6,11 +6,10 @@ import { GenericEmptyState, Icon, InfoBlock, - URLS as COMMON_URLS, + ROUTER_URLS, } from '@devtron-labs/devtron-fe-common-lib' import { importComponentFromFELibrary } from '@Components/common' -import { URLS } from '@Config/routes' import InfrastructureManagementAtAGlance from './AtAGlance' import { ClusterAndNodes } from './ClusterAndNodes' @@ -40,9 +39,7 @@ const Overview = () => { endIcon={noConnectedClusters ? null : } component={ButtonComponentType.link} linkProps={{ - to: noConnectedClusters - ? URLS.GLOBAL_CONFIG_CLUSTER - : COMMON_URLS.INFRASTRUCTURE_MANAGEMENT_RESOURCE_BROWSER, + to: noConnectedClusters ? ROUTER_URLS.GLOBAL_CONFIG_CLUSTER_ENV : ROUTER_URLS.RESOURCE_BROWSER.ROOT, }} /> ) diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/OverviewPageHeader.tsx b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/OverviewPageHeader.tsx index f913c6309c..4a37f67ac6 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/OverviewPageHeader.tsx +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/OverviewPageHeader.tsx @@ -4,11 +4,13 @@ import { DOCUMENTATION, getInfrastructureManagementBreadcrumb, PageHeader, + ROUTER_URLS, useBreadcrumb, } from '@devtron-labs/devtron-fe-common-lib' const OverviewPageHeader = () => { const { breadcrumbs } = useBreadcrumb( + ROUTER_URLS.INFRASTRUCTURE_MANAGEMENT_OVERVIEW, { alias: { ...getInfrastructureManagementBreadcrumb(), @@ -20,7 +22,9 @@ const OverviewPageHeader = () => { [], ) - const renderBreadcrumbs = () => + const renderBreadcrumbs = () => ( + + ) return } diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/utils.ts b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/utils.ts index a14c9e02d1..9b10a309d4 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/utils.ts +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/Overview/utils.ts @@ -2,7 +2,7 @@ import { ClusterFiltersType, getUrlWithSearchParams, MetricsInfoCardProps, - URLS, + ROUTER_URLS, } from '@devtron-labs/devtron-fe-common-lib' import { AUTOSCALER_TYPE_LABELS, NODE_ERRORS_LABEL_MAP } from './ClusterAndNodes/constants' @@ -30,7 +30,7 @@ export const getInfraGlanceConfig = (result: InfraOverviewDTO) => Object.entries(INFRA_OVERVIEW_CARDS_CONFIG).map(([key, config]: [GlanceMetricsKeys, MetricsInfoCardProps]) => ({ ...config, dataTestId: key, - redirectionLink: URLS.INFRASTRUCTURE_MANAGEMENT_RESOURCE_BROWSER, + redirectionLink: ROUTER_URLS.RESOURCE_BROWSER.ROOT, metricValue: (key === GlanceMetricsKeys.REACHABLE_CLUSTERS ? getReachableClusterCount(result) : result?.[key]?.value ?? 0 @@ -100,6 +100,6 @@ export const getNodeListDataForExport = (groupBy: NodeViewGroupType, nodeList: N }) export const getClusterListingUrl = (clusterFilter?: ClusterFiltersType) => - getUrlWithSearchParams(URLS.INFRASTRUCTURE_MANAGEMENT_RESOURCE_BROWSER, { + getUrlWithSearchParams(ROUTER_URLS.RESOURCE_BROWSER.CLUSTER_LIST, { clusterFilter: clusterFilter ?? ClusterFiltersType.ALL_CLUSTERS, }) diff --git a/src/Pages-Devtron-2.0/InfrastructureManagement/index.ts b/src/Pages-Devtron-2.0/InfrastructureManagement/index.ts index bb81fdde18..1edc5e4cd4 100644 --- a/src/Pages-Devtron-2.0/InfrastructureManagement/index.ts +++ b/src/Pages-Devtron-2.0/InfrastructureManagement/index.ts @@ -1 +1,2 @@ +export { default as InfrastructureManagementRouter } from './InfrastructureManagementRouter' export * from './Overview' diff --git a/src/Pages-Devtron-2.0/SecurityCenter/Overview/OverviewPageHeader.tsx b/src/Pages-Devtron-2.0/SecurityCenter/Overview/OverviewPageHeader.tsx index ff5b99b470..f8b61b3e47 100644 --- a/src/Pages-Devtron-2.0/SecurityCenter/Overview/OverviewPageHeader.tsx +++ b/src/Pages-Devtron-2.0/SecurityCenter/Overview/OverviewPageHeader.tsx @@ -4,6 +4,7 @@ import { DOCUMENTATION, getSecurityCenterBreadcrumb, PageHeader, + ROUTER_URLS, useBreadcrumb, } from '@devtron-labs/devtron-fe-common-lib' @@ -24,6 +25,7 @@ const TippyContent = () => ( const OverviewPageHeader = () => { const { breadcrumbs } = useBreadcrumb( + ROUTER_URLS.SECURITY_CENTER_OVERVIEW, { alias: { ...getSecurityCenterBreadcrumb(), @@ -35,7 +37,7 @@ const OverviewPageHeader = () => { [], ) - const renderBreadcrumbs = () => + const renderBreadcrumbs = () => return ( ( ) const SeverityDistribution = ({ prodNonProdValue }: { prodNonProdValue: ProdNonProdSelectValueTypes }) => { - const { push } = useHistory() + const navigate = useNavigate() const { isFetching, isError, data, refetch } = useGetSeverityInsights(prodNonProdValue) const { severityDistributionLabels, severityDistributionDataset, ageDistributionDataset } = data || {} @@ -41,16 +41,16 @@ const SeverityDistribution = ({ prodNonProdValue }: { prodNonProdValue: ProdNonP } const handleSeverityDistributionClick: ChartProps['onChartClick'] = (_, idx) => { - push( - getUrlWithSearchParams(URLS.SECURITY_CENTER_VULNERABILITY_DEPLOYMENTS, { + navigate( + getUrlWithSearchParams(ROUTER_URLS.SECURITY_CENTER_VULNERABILITY_DEPLOYMENTS, { severity: severityDistributionLabels[idx].toLowerCase(), }), ) } const handleAgeDistributionClick: ChartProps['onChartClick'] = (_, idx) => { - push( - getUrlWithSearchParams(URLS.SECURITY_CENTER_VULNERABILITY_CVES, { + navigate( + getUrlWithSearchParams(ROUTER_URLS.SECURITY_CENTER_VULNERABILITY_CVES, { ageOfDiscovery: AGE_DISTRIBUTION_FILTERS[idx], }), ) diff --git a/src/Pages-Devtron-2.0/SecurityCenter/Overview/constants.ts b/src/Pages-Devtron-2.0/SecurityCenter/Overview/constants.ts index 91df5f42d5..79b7b53aea 100644 --- a/src/Pages-Devtron-2.0/SecurityCenter/Overview/constants.ts +++ b/src/Pages-Devtron-2.0/SecurityCenter/Overview/constants.ts @@ -4,9 +4,9 @@ import { getUrlWithSearchParams, MetricsInfoCardProps, ProdNonProdSelectValueTypes, + ROUTER_URLS, SelectPickerOptionType, Severity, - URLS, VulnerabilityDiscoveryAgeOptions, } from '@devtron-labs/devtron-fe-common-lib' @@ -21,14 +21,14 @@ export const SECURITY_AT_A_GLANCE_CARDS_CONFIG: Record< dataTestId: SecurityGlanceMetricKeys.TOTAL_VULNERABILITIES, iconName: 'ic-security-vulnerability', tooltipContent: 'Total number of vulnerabilities found across currently active deployments', - redirectionLink: URLS.SECURITY_CENTER_VULNERABILITY_CVES, + redirectionLink: ROUTER_URLS.SECURITY_CENTER_VULNERABILITY_CVES, }, [SecurityGlanceMetricKeys.FIXABLE_VULNERABILITIES]: { metricTitle: 'Fixable Vulnerabilities', dataTestId: SecurityGlanceMetricKeys.FIXABLE_VULNERABILITIES, iconName: 'ic-security-fixable', tooltipContent: 'Discovered vulnerabilities on currently active deployments whose fix is available', - redirectionLink: getUrlWithSearchParams(URLS.SECURITY_CENTER_VULNERABILITY_CVES, { + redirectionLink: getUrlWithSearchParams(ROUTER_URLS.SECURITY_CENTER_VULNERABILITY_CVES, { fixAvailability: FixAvailabilityOptions.FIX_AVAILABLE, }), }, @@ -37,7 +37,7 @@ export const SECURITY_AT_A_GLANCE_CARDS_CONFIG: Record< dataTestId: SecurityGlanceMetricKeys.ZERO_DAY_VULNERABILITIES, iconName: 'ic-security-not-fixable', tooltipContent: 'Discovered vulnerabilities on currently active deployments whose fix is not available', - redirectionLink: getUrlWithSearchParams(URLS.SECURITY_CENTER_VULNERABILITY_CVES, { + redirectionLink: getUrlWithSearchParams(ROUTER_URLS.SECURITY_CENTER_VULNERABILITY_CVES, { fixAvailability: FixAvailabilityOptions.FIX_NOT_AVAILABLE, }), }, diff --git a/src/Pages-Devtron-2.0/SoftwareReleaseManagement/Overview/Overview.tsx b/src/Pages-Devtron-2.0/SoftwareReleaseManagement/Overview/Overview.tsx deleted file mode 100644 index a39a994aeb..0000000000 --- a/src/Pages-Devtron-2.0/SoftwareReleaseManagement/Overview/Overview.tsx +++ /dev/null @@ -1 +0,0 @@ -export const Overview = () =>
Overview
diff --git a/src/Pages-Devtron-2.0/SoftwareReleaseManagement/Overview/index.ts b/src/Pages-Devtron-2.0/SoftwareReleaseManagement/Overview/index.ts deleted file mode 100644 index bb81fdde18..0000000000 --- a/src/Pages-Devtron-2.0/SoftwareReleaseManagement/Overview/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Overview' diff --git a/src/Pages-Devtron-2.0/SoftwareReleaseManagement/index.ts b/src/Pages-Devtron-2.0/SoftwareReleaseManagement/index.ts deleted file mode 100644 index bb81fdde18..0000000000 --- a/src/Pages-Devtron-2.0/SoftwareReleaseManagement/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Overview' diff --git a/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CDStepperContent.tsx b/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CDStepperContent.tsx index 206677c71e..e8a6afe45a 100644 --- a/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CDStepperContent.tsx +++ b/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CDStepperContent.tsx @@ -15,7 +15,7 @@ */ import { ChangeEvent, useState } from 'react' -import { useHistory } from 'react-router-dom' +import { generatePath, useNavigate } from 'react-router-dom' import { API_STATUS_CODES, @@ -25,6 +25,7 @@ import { Icon, InfoBlock, noop, + ROUTER_URLS, showError, } from '@devtron-labs/devtron-fe-common-lib' @@ -62,7 +63,7 @@ export const CDStepperContent = ({ const [gitopsConflictLoading, setGitopsConflictLoading] = useState(false) // HOOKS - const { push } = useHistory() + const navigate = useNavigate() // CONSTANTS const { environments, selectedEnvironment, deploymentAppType } = ciCdPipeline.cd @@ -108,7 +109,9 @@ export const CDStepperContent = ({ await getGitOpsRepoConfig(+appId) setGitopsConflictLoading(false) - push(`${URLS.APPLICATION_MANAGEMENT_APP}/${appId}/edit/${URLS.APP_GITOPS_CONFIG}`) + navigate( + `${generatePath(ROUTER_URLS.DEVTRON_APP_DETAILS.CONFIGURATIONS, { appId })}/${URLS.APP_GITOPS_CONFIG}`, + ) } catch (err) { setGitopsConflictLoading(false) if (err.code === API_STATUS_CODES.CONFLICT) { diff --git a/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CreateCICDPipeline.tsx b/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CreateCICDPipeline.tsx index 060e5e9f86..40eedcc86b 100644 --- a/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CreateCICDPipeline.tsx +++ b/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/CreateCICDPipeline.tsx @@ -30,6 +30,7 @@ import { ToastManager, ToastVariantType, useAsync, + useMainContext, } from '@devtron-labs/devtron-fe-common-lib' import { saveCIPipeline } from '@Components/ciPipeline/ciPipeline.service' @@ -90,9 +91,11 @@ export const CreateCICDPipeline = ({ // REFS const ciPipelineResRef = useRef<{ appWorkflowId: number; id: number } | null>(null) + const { forceDockerfileScan } = useMainContext() + // ASYNC CALLS const [isCiCdPipelineLoading, ciCdPipelineRes, ciCdPipelineErr, reloadCiCdPipeline, setter] = useAsync( - () => getCICDPipelineInitData(appId, isTemplateView), + () => getCICDPipelineInitData(appId, isTemplateView, forceDockerfileScan), [open, isTemplateView], open, ) diff --git a/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/service.ts b/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/service.ts index bc9e39a009..115e004a0b 100644 --- a/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/service.ts +++ b/src/Pages/App/Configurations/WorkflowEditor/CreateCICDPipeline/service.ts @@ -117,10 +117,10 @@ const getCDInitData = async (appId: string, isTemplateView: boolean): Promise { +const getCIInitData = async (appId: string, isTemplateView: boolean, forceDockerfileScan: boolean) => { const { result: { form, isBlobStorageConfigured, isSecurityModuleInstalled }, - } = await getInitData(appId.toString(), true, false, isTemplateView) + } = await getInitData(appId.toString(), true, false, isTemplateView, forceDockerfileScan) return { ...form, @@ -132,9 +132,13 @@ const getCIInitData = async (appId: string, isTemplateView: boolean) => { export const getCICDPipelineInitData = async ( appId: string, isTemplateView: boolean, + forceDockerfileScan: boolean, ): Promise => { try { - const [ci, cd] = await Promise.all([getCIInitData(appId, isTemplateView), getCDInitData(appId, isTemplateView)]) + const [ci, cd] = await Promise.all([ + getCIInitData(appId, isTemplateView, forceDockerfileScan), + getCDInitData(appId, isTemplateView), + ]) return { ci, cd } } catch (err) { diff --git a/src/Pages/App/Configurations/WorkflowEditor/utils.tsx b/src/Pages/App/Configurations/WorkflowEditor/utils.tsx index 8aa13f9771..aa411bebbf 100644 --- a/src/Pages/App/Configurations/WorkflowEditor/utils.tsx +++ b/src/Pages/App/Configurations/WorkflowEditor/utils.tsx @@ -21,11 +21,10 @@ import { DeploymentAppTypes, MaterialType, PipelineFormType, + ROUTER_URLS, SelectPickerProps, } from '@devtron-labs/devtron-fe-common-lib' -import { URLS } from '@Config/routes' - const gitOpsRepoNotConfiguredWithOptionsHidden = 'Deployment via GitOps requires a repository to save deployment manifests. Please configure and try again.' @@ -137,7 +136,7 @@ export const getCIPipelineBranchSelectorFooterConfig = ( value: ( Select git host for this git account to view all supported options.  - + Select git host diff --git a/src/Pages/App/CreateAppModal/ApplicationInfoForm.tsx b/src/Pages/App/CreateAppModal/ApplicationInfoForm.tsx index c3b93712a9..322ddf6b34 100644 --- a/src/Pages/App/CreateAppModal/ApplicationInfoForm.tsx +++ b/src/Pages/App/CreateAppModal/ApplicationInfoForm.tsx @@ -18,7 +18,7 @@ import { ChangeEvent } from 'react' import { CustomInput, TagsContainer, Textarea } from '@devtron-labs/devtron-fe-common-lib' -import { ReactComponent as ICCaretLeftSmall } from '@Icons/ic-caret-left-small.svg' +import ICCaretLeftSmall from '@Icons/ic-caret-left-small.svg?react' import { importComponentFromFELibrary } from '@Components/common' import { APP_TYPE } from '@Config/constants' import { getAppIconWithBackground } from '@Config/utils' diff --git a/src/Pages/App/CreateAppModal/CreateAppModal.component.tsx b/src/Pages/App/CreateAppModal/CreateAppModal.component.tsx index 3e912a48df..53915aa4ef 100644 --- a/src/Pages/App/CreateAppModal/CreateAppModal.component.tsx +++ b/src/Pages/App/CreateAppModal/CreateAppModal.component.tsx @@ -15,11 +15,12 @@ */ import { useEffect, useMemo, useState } from 'react' -import { useHistory } from 'react-router-dom' +import { generatePath, useNavigate } from 'react-router-dom' import { Button, Drawer, + ROUTER_URLS, showError, ToastManager, ToastVariantType, @@ -31,7 +32,7 @@ import { importComponentFromFELibrary } from '@Components/common' import { saveHostURLConfiguration } from '@Components/hostURL/hosturl.service' import { createJob } from '@Components/Jobs/Service' import { REQUIRED_FIELDS_MISSING } from '@Config/constants' -import { APP_COMPOSE_STAGE, getAppComposeURL, URLS } from '@Config/routes' +import { APP_COMPOSE_STAGE, getAppComposeURL } from '@Config/routes' import { getHostURLConfiguration } from '@Services/service' import ApplicationInfoForm from './ApplicationInfoForm' @@ -55,7 +56,7 @@ import './styles.scss' const createDevtronAppUsingTemplate = importComponentFromFELibrary('createDevtronAppUsingTemplate', null, 'function') const CreateAppModal = ({ isJobView, handleClose }: CreateAppModalProps) => { - const history = useHistory() + const navigate = useNavigate() const [isSubmitting, setIsSubmitting] = useState(false) const [selectedCreationMethod, setSelectedCreationMethod] = useState(null) const [formState, setFormState] = useState(structuredClone(createAppInitialFormState)) @@ -234,9 +235,9 @@ const CreateAppModal = ({ isJobView, handleClose }: CreateAppModalProps) => { const redirectToArtifacts = (appId: string) => { const url = isCreationMethodTemplate - ? `${URLS.APPLICATION_MANAGEMENT_APP}/${appId}/${URLS.APP_TRIGGER}` + ? generatePath(ROUTER_URLS.DEVTRON_APP_DETAILS.TRIGGER, { appId }) : getAppComposeURL(appId, APP_COMPOSE_STAGE.SOURCE_CONFIG, isJobView, false) - history.push(url) + navigate(url) } const getCreateApiMethod = () => { diff --git a/src/Pages/App/CreateAppModal/HeaderSection.tsx b/src/Pages/App/CreateAppModal/HeaderSection.tsx index 08783c8ae6..4fb0d8800e 100644 --- a/src/Pages/App/CreateAppModal/HeaderSection.tsx +++ b/src/Pages/App/CreateAppModal/HeaderSection.tsx @@ -16,7 +16,7 @@ import { Button, ButtonStyleType, ButtonVariantType, ComponentSizeType } from '@devtron-labs/devtron-fe-common-lib' -import { ReactComponent as ICClose } from '@Icons/ic-close.svg' +import ICClose from '@Icons/ic-close.svg?react' import { HeaderSectionProps } from './types' diff --git a/src/Pages/App/CreateAppModal/ProjectSelector.tsx b/src/Pages/App/CreateAppModal/ProjectSelector.tsx index 33117940bb..9fb4c7a952 100644 --- a/src/Pages/App/CreateAppModal/ProjectSelector.tsx +++ b/src/Pages/App/CreateAppModal/ProjectSelector.tsx @@ -22,7 +22,7 @@ import { useGetResourceKindsOptions, } from '@devtron-labs/devtron-fe-common-lib' -import { ReactComponent as ICFolderColor } from '@Icons/ic-folder-color.svg' +import ICFolderColor from '@Icons/ic-folder-color.svg?react' import { PROJECT_SELECT_INPUT_ID } from './constants' import { CreateAppFormStateType, ProjectSelectorProps } from './types' diff --git a/src/Pages/App/CreateAppModal/Workflow/utils.tsx b/src/Pages/App/CreateAppModal/Workflow/utils.tsx index 131e3b561e..955bc57b36 100644 --- a/src/Pages/App/CreateAppModal/Workflow/utils.tsx +++ b/src/Pages/App/CreateAppModal/Workflow/utils.tsx @@ -26,15 +26,15 @@ import { WorkflowType, } from '@devtron-labs/devtron-fe-common-lib' -import { ReactComponent as ICCD } from '@Icons/ic-CD.svg' -import { ReactComponent as ICCi } from '@Icons/ic-CI.svg' -import { ReactComponent as ICCIWebhook } from '@Icons/ic-CIWebhook.svg' -import { ReactComponent as ICError } from '@Icons/ic-error.svg' -import { ReactComponent as ICJobNode } from '@Icons/ic-job-node.svg' -import { ReactComponent as ICLinkedCD } from '@Icons/ic-linked-cd.svg' -import { ReactComponent as ICNodeBuildLinked } from '@Icons/ic-node-build-linked.svg' -import { ReactComponent as ICPaperRocket } from '@Icons/ic-paper-rocket.svg' -import { ReactComponent as ICWarning } from '@Icons/ic-warning.svg' +import ICCD from '@Icons/ic-CD.svg?react' +import ICCi from '@Icons/ic-CI.svg?react' +import ICCIWebhook from '@Icons/ic-CIWebhook.svg?react' +import ICError from '@Icons/ic-error.svg?react' +import ICJobNode from '@Icons/ic-job-node.svg?react' +import ICLinkedCD from '@Icons/ic-linked-cd.svg?react' +import ICNodeBuildLinked from '@Icons/ic-node-build-linked.svg?react' +import ICPaperRocket from '@Icons/ic-paper-rocket.svg?react' +import ICWarning from '@Icons/ic-warning.svg?react' import { createClusterEnvGroup } from '@Components/common' import { diff --git a/src/Pages/App/Details/ExternalFlux/ExternalFluxAppDetailsRoute.tsx b/src/Pages/App/Details/ExternalFlux/ExternalFluxAppDetailsRoute.tsx index 52d4061dd3..1fef5d0388 100644 --- a/src/Pages/App/Details/ExternalFlux/ExternalFluxAppDetailsRoute.tsx +++ b/src/Pages/App/Details/ExternalFlux/ExternalFluxAppDetailsRoute.tsx @@ -15,9 +15,9 @@ */ import { lazy, Suspense } from 'react' -import { Redirect, Route, Switch, useRouteMatch } from 'react-router-dom' +import { Navigate, Route, Routes } from 'react-router-dom' -import { AppListConstants, Progressing } from '@devtron-labs/devtron-fe-common-lib' +import { AppListConstants, Progressing, ROUTER_URLS } from '@devtron-labs/devtron-fe-common-lib' import { URLS } from '@Config/routes' @@ -25,31 +25,26 @@ import EAHeaderComponent from '../../../../components/v2/headers/EAHeader.compon const ExternalFluxAppDetails = lazy(() => import('./ExternalFluxAppDetails')) -const ExternalFluxAppDetailsRoute = () => { - const { path } = useRouteMatch() - - return ( - <> - - }> - - - - - - - - - ) -} +const ExternalFluxAppDetailsRoute = () => ( + <> + + }> + + } /> + } /> + + + +) export default ExternalFluxAppDetailsRoute diff --git a/src/Pages/App/Details/ExternalFlux/types.tsx b/src/Pages/App/Details/ExternalFlux/types.tsx index a8473e1027..51e94dc850 100644 --- a/src/Pages/App/Details/ExternalFlux/types.tsx +++ b/src/Pages/App/Details/ExternalFlux/types.tsx @@ -16,7 +16,7 @@ import { APIOptions } from '@devtron-labs/devtron-fe-common-lib' -export interface ExternalFluxAppDetailParams { +export type ExternalFluxAppDetailParams = { clusterId: string appName: string namespace: string diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx index 69fbb88670..ab34e30a35 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx @@ -15,7 +15,7 @@ */ import { useEffect, useState } from 'react' -import { useHistory, useLocation, useParams, useRouteMatch } from 'react-router-dom' +import { generatePath, useLocation, useNavigate, useParams } from 'react-router-dom' import { AppConfigProps, @@ -26,10 +26,11 @@ import { Progressing, ResourceIdToResourceApprovalPolicyConfigMapType, ResourceKindType, + ROUTER_URLS, showError, ToastManager, ToastVariantType, - URLS as CommonUrls, + URLS as CommonURLS, useAsync, } from '@devtron-labs/devtron-fe-common-lib' @@ -65,9 +66,9 @@ const getApprovalPolicyConfigForApp: (appId: number) => Promise { // HOOKS const { appId } = useParams<{ appId: string }>() - const match = useRouteMatch() + const location = useLocation() - const history = useHistory() + const navigate = useNavigate() // STATES const [showCannotDeleteTooltip, setShowCannotDeleteTooltip] = useState(false) @@ -94,8 +95,19 @@ const AppConfig = ({ appName, resourceKind, filteredEnvIds, isTemplateView }: Ap }, }) + const getCurrentPathPattern = () => { + if (isTemplateView) { + return `${ROUTER_URLS.APP_TEMPLATE_DETAIL}/${CommonURLS.APP_CONFIG}` + } + if (resourceKind === ResourceKindType.job) { + return ROUTER_URLS.JOB_DETAIL.CONFIGURATIONS + } + return ROUTER_URLS.DEVTRON_APP_DETAILS.CONFIGURATIONS + } + // GLOBAL CONSTANTS const isJob = resourceKind === ResourceKindType.job + const matchUrl = generatePath(getCurrentPathPattern(), { appId }) /** * Fetches environment configurations and protections for a given application. @@ -320,15 +332,16 @@ const AppConfig = ({ appName, resourceKind, filteredEnvIds, isTemplateView }: Ap environmentList: updatedEnvs, envIdToEnvApprovalConfigurationMap, }) - if (location.pathname === match.url) { - history.replace(redirectUrl) + + if (location.pathname === matchUrl) { + navigate(redirectUrl, { replace: true }) } } }, [appConfigData]) // METHODS const reloadAppConfig = () => { - history.push(`${URLS.APPLICATION_MANAGEMENT_APP}/${appId}/edit`) + navigate(generatePath(ROUTER_URLS.DEVTRON_APP_DETAILS.CONFIGURATIONS, { appId })) setState((prevState) => ({ ...prevState, view: ViewType.LOADING })) setReload(!reload) } @@ -353,19 +366,19 @@ const AppConfig = ({ appName, resourceKind, filteredEnvIds, isTemplateView }: Ap variant: ToastVariantType.success, description: 'Job Deleted!', }) - history.push(`${URLS.AUTOMATION_AND_ENABLEMENT_JOB}/${URLS.APP_LIST}`) + navigate(ROUTER_URLS.JOBS_LIST) } else if (isTemplateView) { ToastManager.showToast({ variant: ToastVariantType.success, description: 'Template Deleted!', }) - history.push(CommonUrls.APPLICATION_MANAGEMENT_TEMPLATES_DEVTRON_APP) + navigate(ROUTER_URLS.APP_TEMPLATES) } else { ToastManager.showToast({ variant: ToastVariantType.success, description: 'Application Deleted!', }) - history.push(`${URLS.APPLICATION_MANAGEMENT_APP}/${URLS.APP_LIST}`) + navigate(ROUTER_URLS.DEVTRON_APP_LIST) } } } catch (error) { @@ -390,7 +403,7 @@ const AppConfig = ({ appName, resourceKind, filteredEnvIds, isTemplateView }: Ap redirectionUrl: redirectUrl, })) if (redirection) { - history.push(redirectUrl) + navigate(redirectUrl) } }) .catch((errors) => { @@ -423,7 +436,7 @@ const AppConfig = ({ appName, resourceKind, filteredEnvIds, isTemplateView }: Ap const redirectToWorkflowEditor = () => { onClickCloseCannotDeleteModal() - history.push(getAppComposeURL(appId, APP_COMPOSE_STAGE.WORKFLOW_EDITOR, isJob, isTemplateView)) + navigate(getAppComposeURL(appId, APP_COMPOSE_STAGE.WORKFLOW_EDITOR, isJob, isTemplateView)) } const getDeleteComponentName = (): DeleteComponentsName => { @@ -485,7 +498,7 @@ const AppConfig = ({ appName, resourceKind, filteredEnvIds, isTemplateView }: Ap return 'app-compose-for-env-compare' } - return location.pathname.includes(`/${URLS.APP_DOCKER_CONFIG}`) || + return location.pathname.includes(URLS.APP_DOCKER_CONFIG) || (typeof Storage !== 'undefined' && localStorage.getItem('takeMeThereClicked') === '1') ? 'dc__position-rel' : '' @@ -537,10 +550,10 @@ const AppConfig = ({ appName, resourceKind, filteredEnvIds, isTemplateView }: Ap
- +
- +
{renderDeleteDialog()} diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts index 2490476b63..fb08dd8fda 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import type { JSX } from 'react' + import { AppConfigProps, AppEnvDeploymentConfigType, @@ -219,9 +221,10 @@ export interface EnvConfigurationsNavProps extends Required string overwriteNavHeading?: string + routePath: string } & ( | { type: 'appGroup' diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts index 98f6c04985..f14ef17e71 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts @@ -21,6 +21,7 @@ import { BASE_CONFIGURATION_ENV_ID, ConfigResourceType, ResourceKindType, + ROUTER_URLS, stringComparatorBySortOrder, URLS as CommonURLS, } from '@devtron-labs/devtron-fe-common-lib' @@ -122,9 +123,10 @@ export const getNavItems = ({ ) let completedPercent = 0 - const basePath = isTemplateView - ? generatePath(CommonURLS.APPLICATION_MANAGEMENT_TEMPLATES_DEVTRON_APP_DETAIL, { appId }) - : `${URLS.APPLICATION_MANAGEMENT_APP}/${appId}` + const basePath = generatePath( + isTemplateView ? ROUTER_URLS.APP_TEMPLATE_DETAIL : ROUTER_URLS.DEVTRON_APP_DETAILS.ROOT, + { appId }, + ) switch (resourceKind) { case ResourceKindType.job: @@ -134,7 +136,7 @@ export const getNavItems = ({ navItems: [ { title: 'Source code', - href: `${URLS.AUTOMATION_AND_ENABLEMENT_JOB}/${appId}/edit/materials`, + href: `${ROUTER_URLS.JOBS}/${appId}/edit/materials`, stage: STAGE_NAME.GIT_MATERIAL, isLocked: !_isUnlocked.material, supportDocumentURL: 'JOB_SOURCE_CODE', @@ -144,7 +146,7 @@ export const getNavItems = ({ }, { title: 'Workflow Editor', - href: `${URLS.AUTOMATION_AND_ENABLEMENT_JOB}/${appId}/edit/workflow`, + href: `${ROUTER_URLS.JOBS}/${appId}/edit/workflow`, stage: STAGE_NAME.WORKFLOW, isLocked: !_isUnlocked.workflowEditor, supportDocumentURL: 'JOB_WORKFLOW_EDITOR', @@ -186,7 +188,7 @@ export const getNavItems = ({ }, { title: 'Environment Override', - href: `${URLS.AUTOMATION_AND_ENABLEMENT_JOB}/${appId}/edit/env-override`, + href: `${ROUTER_URLS.JOBS}/${appId}/edit/env-override`, stage: STAGE_NAME.ENV_OVERRIDE, isLocked: !_isUnlocked.envOverride, }, diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/AppComposeRouter.tsx b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/AppComposeRouter.tsx index cd42881113..0b02ac9bf5 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/AppComposeRouter.tsx +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/AppComposeRouter.tsx @@ -14,20 +14,19 @@ * limitations under the License. */ -import React, { lazy, Suspense } from 'react' -import { generatePath, Redirect, Route, Switch, useHistory, useLocation, useRouteMatch } from 'react-router-dom' +import React, { type JSX, lazy, Suspense } from 'react' +import { generatePath, Navigate, Route, Routes, useLocation, useNavigate, useParams } from 'react-router-dom' import { ApprovalConfigDataKindType, BASE_CONFIGURATION_ENV_ID, Button, CMSecretComponentType, - EnvResourceType, getIsApprovalPolicyConfigured, Progressing, } from '@devtron-labs/devtron-fe-common-lib' -import { ReactComponent as Next } from '@Icons/ic-arrow-forward.svg' +import Next from '@Icons/ic-arrow-forward.svg?react' import { ErrorBoundary, useAppContext } from '@Components/common' import ExternalLinks from '@Components/externalLinks/ExternalLinks' import { DEPLOYMENT_CONFIGURATION_RESOURCE_TYPE_ROUTE, URLS } from '@Config/index' @@ -35,7 +34,7 @@ import { ConfigMapSecretWrapper } from '@Pages/Shared/ConfigMapSecret/ConfigMapS import { NextButtonProps, STAGE_NAME } from '../AppConfig.types' import { useAppConfigurationContext } from '../AppConfiguration.provider' -import { DeploymentConfigCompare } from './DeploymentConfigCompare' +import { DeploymentConfigCompareWrapper } from './DeploymentConfigCompare' import '../appConfig.scss' @@ -47,7 +46,7 @@ const EnvironmentOverride = lazy(() => import('@Pages/Shared/EnvironmentOverride const UserGitRepoConfiguration = lazy(() => import('@Components/gitOps/UserGitRepConfiguration')) const NextButton: React.FC = ({ isCiPipeline, navItems, currentStageName, isDisabled }) => { - const history = useHistory() + const navigate = useNavigate() const index = navItems.findIndex((item) => item.stage === currentStageName) const nextUrl = navItems[index + 1].href if (!isCiPipeline) { @@ -56,7 +55,7 @@ const NextButton: React.FC = ({ isCiPipeline, navItems, current