Files
cosmos-explorer/.github/copilot-instructions.md
jawelton74 b483118b99 Copilot instructions and build/test skills (#2444)
* Add copilot instructions and skills for build and tests.

* Add dev-server skill.

* Auth Util changes to fix Entra login while running from copilot.

* Fix lint issue.
2026-04-06 15:51:54 -07:00

8.7 KiB
Raw Blame History

Copilot Instructions for Cosmos Explorer

Build, Test, and Lint

To build the project, use the /build skill. It handles dependency checks (npm install) and all build variants. See .github/skills/build/SKILL.md for full details.

Quick reference:

npm install              # Install dependencies (runs patch-package and i18n key generation automatically)
npm run build            # Full build: format check → lint → compile → strict compile → webpack prod → copy
npm run build:ci         # CI build: same as above but uses webpack dev mode (faster)
npm start                # Dev server with hot reload at https://localhost:1234 (see /dev-server skill)

npm run compile          # TypeScript check only (no emit)
npm run compile:strict   # TypeScript strict mode check (subset of files in tsconfig.strict.json)
npm run lint             # ESLint across all .ts/.tsx files
npm run format           # Prettier format (write)
npm run format:check     # Prettier format (check only)

Testing

To run unit tests, use the /run-unit-tests skill. It handles dependency checks and all test variants. See .github/skills/run-unit-tests/SKILL.md for full details.

Quick reference:

npm test                 # Run all unit tests with Jest (includes coverage)
npm run test:file -- path/to/file.test.ts   # Run a single test file (no coverage)
npm run test:debug       # Run tests serially for debugging (--runInBand)

# E2E tests (requires .env config and running dev server)
npm run test:e2e         # Playwright E2E tests
npx playwright test test/sql/document.spec.ts  # Run a single E2E spec

Unit tests live adjacent to source files (*.test.ts / *.test.tsx in src/). E2E tests are in test/ organized by API type (sql, mongo, cassandra, gremlin, tables).

Dev Server

To start the local dev server and connect a browser, use the /dev-server skill. It handles dependency checks, server startup, readiness polling, and Playwright browser navigation. See .github/skills/dev-server/SKILL.md for full details.

The dev server runs at https://localhost:1234 with a /_ready health-check endpoint. Entry points include hostedExplorer.html (standalone), explorer.html (portal iframe), and index.html (emulator).

Architecture

Platform Modes

The app runs in four hosting contexts, determined by ConfigContext.platform:

  • Portal Embedded as an iframe inside Azure Portal
  • Hosted Standalone at cosmos.azure.com, supports AAD, connection string, and resource token auth
  • Emulator Connects to local Cosmos DB Emulator via master key
  • Fabric Embedded in Microsoft Fabric, communicates via postMessage RPC

Platform-specific code lives in src/Platform/{Emulator,Hosted,Fabric}/. The active platform is set during initialization in src/hooks/useKnockoutExplorer.ts, which orchestrates bootstrapping for all modes.

Global State (Module Singletons + Zustand)

State is not managed by React Context or Redux for most application concerns. Instead:

  • userContext (src/UserContext.ts) Module-level singleton holding current account info, auth tokens, API type, and feature flags. Updated via updateUserContext(). Not a React store; components read it directly.
  • configContext (src/ConfigContext.ts) Module-level singleton for environment/endpoint configuration. Updated via updateConfigContext().
  • Zustand stores (src/hooks/use*.ts) Used for UI state that React components need to subscribe to reactively. Key stores:
    • useDatabases Database/collection tree state
    • useTabs Open tab management
    • useQueryCopilot Copilot query assistant state
    • useNotificationConsole Console notifications
    • useSidePanel Side panel visibility
    • useSelectedNode Currently selected tree node

Data Access Layer

src/Common/dataAccess/ contains all Cosmos DB CRUD operations (createCollection, readDatabases, queryDocuments, etc.). These functions call either the Cosmos SDK (@azure/cosmos) directly or go through proxy endpoints depending on the API type and auth method.

ARM (Azure Resource Manager) clients are auto-generated in src/Utils/arm/generatedClients/ — regenerate with npm run generateARMClients.

Multi-API Support

Cosmos DB supports multiple APIs: SQL, Mongo, Gremlin, Tables, Cassandra, Postgres, and VCoreMongo. The current API type is determined from userContext.apiType (derived from the database account's capabilities). API-specific UI components branch on this value.

Entry Points

Webpack builds multiple independent entry points (see webpack.config.js):

  • src/Main.tsxexplorer.html (Portal iframe)
  • src/Index.tsxindex.html (Emulator)
  • src/HostedExplorer.tsxhostedExplorer.html (cosmos.azure.com)
  • Plus: terminal, cellOutputViewer, galleryViewer, selfServe, connectToGitHub, quickstart

Knockout → React Migration

The codebase is actively migrating from Knockout.js to React. Legacy Knockout code still exists (observables, bindings), but all new UI must be React. The main Explorer class (src/Explorer/Explorer.tsx) is a large legacy class that orchestrates much of the app — it is not a React component but interacts with React via hooks and stores.

Key Conventions

Ignored Directories

The src/preview/ folder is a separate project and should not be modified or referenced.

Localization

All user-facing strings must be defined in src/Localization/en/Resources.json and referenced via the type-safe t() helper:

import { t } from "Localization/t";

// Use dot-notation keys matching the JSON structure
const label = t("common.save");
const title = t("splashScreen.title.default");

The ResourceKey type (derived from Resources.json) ensures compile-time safety — invalid keys will cause a type error. When adding new strings, add the English entry to Resources.json first, then reference it with t().

Imports

TypeScript baseUrl is set to src/, so imports from src/ are written without a leading ./src/ prefix:

import { userContext } from "UserContext";         // src/UserContext.ts
import { configContext } from "ConfigContext";      // src/ConfigContext.ts
import { readDatabases } from "Common/dataAccess/readDatabases";

React Components

  • Use Fluent UI v9 (@fluentui/react-components) for new components. Legacy code uses v8 (@fluentui/react), but new code should prefer v9.
  • Prefer pure functional components; hooks and class components are both acceptable
  • Do not use component inheritance for shared behavior
  • Do not suffix file or component names with "Component"

ESLint Rules to Note

  • no-console: Only console.error and console.warn are allowed (not console.log)
  • @typescript-eslint/no-explicit-any: Error — avoid any types
  • prefer-arrow/prefer-arrow-functions: Arrow functions preferred (standalone declarations allowed)
  • eqeqeq: Strict equality required
  • @typescript-eslint/switch-exhaustiveness-check: Switch statements must handle all cases
  • Do not use JSON.stringify(error) — it prints '{}'. The linter catches variable names matching $err.

Testing

Any code change should consider both unit and E2E test coverage:

  • Unit tests Write or update unit tests for all logic, utility, and component changes. Place test files adjacent to the source file (Foo.test.ts next to Foo.ts). Do not decrease existing coverage.
  • E2E tests Write or update a Playwright E2E test when a change affects a user-facing workflow (e.g., creating a container, running a query, editing a document). E2E tests live in test/ organized by API type.

Tooling and conventions:

  • Use Jest for unit tests with jest-environment-jsdom
  • Use @testing-library/react for new component tests. Enzyme exists in legacy tests but should not be used for new code.
  • Use Jest built-in mocking (not sinon.js)
  • E2E tests use Playwright (configured in playwright.config.ts); use accessible attributes (role, title, label) over data-* attributes for selectors

Strict Null Checks

The project is incrementally adopting strict null checks. tsconfig.strict.json lists files that compile under --strictNullChecks. New files must be added to tsconfig.strict.json so they compile under strict mode. Use npm run strict:add to add eligible files.

Libraries to Avoid

  • underscore.js Use native JS methods instead (legacy usage exists)
  • jQuery Being removed; do not add new usage
  • sinon.js Deprecated; use Jest mocking
  • TSLint Removed; use ESLint only

Formatting

Prettier with printWidth: 120 and endOfLine: auto. Format is enforced in the build pipeline via npm run format:check.