Compare commits

...

8 Commits

Author SHA1 Message Date
Pablo F.G 691773a941 docs(ui): move ESLint changelog entry to UNRELEASED block
- Relocate ESLint #11352 entry out of released v5.29.0 block
- Add 1.30.0 UNRELEASED block after merging master

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:28:25 +02:00
Pablo F.G ccc116cb64 Merge remote-tracking branch 'origin/master' into feature/eslint-typescript-flat 2026-06-02 09:21:08 +02:00
Prowler Bot c2cef99b33 chore(release): Bump versions to v5.30.0 (#11418)
Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com>
2026-06-01 18:37:51 +02:00
Pablo F.G d2cc939f81 Merge remote-tracking branch 'origin/master' into feature/eslint-typescript-flat
# Conflicts:
#	ui/CHANGELOG.md
#	ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx
#	ui/components/scans/table/scans/column-get-scans.tsx
#	ui/pnpm-lock.yaml
2026-05-29 11:16:16 +02:00
Pablo F.G ba95b1f0ad docs(ui): set PR number in changelog entry 2026-05-27 14:27:27 +02:00
Pablo F.G c9a2685a5f chore(ui): apply eslint 2026-05-27 14:27:00 +02:00
Pablo F.G acd1a6d1cf style(ui): apply ESLint --fix for import-x/order across the workspace
Re-sort imports and consolidate duplicate React imports to satisfy the
new import-x/order rule from eslint-plugin-import-x's recommended +
typescript configs. The rule enforces alphabetical sort within groups
(builtin / external / internal / parent / sibling / index) and a blank
line between groups, replacing the prior simple-import-sort layout.

Pure auto-fix output from `pnpm run lint:fix` — no runtime changes.
2026-05-27 14:26:59 +02:00
Pablo F.G a43d65f8be chore(ui): migrate ESLint to flat eslint.config.ts with typescript-eslint and import-x
Convert ui/eslint.config.mjs to ui/eslint.config.ts and switch to the
typescript-eslint meta-package via tseslint.config(), replacing the
separate @typescript-eslint/eslint-plugin and @typescript-eslint/parser
entries. Enable projectService with tsconfigRootDir: import.meta.dirname
so the parser uses the canonical TS project graph; one duplicate test
file (events-timeline.test.tsx) is opted into allowDefaultProject
because TypeScript skips it in favor of its .ts sibling.

Replace eslint-plugin-prettier (which proxies Prettier through ESLint
rules) with eslint-config-prettier/flat so Prettier only disables
conflicting rules. Replace eslint-plugin-simple-import-sort and
eslint-plugin-unused-imports with eslint-plugin-import-x using the
recommended + typescript flat configs, wire up the import-x
resolver-next chain via eslint-import-resolver-typescript +
createNodeResolver, and add jiti so ESLint can load the .ts config.

The migration is intentionally behavior-preserving: import-x/export is
disabled to keep parity with the legacy config (pre-existing duplicate
exports stay tracked for the canonical Base layer PR), eslint.config.ts
is excluded from tsc and ignored by ESLint, and lint:check stays under
the --max-warnings 40 budget.
2026-05-27 14:26:59 +02:00
56 changed files with 696 additions and 385 deletions
+1 -1
View File
@@ -145,7 +145,7 @@ SENTRY_RELEASE=local
NEXT_PUBLIC_SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT}
#### Prowler release version ####
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.29.0
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.30.0
# Social login credentials
SOCIAL_GOOGLE_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/google"
+1 -1
View File
@@ -68,7 +68,7 @@ name = "prowler-api"
package-mode = false
# Needed for the SDK compatibility
requires-python = ">=3.11,<3.13"
version = "1.30.0"
version = "1.31.0"
[tool.uv]
# Transitive pins matching master to avoid silent drift; bump deliberately.
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: Prowler API
version: 1.30.0
version: 1.31.0
description: |-
Prowler API specification.
Generated
+1 -1
View File
@@ -4494,7 +4494,7 @@ dependencies = [
[[package]]
name = "prowler-api"
version = "1.30.0"
version = "1.31.0"
source = { virtual = "." }
dependencies = [
{ name = "cartography" },
@@ -118,8 +118,8 @@ To update the environment file:
Edit the `.env` file and change version values:
```env
PROWLER_UI_VERSION="5.28.0"
PROWLER_API_VERSION="5.28.0"
PROWLER_UI_VERSION="5.29.0"
PROWLER_API_VERSION="5.29.0"
```
<Note>
+1 -1
View File
@@ -48,7 +48,7 @@ class _MutableTimestamp:
timestamp = _MutableTimestamp(datetime.today())
timestamp_utc = _MutableTimestamp(datetime.now(timezone.utc))
prowler_version = "5.29.0"
prowler_version = "5.30.0"
html_logo_url = "https://github.com/prowler-cloud/prowler/"
square_logo_img = "https://raw.githubusercontent.com/prowler-cloud/prowler/dc7d2d5aeb92fdf12e8604f42ef6472cd3e8e889/docs/img/prowler-logo-black.png"
aws_logo = "https://user-images.githubusercontent.com/38561120/235953920-3e3fba08-0795-41dc-b480-9bea57db9f2e.png"
+1 -1
View File
@@ -123,7 +123,7 @@ maintainers = [{name = "Prowler Engineering", email = "engineering@prowler.com"}
name = "prowler"
readme = "README.md"
requires-python = ">=3.10,<3.13"
version = "5.29.0"
version = "5.30.0"
[project.scripts]
prowler = "prowler.__main__:prowler"
+8
View File
@@ -2,6 +2,14 @@
All notable changes to the **Prowler UI** are documented in this file.
## [1.30.0] (Prowler UNRELEASED)
### 🔄 Changed
- ESLint: typed flat config with `typescript-eslint` (type-aware via `projectService`) and `eslint-plugin-import-x`, replacing `eslint-plugin-prettier`, `eslint-plugin-simple-import-sort`, and `eslint-plugin-unused-imports` [(#11352)](https://github.com/prowler-cloud/prowler/pull/11352)
---
## [1.29.0] (Prowler v5.29.0)
### 🚀 Added
@@ -1,5 +1,5 @@
import { LucideIcon } from "lucide-react";
import {
LucideIcon,
Activity,
BarChart3,
Bot,
+5 -2
View File
@@ -1,6 +1,9 @@
import { AuthForm } from "@/components/auth/oss";
import { getAuthUrl, isGithubOAuthEnabled } from "@/lib/helper";
import { isGoogleOAuthEnabled } from "@/lib/helper";
import {
getAuthUrl,
isGithubOAuthEnabled,
isGoogleOAuthEnabled,
} from "@/lib/helper";
import { SearchParamsProps } from "@/types";
const SignUp = async ({
@@ -5,6 +5,7 @@ import {
import { pickFilterParams } from "../_lib/filter-params";
import { SSRComponentProps } from "../_types";
import { AttackSurface } from "./_components/attack-surface";
export const AttackSurfaceSSR = async ({ searchParams }: SSRComponentProps) => {
@@ -8,6 +8,7 @@ import { getAllProviders } from "@/actions/providers";
import { SearchParamsProps } from "@/types";
import { pickFilterParams } from "../../_lib/filter-params";
import { RiskPlotClient } from "./risk-plot-client";
export async function RiskPlotSSR({
@@ -7,6 +7,7 @@ import {
import { SearchParamsProps } from "@/types";
import { pickFilterParams } from "../../_lib/filter-params";
import { RiskRadarViewClient } from "./risk-radar-view-client";
export async function RiskRadarViewSSR({
@@ -5,6 +5,7 @@ import {
import { pickFilterParams } from "../_lib/filter-params";
import { SSRComponentProps } from "../_types";
import { ResourcesInventory } from "./_components/resources-inventory";
export const ResourcesInventorySSR = async ({
@@ -2,6 +2,7 @@ import { getFindingsBySeverity } from "@/actions/overview";
import { pickFilterParams } from "../_lib/filter-params";
import { SSRComponentProps } from "../_types";
import { RiskSeverityChart } from "./_components/risk-severity-chart";
export const RiskSeverityChartSSR = async ({
@@ -14,6 +14,7 @@ import {
} from "@/types/severities";
import { DEFAULT_TIME_RANGE } from "../_constants/time-range.constants";
import { type TimeRange, TimeRangeSelector } from "./time-range-selector";
interface FindingSeverityOverTimeProps {
@@ -3,6 +3,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/shadcn";
import { pickFilterParams } from "../_lib/filter-params";
import { SSRComponentProps } from "../_types";
import { FindingSeverityOverTime } from "./_components/finding-severity-over-time";
import { FindingSeverityOverTimeSkeleton } from "./_components/finding-severity-over-time.skeleton";
import { DEFAULT_TIME_RANGE } from "./_constants/time-range.constants";
@@ -2,6 +2,7 @@ import { getThreatScore } from "@/actions/overview";
import { pickFilterParams } from "../_lib/filter-params";
import { SSRComponentProps } from "../_types";
import { ThreatScore } from "./_components/threat-score";
export const ThreatScoreSSR = async ({ searchParams }: SSRComponentProps) => {
@@ -5,6 +5,7 @@ import {
import { pickFilterParams } from "../_lib/filter-params";
import { SSRComponentProps } from "../_types";
import { ComplianceWatchlist } from "./_components/compliance-watchlist";
export const ComplianceWatchlistSSR = async ({
@@ -2,6 +2,7 @@ import { getServicesOverview, ServiceOverview } from "@/actions/overview";
import { pickFilterParams } from "../_lib/filter-params";
import { SSRComponentProps } from "../_types";
import { ServiceWatchlist } from "./_components/service-watchlist";
export const ServiceWatchlistSSR = async ({
@@ -25,6 +25,7 @@ vi.mock("@/lib/server-actions-helper", () => ({
}));
import { ALERT_AGGREGATE_OPS, ALERT_TRIGGER_KINDS } from "../_types";
import {
createAlert,
deleteAlert,
@@ -19,8 +19,7 @@ import { Button } from "@/components/shadcn";
import { Modal } from "@/components/shadcn/modal";
import { useToast } from "@/components/ui";
import { DOCS_URLS } from "@/lib/external-urls";
import type { MetaDataProps } from "@/types";
import type { ScanEntity } from "@/types";
import type { MetaDataProps, ScanEntity } from "@/types";
import type { ProviderProps } from "@/types/providers";
import { toAlertPayload } from "../_lib/alert-adapter";
@@ -28,6 +27,7 @@ import type {
AlertFormSubmitResult,
AlertFormValues,
} from "../_types/alert-form";
import { AlertFormModal } from "./alert-form-modal";
import { AlertsEmptyState } from "./alerts-empty-state";
import { AlertsTable } from "./alerts-table";
@@ -34,6 +34,7 @@ import {
resolveHiddenFindingIds,
} from "../../_lib";
import { isFindingNode, layoutWithDagre } from "../../_lib/layout";
import { FindingNode } from "./nodes/finding-node";
import { InternetNode } from "./nodes/internet-node";
import { ResourceNode } from "./nodes/resource-node";
@@ -12,6 +12,7 @@ import type { GraphNode } from "@/types/attack-paths";
import { resolveNodeColors, resolveNodeVisual } from "../../../_lib";
import { FINDING_NODE_DIMENSIONS } from "../../../_lib/node-dimensions";
import { getNodeLabelDisplay } from "../../../_lib/node-label-lines";
import { HiddenHandles } from "./hidden-handles";
interface FindingNodeData {
@@ -5,6 +5,7 @@ import { type NodeProps } from "@xyflow/react";
import type { GraphNode } from "@/types/attack-paths";
import { resolveNodeColors } from "../../../_lib";
import { HiddenHandles } from "./hidden-handles";
interface InternetNodeData {
@@ -12,6 +12,7 @@ import type { GraphNode } from "@/types/attack-paths";
import { resolveNodeColors, resolveNodeVisual } from "../../../_lib";
import { RESOURCE_NODE_DIMENSIONS } from "../../../_lib/node-dimensions";
import { getNodeLabelDisplay } from "../../../_lib/node-label-lines";
import { HiddenHandles } from "./hidden-handles";
interface ResourceNodeData {
@@ -1,5 +1,4 @@
import React from "react";
import { Suspense } from "react";
import React, { Suspense } from "react";
import { getRoles } from "@/actions/roles";
import { SkeletonInvitationInfo } from "@/components/invitations/workflow";
+1 -2
View File
@@ -6,8 +6,7 @@ import { useIsSSR } from "@react-aria/ssr";
import { VisuallyHidden } from "@react-aria/visually-hidden";
import clsx from "clsx";
import { useTheme } from "next-themes";
import { FC } from "react";
import React from "react";
import React, { FC } from "react";
import {
Tooltip,
@@ -18,6 +18,7 @@ import {
import { ScanEntity } from "@/types/scans";
import { getComplianceIcon } from "../icons";
import { ComplianceDownloadContainer } from "./compliance-download-container";
interface ComplianceCardProps {
@@ -3,6 +3,7 @@
import { FilterOption } from "@/types";
import { DataTableFilterCustom } from "../ui/table";
import { CustomSearchInput } from "./custom-search-input";
export interface FilterControlsProps {
@@ -16,8 +16,9 @@ import {
TableHead,
TableHeader,
TableRow,
SeverityBadge,
StatusFindingBadge,
} from "@/components/ui/table";
import { SeverityBadge, StatusFindingBadge } from "@/components/ui/table";
import { useFindingGroupResourceState } from "@/hooks/use-finding-group-resource-state";
import { cn, hasHistoricalFindingFilter } from "@/lib";
import {
@@ -28,6 +29,7 @@ import {
import { FindingGroupRow } from "@/types";
import { FloatingMuteButton } from "../floating-mute-button";
import { getColumnFindingResources } from "./column-finding-resources";
import { FindingsSelectionContext } from "./findings-selection-context";
import { ImpactedResourcesCell } from "./impacted-resources-cell";
@@ -11,6 +11,7 @@ import { canDrillDownFindingGroup } from "@/lib/findings-groups";
import { FindingGroupRow, MetaDataProps } from "@/types";
import { FloatingMuteButton } from "../floating-mute-button";
import { getColumnFindingGroups } from "./column-finding-groups";
import { canMuteFindingGroup } from "./finding-group-selection";
import { FindingsSelectionContext } from "./findings-selection-context";
@@ -67,8 +67,7 @@ import {
type FindingStatus,
StatusFindingBadge,
} from "@/components/ui/table/status-finding-badge";
import { getFailingForLabel } from "@/lib/date-utils";
import { formatDuration } from "@/lib/date-utils";
import { getFailingForLabel, formatDuration } from "@/lib/date-utils";
import { getRegionFlag } from "@/lib/region-flags";
import { getRecommendationLinkLabel } from "@/lib/vulnerability-references";
import type { ComplianceOverviewData } from "@/types/compliance";
@@ -77,6 +76,7 @@ import type { FindingResourceRow } from "@/types/findings-table";
import { Muted } from "../../muted";
import { DeltaIndicator } from "../delta-indicator";
import { DeltaValues, NotificationIndicator } from "../notification-indicator";
import { ResourceDetailSkeleton } from "./resource-detail-skeleton";
import type { CheckMeta } from "./use-resource-detail-drawer";
@@ -4,11 +4,9 @@ import { SettingsIcon } from "lucide-react";
import Link from "next/link";
import { JiraIcon } from "@/components/icons/services/IconServices";
import { Button } from "@/components/shadcn";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Card, CardContent, CardHeader } from "../../shadcn";
export const JiraIntegrationCard = () => {
return (
<Card variant="base" padding="lg">
@@ -15,7 +15,7 @@ import {
IntegrationCardHeader,
IntegrationSkeleton,
} from "@/components/integrations/shared";
import { Button } from "@/components/shadcn";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { Modal } from "@/components/shadcn/modal";
import { useToast } from "@/components/ui";
import { DataTablePagination } from "@/components/ui/table/data-table-pagination";
@@ -23,7 +23,6 @@ import { triggerTestConnectionWithDelay } from "@/lib/integrations/test-connecti
import { MetaDataProps } from "@/types";
import { IntegrationProps } from "@/types/integrations";
import { Card, CardContent, CardHeader } from "../../shadcn";
import { JiraIntegrationForm } from "./jira-integration-form";
interface JiraIntegrationsManagerProps {
@@ -4,11 +4,9 @@ import { SettingsIcon } from "lucide-react";
import Link from "next/link";
import { AmazonS3Icon } from "@/components/icons/services/IconServices";
import { Button } from "@/components/shadcn";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Card, CardContent, CardHeader } from "../../shadcn";
export const S3IntegrationCard = () => {
return (
<Card variant="base" padding="lg">
@@ -15,7 +15,7 @@ import {
IntegrationCardHeader,
IntegrationSkeleton,
} from "@/components/integrations/shared";
import { Button } from "@/components/shadcn";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { Modal } from "@/components/shadcn/modal";
import { useToast } from "@/components/ui";
import { DataTablePagination } from "@/components/ui/table/data-table-pagination";
@@ -24,7 +24,6 @@ import { MetaDataProps } from "@/types";
import { IntegrationProps } from "@/types/integrations";
import { ProviderProps } from "@/types/providers";
import { Card, CardContent, CardHeader } from "../../shadcn";
import { S3IntegrationForm } from "./s3-integration-form";
interface S3IntegrationsManagerProps {
@@ -4,12 +4,11 @@ import { CheckIcon, Trash2Icon } from "lucide-react";
import { useState } from "react";
import { deleteSamlConfig } from "@/actions/integrations";
import { Button } from "@/components/shadcn";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { Modal } from "@/components/shadcn/modal";
import { useToast } from "@/components/ui";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Card, CardContent, CardHeader } from "../../shadcn";
import { SamlConfigForm } from "./saml-config-form";
export const SamlIntegrationCard = ({ samlConfig }: { samlConfig?: any }) => {
@@ -4,11 +4,9 @@ import { SettingsIcon } from "lucide-react";
import Link from "next/link";
import { AWSSecurityHubIcon } from "@/components/icons/services/IconServices";
import { Button } from "@/components/shadcn";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Card, CardContent, CardHeader } from "../../shadcn";
export const SecurityHubIntegrationCard = () => {
return (
<Card variant="base" padding="lg">
@@ -15,7 +15,13 @@ import {
IntegrationCardHeader,
IntegrationSkeleton,
} from "@/components/integrations/shared";
import { Badge, Button } from "@/components/shadcn";
import {
Badge,
Button,
Card,
CardContent,
CardHeader,
} from "@/components/shadcn";
import { Modal } from "@/components/shadcn/modal";
import { useToast } from "@/components/ui";
import { DataTablePagination } from "@/components/ui/table/data-table-pagination";
@@ -24,7 +30,6 @@ import { MetaDataProps } from "@/types";
import { IntegrationProps } from "@/types/integrations";
import { ProviderProps } from "@/types/providers";
import { Card, CardContent, CardHeader } from "../../shadcn";
import { SecurityHubIntegrationForm } from "./security-hub-integration-form";
interface SecurityHubIntegrationsManagerProps {
@@ -3,11 +3,9 @@
import { ExternalLinkIcon, LucideIcon } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/shadcn";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Card, CardContent, CardHeader } from "../../shadcn";
interface LinkCardProps {
icon: LucideIcon;
title: string;
@@ -26,6 +26,7 @@ import {
pollConnectionTask,
runWithConcurrencyLimit,
} from "../org-account-selection.utils";
import { extractErrorMessage } from "./error-utils";
interface SelectionState {
@@ -27,6 +27,7 @@ import {
} from "@/types/providers-table";
import { LinkToScans } from "../link-to-scans";
import { DataTableRowActions } from "./data-table-row-actions";
interface GroupNameChipsProps {
@@ -10,6 +10,7 @@ import {
} from "@/types/provider-wizard";
import type { ProviderWizardInitialData } from "../types";
import { useProviderWizardController } from "./use-provider-wizard-controller";
const { refreshMock } = vi.hoisted(() => ({
@@ -22,6 +22,7 @@ import {
import { SelectViaGitHub } from "../../workflow/forms/select-credentials-type/github";
import { SelectViaM365 } from "../../workflow/forms/select-credentials-type/m365";
import { UpdateViaServiceAccountForm } from "../../workflow/forms/update-via-service-account-key-form";
import {
WIZARD_FOOTER_ACTION_TYPE,
WizardFooterConfig,
@@ -11,6 +11,7 @@ import {
TestConnectionForm,
TestConnectionProviderData,
} from "../../workflow/forms/test-connection-form";
import {
WIZARD_FOOTER_ACTION_TYPE,
WizardFooterConfig,
@@ -37,6 +37,7 @@ import {
} from "@/types";
import { ProviderTitleDocs } from "../provider-title-docs";
import {
AlibabaCloudRoleCredentialsForm,
AlibabaCloudStaticCredentialsForm,
@@ -14,8 +14,7 @@ import { CheckIcon } from "@/components/icons";
import { Button } from "@/components/shadcn";
import { Form } from "@/components/ui/form";
import { testProviderConnection } from "@/lib/provider-helpers";
import { ProviderType } from "@/types";
import { testConnectionFormSchema } from "@/types";
import { ProviderType, testConnectionFormSchema } from "@/types";
import { ProviderConnectionInfo } from "./provider-connection-info";
@@ -1,7 +1,9 @@
"use client";
import { getProviderName } from "@/components/ui/entities/get-provider-logo";
import { getProviderLogo } from "@/components/ui/entities/get-provider-logo";
import {
getProviderName,
getProviderLogo,
} from "@/components/ui/entities/get-provider-logo";
import { ProviderType } from "@/types";
export const ProviderTitleDocs = ({
+2 -2
View File
@@ -3,13 +3,13 @@
import clsx from "clsx";
import Link from "next/link";
import { ProwlerShort } from "@/components/icons";
import { ProwlerExtended } from "@/components/icons";
import { ProwlerShort, ProwlerExtended } from "@/components/icons";
import { useSidebar } from "@/hooks/use-sidebar";
import { useStore } from "@/hooks/use-store";
import { cn } from "@/lib/utils";
import { Button } from "../button/button";
import { Menu } from "./menu";
export function Sidebar() {
+31 -39
View File
@@ -751,22 +751,6 @@
"strategy": "installed",
"generatedAt": "2025-10-30T10:22:21.335Z"
},
{
"section": "devDependencies",
"name": "@typescript-eslint/eslint-plugin",
"from": "7.18.0",
"to": "8.53.0",
"strategy": "installed",
"generatedAt": "2026-01-19T13:54:24.770Z"
},
{
"section": "devDependencies",
"name": "@typescript-eslint/parser",
"from": "7.18.0",
"to": "8.53.0",
"strategy": "installed",
"generatedAt": "2026-01-19T13:54:24.770Z"
},
{
"section": "devDependencies",
"name": "@vitejs/plugin-react",
@@ -841,17 +825,25 @@
},
{
"section": "devDependencies",
"name": "eslint-plugin-jsx-a11y",
"from": "6.10.2",
"to": "6.10.2",
"name": "eslint-import-resolver-typescript",
"from": "4.4.4",
"to": "4.4.4",
"strategy": "installed",
"generatedAt": "2025-10-22T12:36:37.962Z"
"generatedAt": "2026-05-13T15:04:07.559Z"
},
{
"section": "devDependencies",
"name": "eslint-plugin-prettier",
"from": "5.5.1",
"to": "5.5.1",
"name": "eslint-plugin-import-x",
"from": "4.16.2",
"to": "4.16.2",
"strategy": "installed",
"generatedAt": "2026-05-13T15:02:04.867Z"
},
{
"section": "devDependencies",
"name": "eslint-plugin-jsx-a11y",
"from": "6.10.2",
"to": "6.10.2",
"strategy": "installed",
"generatedAt": "2025-10-22T12:36:37.962Z"
},
@@ -879,22 +871,6 @@
"strategy": "installed",
"generatedAt": "2025-10-22T12:36:37.962Z"
},
{
"section": "devDependencies",
"name": "eslint-plugin-simple-import-sort",
"from": "12.1.1",
"to": "12.1.1",
"strategy": "installed",
"generatedAt": "2025-10-22T12:36:37.962Z"
},
{
"section": "devDependencies",
"name": "eslint-plugin-unused-imports",
"from": "3.2.0",
"to": "4.3.0",
"strategy": "installed",
"generatedAt": "2026-01-19T13:54:24.770Z"
},
{
"section": "devDependencies",
"name": "globals",
@@ -903,6 +879,14 @@
"strategy": "installed",
"generatedAt": "2026-01-19T13:54:24.770Z"
},
{
"section": "devDependencies",
"name": "jiti",
"from": "2.7.0",
"to": "2.7.0",
"strategy": "installed",
"generatedAt": "2026-05-13T15:02:04.867Z"
},
{
"section": "devDependencies",
"name": "jsdom",
@@ -975,6 +959,14 @@
"strategy": "installed",
"generatedAt": "2025-10-22T12:36:37.962Z"
},
{
"section": "devDependencies",
"name": "typescript-eslint",
"from": "8.59.3",
"to": "8.59.3",
"strategy": "installed",
"generatedAt": "2026-05-13T15:02:04.867Z"
},
{
"section": "devDependencies",
"name": "vitest",
+52 -46
View File
@@ -1,22 +1,15 @@
import { dirname } from "path";
import { fileURLToPath } from "url";
import tsPlugin from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
import prettierPlugin from "eslint-plugin-prettier";
import simpleImportSort from "eslint-plugin-simple-import-sort";
import jsxA11y from "eslint-plugin-jsx-a11y";
import security from "eslint-plugin-security";
import unusedImports from "eslint-plugin-unused-imports";
import nextPlugin from "@next/eslint-plugin-next";
import prettierConfig from "eslint-config-prettier/flat";
import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript";
import importX, { createNodeResolver } from "eslint-plugin-import-x";
import jsxA11y from "eslint-plugin-jsx-a11y";
import reactPlugin from "eslint-plugin-react";
import reactHooksPlugin from "eslint-plugin-react-hooks";
import security from "eslint-plugin-security";
import globals from "globals";
import tseslint from "typescript-eslint";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export default [
// Global ignores (replaces .eslintignore)
export default tseslint.config(
{
ignores: [
".now/**",
@@ -29,6 +22,7 @@ export default [
"scripts/**",
"*.config.js",
"*.config.mjs",
"*.config.ts",
".DS_Store",
"node_modules/**",
"coverage/**",
@@ -37,27 +31,33 @@ export default [
"next-env.d.ts",
],
},
// TypeScript and React files configuration
importX.flatConfigs.recommended,
importX.flatConfigs.typescript,
{
files: ["**/*.{ts,tsx,js,jsx}"],
linterOptions: {
reportUnusedDisableDirectives: "error",
},
plugins: {
"@typescript-eslint": tsPlugin,
"@typescript-eslint": tseslint.plugin,
"@next/next": nextPlugin,
react: reactPlugin,
"react-hooks": reactHooksPlugin,
prettier: prettierPlugin,
"simple-import-sort": simpleImportSort,
"jsx-a11y": jsxA11y,
security: security,
"unused-imports": unusedImports,
security,
},
languageOptions: {
parser: tsParser,
parser: tseslint.parser,
parserOptions: {
projectService: {
allowDefaultProject: [
// Duplicate of events-timeline.test.ts in the same folder;
// TypeScript only picks the .ts sibling, so this .tsx file is
// outside the project graph. Tracked for follow-up cleanup.
"components/shared/events-timeline/events-timeline.test.tsx",
],
},
tsconfigRootDir: import.meta.dirname,
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
@@ -75,14 +75,19 @@ export default [
react: {
version: "detect",
},
"import-x/resolver-next": [
createTypeScriptImportResolver({
alwaysTryTypes: true,
project: "./tsconfig.json",
}),
createNodeResolver(),
],
},
rules: {
// Console rules - allow console.error but no console.log
"no-console": ["error", { allow: ["error"] }],
eqeqeq: 2,
quotes: ["error", "double", "avoid-escape"],
eqeqeq: "error",
quotes: ["error", "double", { avoidEscape: true }],
// TypeScript rules
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": [
"error",
@@ -93,28 +98,30 @@ export default [
},
],
// Security
"security/detect-object-injection": "off",
// Prettier integration
"prettier/prettier": [
"error",
{
endOfLine: "auto",
tabWidth: 2,
useTabs: false,
},
],
"eol-last": ["error", "always"],
// Import sorting
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"import-x/order": [
"error",
{
groups: [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index",
],
"newlines-between": "always",
alphabetize: { order: "asc", caseInsensitive: true },
},
],
// Pre-existing duplicate exports and re-export shape mismatches are
// tracked separately; the migration keeps behavior parity with the
// legacy config until the rule is enforced in the canonical Base layer.
"import-x/export": "off",
// Unused imports
"unused-imports/no-unused-imports": "error",
// Accessibility
"jsx-a11y/anchor-is-valid": [
"error",
{
@@ -125,14 +132,13 @@ export default [
],
"jsx-a11y/alt-text": "error",
// React Hooks
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
// Next.js specific rules
"@next/next/no-html-link-for-pages": "error",
"@next/next/no-img-element": "warn",
"@next/next/no-sync-scripts": "error",
},
},
];
prettierConfig,
);
+4 -5
View File
@@ -130,8 +130,6 @@
"@types/react-dom": "19.2.3",
"@types/topojson-client": "3.1.5",
"@types/topojson-specification": "1.0.5",
"@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.53.0",
"@vitejs/plugin-react": "5.1.2",
"@vitest/browser": "4.0.18",
"@vitest/browser-playwright": "4.0.18",
@@ -141,14 +139,14 @@
"dotenv-expand": "12.0.3",
"eslint": "9.39.2",
"eslint-config-prettier": "10.1.5",
"eslint-import-resolver-typescript": "4.4.4",
"eslint-plugin-import-x": "4.16.2",
"eslint-plugin-jsx-a11y": "6.10.2",
"eslint-plugin-prettier": "5.5.1",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-security": "3.0.1",
"eslint-plugin-simple-import-sort": "12.1.1",
"eslint-plugin-unused-imports": "4.3.0",
"globals": "17.0.0",
"jiti": "2.7.0",
"jsdom": "27.4.0",
"knip": "6.3.1",
"msw": "2.13.4",
@@ -158,6 +156,7 @@
"prettier-plugin-tailwindcss": "0.6.14",
"tailwindcss": "4.1.18",
"typescript": "5.5.4",
"typescript-eslint": "8.59.3",
"vitest": "4.0.18",
"vitest-browser-react": "2.0.4"
},
+531 -247
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -24,7 +24,7 @@
"strict": true,
"target": "es5"
},
"exclude": ["node_modules", "vitest.config.ts"],
"exclude": ["node_modules", "vitest.config.ts", "eslint.config.ts"],
"include": [
"next-env.d.ts",
"**/*.ts",
Generated
+1 -1
View File
@@ -3241,7 +3241,7 @@ wheels = [
[[package]]
name = "prowler"
version = "5.29.0"
version = "5.30.0"
source = { editable = "." }
dependencies = [
{ name = "alibabacloud-actiontrail20200706" },