Conversation
- cross-env: ~7.0.3 → ~10.1.0 - globals: ~16.5.0 → ~17.3.0 - Added eslint-plugin-jsx-a11y ~6.10.2 - Added eslint-plugin-react ~7.37.5 - Added eslint-plugin-react-hooks ~7.0.1
- Split .ts and .tsx into separate config blocks - Add React, JSX A11y, and React Hooks extends for .tsx files - Add mocha recommended rules with project-specific overrides - Add test rule relaxations (no-unsafe-call, no-unsafe-argument, etc.) - Enable consistent-type-imports rule for .tsx files
Add filesystem caching to both extension and views webpack configs to improve incremental build times.
Auto-fix 'import * as React' to 'import type * as React' across 16 webview component files where React is used only for types.
- Hoist function declarations before useEffect hooks that reference them (MonacoAutoHeight, CollectionView, documentView, DataViewPanelJSON) - Fix conditional useState in documentView (ternary → variable) - Rename useVSCodeTheme → getVSCodeThemeKind (not a hook, ThemeContext) - Convert synchronous setState in effects to functional updates or setTimeout callbacks (Announcer, AnimatedCardList) - Add targeted eslint-disable for legitimate patterns: - set-state-in-effect: loading state before async operations - refs: SlickgridReact imperative ref access (DataViewPanelTable) - Fix react/no-unescaped-entities in CollectionView
Repeated identical screen-reader messages (e.g. 'AI is analyzing...', 'Press Escape to exit editor') could be silently dropped because React deduplicated the unchanged state. Fix by scheduling a clear (setTimeout 0) before the announce (setTimeout 100) so the live region always transitions empty -> message, which assistive technologies detect as a new announcement. Both setState calls remain in timer callbacks to satisfy the react-hooks/set-state-in-effect lint rule added in this PR.
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2. - [Commits](WebReflection/flatted@v3.3.3...v3.4.2) --- updated-dependencies: - dependency-name: flatted dependency-version: 3.4.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [undici](https://github.com/nodejs/undici) from 7.22.0 to 7.24.5. - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](nodejs/undici@v7.22.0...v7.24.5) --- updated-dependencies: - dependency-name: undici dependency-version: 7.24.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
- Add .catch() to abort handler's close() to prevent unhandled rejections - Fix malformed l10n key: replace \u2026 escape with literal ellipsis character - Use neutral log message for cancelled/failed connections - Regenerate l10n bundle
Bumps and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together. Updates `picomatch` from 2.3.1 to 2.3.2 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](micromatch/picomatch@2.3.1...2.3.2) Updates `picomatch` from 4.0.3 to 4.0.4 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](micromatch/picomatch@2.3.1...2.3.2) --- updated-dependencies: - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect - dependency-name: picomatch dependency-version: 4.0.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [handlebars](https://github.com/handlebars-lang/handlebars.js) from 4.7.8 to 4.7.9. - [Release notes](https://github.com/handlebars-lang/handlebars.js/releases) - [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/v4.7.9/release-notes.md) - [Commits](handlebars-lang/handlebars.js@v4.7.8...v4.7.9) --- updated-dependencies: - dependency-name: handlebars dependency-version: 4.7.9 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.13. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.12...v1.1.13) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
There was a problem hiding this comment.
Pull request overview
This PR prepares the DocumentDB for VS Code extension v0.7.3 release by adding cancellable cluster connections, upgrading the runtime/tooling baseline to Node.js 22, and refining telemetry + developer tooling (ESLint/webpack/CI docs & templates).
Changes:
- Add cancellable connection UX (progress notification cancel) by plumbing
AbortSignalthroughClustersClientconnection creation and emitting connection correlation telemetry. - Upgrade Node/VS Code engine requirements and refresh dependencies; update webpack builds with filesystem caching and refine ESLint flat config for TSX/React/a11y.
- Expand telemetry measurements/properties (connection/discovery/query insights) and update docs/changelog + add placeholder ADO pipeline YAMLs.
Reviewed changes
Copilot reviewed 50 out of 51 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| webpack.config.views.js | Enable filesystem build cache for webview bundles. |
| webpack.config.ext.js | Enable filesystem build cache for extension bundle. |
| src/webviews/WebviewContext.tsx | Convert React import to type-only. |
| src/webviews/theme/state/ThemeContext.tsx | Rename theme getter; use functional state updates; add hook lint suppression. |
| src/webviews/index.tsx | Convert React import to type-only. |
| src/webviews/documentdb/documentView/documentView.tsx | Refactor initial editor content + editor refs/layout helpers. |
| src/webviews/documentdb/collectionView/components/toolbar/ToolbarDividerTransparent.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/resultsTab/DataViewPanelTable.tsx | Add eslint suppression for ref usage with Slickgrid. |
| src/webviews/documentdb/collectionView/components/resultsTab/DataViewPanelJSON.tsx | Reorder resize handler definition (no behavioral change intended). |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/summaryCard/SummaryCard.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/summaryCard/GenericCell.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/summaryCard/custom/PerformanceRatingCell.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/summaryCard/CellBase.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/QuickActions.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/queryPlanSummary/StageDetailCard.tsx | Change React import form (now type-only). |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/optimizationCards/custom/GetPerformanceInsightsCard.tsx | Change React import form (now type-only). |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/metricsRow/TimeMetric.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/metricsRow/RatioMetric.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/metricsRow/MetricsRow.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/metricsRow/MetricBase.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/metricsRow/GenericMetric.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/metricsRow/CountMetric.tsx | Convert React import to type-only. |
| src/webviews/documentdb/collectionView/components/queryInsightsTab/components/animatedCardList/AnimatedCardList.tsx | Use functional state updates to avoid stale closures when diffing items. |
| src/webviews/documentdb/collectionView/collectionViewRouter.ts | Add telemetry breakdown counts for recommendation actions. |
| src/webviews/documentdb/collectionView/CollectionView.tsx | Minor lint suppressions + HTML escaping in UI error fallback. |
| src/webviews/components/MonacoAutoHeight.tsx | Reorder helper definitions; preserve existing resize/tab handling logic. |
| src/webviews/api/webview-client/accessibility/Announcer.tsx | Improve re-announcement behavior for identical messages + timer cleanup. |
| src/tree/documentdb/ClusterItemBase.ts | Add cancellable connection progress wrapper + cancellation telemetry/logging. |
| src/tree/connections-view/DocumentDBClusterItem.ts | Add connection source/type telemetry + cancellable connect path + correlation ID. |
| src/tree/azure-resources-view/mongo-ru/RUCoreResourceItem.ts | Use cancellable connect path + connection telemetry fields. |
| src/tree/azure-resources-view/documentdb/VCoreResourceItem.ts | Use cancellable connect path + connection telemetry fields. |
| src/services/ai/QueryInsightsAIService.ts | Add telemetry breakdown counts for recommendation actions. |
| src/plugins/service-azure-vm/discovery-tree/vm/AzureVMResourceItem.ts | Use cancellable connect path + connection correlation telemetry. |
| src/plugins/service-azure-mongo-vcore/discovery-tree/documentdb/DocumentDBResourceItem.ts | Use cancellable connect path + cancellation telemetry + correlation ID. |
| src/plugins/service-azure-mongo-ru/discovery-tree/documentdb/MongoRUResourceItem.ts | Use cancellable connect path + cancellation telemetry + correlation ID. |
| src/documentdb/utils/getClusterMetadata.ts | Add pre-connection domain-only metadata helper. |
| src/documentdb/ClustersClient.ts | Add abortable connect, correlation ID, and static metadata telemetry emission. |
| src/commands/updateCredentials/updateCredentials.ts | Add telemetry property for invocation source. |
| src/commands/removeDiscoveryRegistry/removeDiscoveryRegistry.ts | Add telemetry for discovery provider removal + active count. |
| src/commands/addDiscoveryRegistry/ExecuteStep.ts | Add telemetry for discovery provider addition + active count. |
| src/commands/addConnectionFromRegistry/addConnectionFromRegistry.ts | Add telemetry property for source view. |
| package.json | Bump version to 0.7.3; update engines + dependency refresh. |
| l10n/bundle.l10n.json | Add new connection/cancellation/localized error strings. |
| eslint.config.mjs | Split TS/TSX configs; add react/react-hooks/jsx-a11y; refine test file overrides. |
| docs/release-notes/0.7.md | Add v0.7.3 release notes entry. |
| docs/index.md | Link v0.7.3 release notes section. |
| CHANGELOG.md | Add v0.7.3 changelog entry. |
| .nvmrc | Update Node version to 22.18. |
| .azure-pipelines/release-npm-packages.yml | Add placeholder ADO release pipeline for config validation. |
| .azure-pipelines/build-npm-packages.yml | Add placeholder ADO build pipeline for config validation. |
Comments suppressed due to low confidence (6)
src/webviews/documentdb/collectionView/components/resultsTab/DataViewPanelTable.tsx:213
/* eslint-disable react-hooks/refs */disables the rule for the rest of the file. Prefer a narrower suppression (e.g.,eslint-disable-next-line react-hooks/refson theref={gridRef}line, or re-enable immediately after) to avoid masking future violations.
src/tree/connections-view/DocumentDBClusterItem.ts:244- Avoid
(error as Error).messagein catch blocks;errorcan be non-Error and this will produce misleading/undefined messages (and violates the repo’s safe-error-handling pattern). ExtracterrorMessageviaerror instanceof Error ? error.message : String(error)and use that in output/UI.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
src/tree/azure-resources-view/mongo-ru/RUCoreResourceItem.ts:130
- Avoid
(error as Error).messagein this catch block; use a safeerrorMessageextraction (error instanceof Error ? error.message : String(error)) before logging/showing the error.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
src/tree/azure-resources-view/documentdb/VCoreResourceItem.ts:178
- Avoid
(error as Error).messagein this catch block; use a safeerrorMessageextraction (error instanceof Error ? error.message : String(error)) before logging/showing the error.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
src/plugins/service-azure-mongo-vcore/discovery-tree/documentdb/DocumentDBResourceItem.ts:195
- Avoid
(error as Error).messagein this catch block; use a safeerrorMessageextraction (error instanceof Error ? error.message : String(error)) before logging/showing the error.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.measurements.connectionEstablishmentTimeMs = Date.now() - connectionStartTime;
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
// Add error telemetry
context.telemetry.measurements.connectionEstablishmentTimeMs = Date.now() - connectionStartTime;
context.telemetry.properties.connectionResult = 'failed';
context.telemetry.properties.connectionErrorType = error instanceof Error ? error.name : 'UnknownError';
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
src/plugins/service-azure-mongo-ru/discovery-tree/documentdb/MongoRUResourceItem.ts:146
- Avoid
(error as Error).messagein this catch block; use a safeerrorMessageextraction (error instanceof Error ? error.message : String(error)) before logging/showing the error.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.measurements.connectionEstablishmentTimeMs = Date.now() - connectionStartTime;
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
// Add error telemetry
context.telemetry.measurements.connectionEstablishmentTimeMs = Date.now() - connectionStartTime;
context.telemetry.properties.connectionResult = 'failed';
context.telemetry.properties.connectionErrorType = error instanceof Error ? error.name : 'UnknownError';
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
… telemetry C1/C2: actionableRecommendationCount was incremented unconditionally for every improvement, including those with action:'none'. This overcounted actionable items and caused divergence from per-action counters. Move the increment inside each actionable switch case (create/drop/modify) so 'none' recommendations are excluded from actionableRecommendationCount.
…eact.Ref C3/C4: 'import type React from react' shadows the React namespace making React.Ref inaccessible for type checking. Switch to 'import type * as React' which is the established pattern in this codebase and keeps React.Ref accessible.
…dren C6: when the user cancels a connection attempt, ClusterItemBase was setting clustersClient=null and falling through to the generic failure path which logged 'Could not connect...' and rendered an error/retry tree node. Return early with an empty array on UserCancelledError so cancellation is silent — no error message, no retry node shown to the user.
C5/S2-S6: Replace (error as Error).message with the safe extraction pattern
'error instanceof Error ? error.message : String(error)' in catch blocks
across AzureVMResourceItem, DocumentDBClusterItem, RUCoreResourceItem,
VCoreResourceItem, DocumentDBResourceItem and MongoRUResourceItem.
S1: Replace file-wide eslint-disable for react-hooks/refs with a narrower
eslint-disable-next-line comment on the specific ref={gridRef} line in
DataViewPanelTable.tsx to avoid masking future violations.
…wPanelTable S1: The narrower per-line suppression required two separate comments and was fragile. Restore the file-wide disable with an explanatory comment — SlickgridReact's imperative ref API inherently requires ref access patterns that trigger this rule throughout the file.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 50 out of 51 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (4)
src/tree/connections-view/DocumentDBClusterItem.ts:245
- This catch block uses
(error as Error).messagewhen logging and showing the error. If a non-Errorvalue is thrown, this will itself throw and hide the original failure. Extract a safeerrorMessageviaerror instanceof Error ? error.message : String(error)and use that for both output + UI.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
);
src/tree/azure-resources-view/mongo-ru/RUCoreResourceItem.ts:130
- This catch block uses
(error as Error).messagewhen logging and building the modaldetail. If the thrown value isn’t anError, this can crash the handler and obscure the real issue. Use a safeerrorMessage(error instanceof Error ? error.message : String(error)) and use that consistently.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
src/tree/azure-resources-view/documentdb/VCoreResourceItem.ts:178
- This catch block uses
(error as Error).messagewhen logging and building the modaldetail. If the thrown value isn’t anError, accessing.messagecan throw and mask the underlying error. Prefer a safe extraction (error instanceof Error ? error.message : String(error)) and use that for output + UI.
} catch (error) {
if (error instanceof UserCancelledError) {
context.telemetry.properties.connectionResult = 'cancelled';
throw error;
}
ext.outputChannel.appendLine(l10n.t('Error: {error}', { error: (error as Error).message }));
void vscode.window.showErrorMessage(
l10n.t('Failed to connect to "{cluster}"', { cluster: this.cluster.name }),
{
modal: true,
detail:
l10n.t('Revisit connection details and try again.') +
'\n\n' +
l10n.t('Error: {error}', { error: (error as Error).message }),
},
src/webviews/documentdb/collectionView/components/resultsTab/DataViewPanelTable.tsx:213
/* eslint-disable react-hooks/refs */here disables the rule for the rest of the file (there’s no matchingeslint-enable). If the intent is only to allow the singleref={gridRef}usage, prefereslint-disable-next-line react-hooks/refson therefline (or re-enable immediately after) to keep the suppression scoped.
Previously, when a cached ClustersClient existed, getClient() called client._mongoClient.connect() without hooking up the abortSignal, making the cancellable progress UI ineffective for reconnections. Now the cached client branch mirrors the fresh-connection pattern: check for pre-aborted signal, wire an abort listener that closes the MongoClient, and convert aborted errors to UserCancelledError.
The abort listener was kept active during synchronous API initialization (llmEnhancedFeatureApis, QueryInsightsApis) after the MongoClient connected. A late cancellation in that narrow window could close an already-connected client while the method continued as successful. Remove the listener right after connect() resolves to eliminate this race.
Add inline comment explaining that connectionCorrelationId retains the value from the initial connection. Cached reconnects do not emit new metadata telemetry events, so generating a new ID would be misleading rather than helpful.
The connect telemetry event emitted on tree-expansion cancellation was missing source and experience properties, making the event harder to attribute in analytics. Add source='treeExpansion' and the experience API type to match the pattern used by subclass connect events.
This pull request delivers the 0.7.3 release for the DocumentDB for VS Code extension. It introduces a user-facing feature to cancel in-progress cluster connections, upgrades the extension’s runtime and dependencies to Node.js 22 and the latest package versions, and refines internal telemetry for improved diagnostics. Additionally, it updates CI/CD pipeline templates and enhances the ESLint configuration for React and TypeScript codebases.
Key changes:
New Features:
Dependency and Platform Upgrades:
.nvmrc,package.json, and documentation). [1] [2] [3] [4]Developer Experience and Tooling:
CI/CD Pipeline Improvements:
Localization: