diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..49a205275 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,109 @@ +# Copilot Instructions + +Digma UI is a React-based frontend for the Digma continuous feedback platform, designed to help developers analyze and improve code quality and runtime behavior. The project is a monorepo for multiple React applications and provides the distributions for different platforms: Web and IDEs (JetBrains, Visual Studio and VS Code) + +Tech stack: TypeScript, React, React Router, Tanstack Table, React Hook Form, Recharts, styled-components, RTK Query, zustand (deprecated), axios, Storybook, Jest, Webpack, ESLint. + +## Project Structure + +- **.github/** + GitHub-specific files such as workflows + +- **scripts/** + Utility scripts for development, build, and CI/CD automation. + +- **.husky/** + Git hooks managed by Husky for enforcing code quality and workflow automation. + +- **.storybook/** + Storybook configuration files for UI component development and documentation. + +- **.vscode/** + Visual Studio Code workspace settings and recommended extensions. + +- **src/** + Main source code for the Digma UI applications, including all React components, features, hooks, utilities, and configuration. + +- **src/components/** + Shared, reusable React components used across features and apps. + +- **src/api/** + Contains custom message API-related code, including service definitions, types, and API clients for communicating with backend services. + +- **src/containers/** + Entry points for React applications. + +- **src/history/** + Custom container for application history state management. + +- **src/hooks/** + Custom React hooks for shared logic across the applications. + +- **src/logging/** + Logger for application events and errors. + +- **src/redux/** + Redux store configuration, slices, and RTK Query services. + +- **src/store/** + Zustand stores and state management logic (deprecated). + +- **src/stories/** + Storybook stories for UI components. + +- **src/typeGuards/** + TypeScript type guard functions for runtime type checking. + +- **src/utils/** + General utility functions and helpers used throughout the project. + +- **public/** + Static assets served by the app (e.g., images, fonts). + +- **apps.ts** + Entry points and configuration for each distributive. + +## Code Style + +### JavaScript/TypeScript + +- Use Boolean() constructor instead of !! operator for boolean casting. +- Follow the ESLint rules from `eslint.config.mjs`. + +### TypeScript + +- Use `import type` for all type-only imports. +- Define all type definitions and props in a `types.ts` file. + +### React + +- Each React component should reside in its own folder under the relevant feature/component directory. +- The main component file must be named `[Component]/index.tsx`. +- Do not import React at the top of files for JSX usage (React 18+). +- Do not import the React namespace unless it is actually needed (e.g., for types or APIs not available via direct import). +- Use implicit return for functional components when possible. +- Destructure component props in the function signature. + +### Styles + +- Import styles as: `import * as s from "./styles"`. +- Use a `styles.ts` file for styled-components definitions. +- The top-level styled component should be named `Container`. +- Do not use inline styles; use props with semantic names instead. +- Do not use the `font-family` CSS rule for `SF Pro Text` (treat as the default OS font). Only specify `font-family` if a non-default font is required. +- Use semantic color tokens from the theme (e.g., `theme.colors.v3.surface.primary`) instead of hardcoded color values or direct palette imports. +- Use typography mixins from `typographies.ts` wherever Figma specifies a typography variable. Do not hardcode font-size, font-weight, or line-height if a corresponding typography token exists. +- Avoid hardcoded colors, font sizes, and font weights if a semantic or design token exists. +- All styled-components should use theme values via the `theme` prop for colors and typography, ensuring support for both dark and light themes. +- Do not use inline types for styled-components. Always create and import interfaces for props used in styled-components from the component's `types.ts` file. +- Do not use className prop without the need +- Follow Stylelint rules for all CSS/styled-components code from `stylelint.config.js`. + +### Images + +- Use standard `` tags for images, styled via styled-components if needed. + +### Storybook & Tests + +- Create a Storybook file named `[Component].stories.tsx` for stories. +- Create a test file named `[Component].test.tsx` for tests. diff --git a/.github/prompts/create-app.prompt.md b/.github/prompts/create-app.prompt.md new file mode 100644 index 000000000..49d42b303 --- /dev/null +++ b/.github/prompts/create-app.prompt.md @@ -0,0 +1,8 @@ +--- +mode: "agent" +tools: [] +--- + +Add the infrastructure for a new app called "" for the "" platform. +Take an existing app for the same platform as an example, but do not add any business logic yet—just the necessary boilerplate and wiring. +Update all relevant files (such as apps.ts, containers, and routing) to register the new app and ensure it builds and runs like the other apps for this platform. diff --git a/README.md b/README.md index b429b796c..5cdf2e25f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Digma UI +Digma UI is a React-based frontend for the Digma continuous feedback platform. The project is a monorepo for multiple React applications and provides the distributions for different platforms: Web and IDEs (JetBrains, Visual Studio and VS Code) + Install dependencies: ```shell @@ -57,7 +59,7 @@ To set environment variables use .env file ## Jaeger UI -The Digma UI distributive includes a [Digma fork of Jaeger UI](https://github.com/digma-ai/jaeger-ui). You can find the linked version in the [./dependencies.json](./dependencies.json) file. +The Digma UI distribution includes a [Digma fork of Jaeger UI](https://github.com/digma-ai/jaeger-ui). You can find the linked version in the [./dependencies.json](./dependencies.json) file. To use a custom build of Jaeger UI during development set `JAEGER_UI_PATH` environment variable. diff --git a/scripts/get-jaeger-ui.mts b/scripts/get-jaeger-ui.mts index 6b5055710..581a0eeb6 100644 --- a/scripts/get-jaeger-ui.mts +++ b/scripts/get-jaeger-ui.mts @@ -91,13 +91,13 @@ if (process.env.JAEGER_UI_PATH) { if (!fs.existsSync(customJaegerUIPath)) { // eslint-disable-next-line no-console console.error( - `Jaeger UI distributive has not been found at ${customJaegerUIPath}` + `Jaeger UI distribution has not been found at ${customJaegerUIPath}` ); process.exit(1); } // eslint-disable-next-line no-console - console.log(`Using Jaeger UI distributive from ${customJaegerUIPath}`); + console.log(`Using Jaeger UI distribution from ${customJaegerUIPath}`); fs.copySync(customJaegerUIPath, extractPath); diff --git a/src/api/index.ts b/src/api/index.ts index b65b88710..b1604a26e 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -65,8 +65,6 @@ export const initializeDigmaMessageListener = ( break; } - window.addEventListener("message", handleDigmaMessage); - return () => { switch (platform) { case "Visual Studio": diff --git a/src/components/Admin/index.tsx b/src/components/Admin/index.tsx index 952ef6be8..946c24faf 100644 --- a/src/components/Admin/index.tsx +++ b/src/components/Admin/index.tsx @@ -32,7 +32,7 @@ export const Admin = () => { FeatureFlag.IsUserIdEnabled ); - // Clear issues report state when user changes + // Clear state when user changes useEffect(() => { if (isUserIdEnabled && userProfile) { if (currentUser?.uid !== userProfile?.uid) { diff --git a/src/components/Main/index.tsx b/src/components/Main/index.tsx index e032a44b1..65fb9efd1 100644 --- a/src/components/Main/index.tsx +++ b/src/components/Main/index.tsx @@ -41,7 +41,7 @@ const getURLToNavigateOnCodeLensClick = (scope: Scope): string | undefined => { } const codeLens = scope.context.payload.codeLens; - if (!codeLens.scopeCodeObjectId.startsWith("span:")) { + if (!codeLens.scopeCodeObjectId?.startsWith("span:")) { return; } diff --git a/src/components/common/App/index.tsx b/src/components/common/App/index.tsx index 235f4c610..93bdf6bca 100644 --- a/src/components/common/App/index.tsx +++ b/src/components/common/App/index.tsx @@ -332,7 +332,9 @@ export const App = ({ theme, children, id }: AppProps) => { }; scope = newScope; - setGlobalErrorsSearch(newScope.context.payload.codeLens.codeMethod); + if (newScope.method?.methodId) { + setGlobalErrorsSearch(newScope.method?.methodId); + } } setScope(scope); diff --git a/src/components/common/App/types.ts b/src/components/common/App/types.ts index a1582b211..8c15ac810 100644 --- a/src/components/common/App/types.ts +++ b/src/components/common/App/types.ts @@ -57,8 +57,14 @@ export interface ScopeSpan { role: ScopeSpanRole | null; } +export interface MethodScope { + methodId: string; + displayName: string | null; +} + export interface Scope { span: ScopeSpan | null; + method?: MethodScope; code: { relatedCodeDetailsList: CodeDetails[]; codeDetailsList: CodeDetails[]; @@ -77,7 +83,7 @@ export interface Scope { export interface CodeLens { id: string; codeMethod: string; - scopeCodeObjectId: string; + scopeCodeObjectId?: string; lensTitle: string; importance: number; } diff --git a/src/components/common/IssuesReport/Header/styles.ts b/src/components/common/IssuesReport/Header/styles.ts index 421a73219..f1aa0d334 100644 --- a/src/components/common/IssuesReport/Header/styles.ts +++ b/src/components/common/IssuesReport/Header/styles.ts @@ -54,7 +54,7 @@ export const Filters = styled(Row)` const StyledToggle = styled(Toggle)` align-items: center; - background-color: transparent; + background: transparent; border-radius: 8px; border-color: ${({ theme }) => theme.colors.v3.stroke.primaryLight}; `; diff --git a/src/components/common/JiraTicket/ActionableTextField/styles.ts b/src/components/common/JiraTicket/ActionableTextField/styles.ts index 8609aef53..dfddea8dd 100644 --- a/src/components/common/JiraTicket/ActionableTextField/styles.ts +++ b/src/components/common/JiraTicket/ActionableTextField/styles.ts @@ -15,7 +15,7 @@ export const TextFieldContainer = styled.div` export const RelativeTextField = styled(TextField)` position: relative; - background-color: transparent; + background: transparent; border: 1px solid ${({ theme }) => theme.colors.field.border}; & > input { diff --git a/src/components/common/NewPopover/index.tsx b/src/components/common/NewPopover/index.tsx index 924f9e790..e738ff2f2 100644 --- a/src/components/common/NewPopover/index.tsx +++ b/src/components/common/NewPopover/index.tsx @@ -99,6 +99,7 @@ export const NewPopover = ({ setMinWidth(rects.reference.width); setMaxWidth(rects.reference.width); } else { + // TODO: Check if needed const safeAvailableWidth = Math.max(availableWidth, 0); const viewportWidth = window.innerWidth; const anchorLeft = rects.reference.x; diff --git a/src/logging/Logger.ts b/src/logging/Logger.ts index cac412b9e..eafc37d68 100644 --- a/src/logging/Logger.ts +++ b/src/logging/Logger.ts @@ -20,13 +20,17 @@ export class Logger { return format(new Date(), "HH:mm:ss"); } - private getLogLevelTag(): string { - return LogLevel[this.minLogLevel]; + private getLogLevelTag(level: LogLevel): string { + return LogLevel[level]; } - private getFormattedMessage(tags: string[], message: unknown): string { + private getFormattedMessage( + level: LogLevel, + tags: string[], + message: unknown + ): string { if (this.showLogLevel) { - tags.unshift(this.getLogLevelTag()); + tags.unshift(this.getLogLevelTag(level)); } if (this.showTimeStamp) { @@ -48,7 +52,7 @@ export class Logger { message?: unknown, ...optionalParams: unknown[] ): void { - const formattedMessage = this.getFormattedMessage(tags, message); + const formattedMessage = this.getFormattedMessage(level, tags, message); if (this.minLogLevel > level) { return;