Skip to content
Merged
Show file tree
Hide file tree
Changes from 95 commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
63ee520
sync next and main (#501)
tnaum-ms Feb 10, 2026
c609539
feat: add maxWorkers configuration to optimize memory usage in Jest
tnaum-ms Feb 10, 2026
56ca5c3
feat: implement tests for vscodeLink operations including queries, mu…
tnaum-ms Feb 10, 2026
c7f7fa6
feat: update @trpc/client and @trpc/server to version 11.10.0
tnaum-ms Feb 10, 2026
afcea58
Initial plan
Copilot Feb 11, 2026
5ceda4f
Add experimental AI query generation setting and activation telemetry
Copilot Feb 11, 2026
d06bbb8
Revert unrelated package-lock.json changes
Copilot Feb 11, 2026
9c01543
feat: implement support for tRPC query and mutation cancellation usin…
tnaum-ms Feb 11, 2026
5381ca8
feat: enhance BaseRouterContext with detailed AbortSignal documentati…
tnaum-ms Feb 11, 2026
69ae902
feat: add SKILL.md for webview tRPC messaging with detailed guidance …
tnaum-ms Feb 11, 2026
522eb28
feat: refactor WebviewController to support AbortSignal for query and…
tnaum-ms Feb 11, 2026
4b74c1a
feat: refactor WebviewController and appRouter for improved AbortSign…
tnaum-ms Feb 11, 2026
a76a9ac
feat: enhance type safety for webview names and update SKILL.md with …
tnaum-ms Feb 11, 2026
a40fc5e
Initial plan
Copilot Feb 11, 2026
c330a3c
Add PromptReconnectStep and ReconnectStep to updateCredentials wizard
Copilot Feb 11, 2026
3883a91
Revert package-lock.json changes from npm install
Copilot Feb 11, 2026
73f41d9
feat: add AbortSignal support for query cancellation across various s…
tnaum-ms Feb 11, 2026
957e1fb
feat: propagate UserCancelledError for AbortSignal in query optimizat…
tnaum-ms Feb 11, 2026
d267243
feat: enhance query optimization with AbortSignal cancellation handli…
tnaum-ms Feb 11, 2026
d0b9627
feat: add cancellation messages for query insights and log Copilot ca…
tnaum-ms Feb 11, 2026
2fb430f
feat: add explanation for AbortSignal handling in sendSafe function t…
tnaum-ms Feb 11, 2026
458e1f3
feat: implement AbortSignal handling in dispose method to abort activ…
tnaum-ms Feb 11, 2026
392f135
Fix lint errors in PromptReconnectStep.test.ts
Copilot Feb 11, 2026
c8d6275
docs: update SKILL.md to use ${workspaceFolder} for file paths and ad…
tnaum-ms Feb 11, 2026
fcac390
Fix unbound-method lint errors in PromptReconnectStep.test.ts
Copilot Feb 11, 2026
b8ffaf2
Add PR Completion Checklist to copilot-instructions.md
Copilot Feb 11, 2026
8d39b6d
test: update expectation in vscodeLink tests to account for signal st…
tnaum-ms Feb 11, 2026
cbdf501
test: update expectation in vscodeLink tests to verify operation stru…
tnaum-ms Feb 11, 2026
53cdc3e
Apply prettier formatting fixes
Copilot Feb 11, 2026
3a740d2
Address review feedback on PromptReconnectStep
Copilot Feb 11, 2026
821b8b5
Show reconnect prompt when updating credentials from error node
Copilot Feb 12, 2026
fea7cb8
Rename isInErrorState to offerReconnect and apply reconnect to update…
Copilot Feb 12, 2026
ae97c48
Add React Webview Architecture and Guidelines documentation
tnaum-ms Feb 12, 2026
a12913c
Refactor reconnect logic in UpdateCS and UpdateCredentials wizards
tnaum-ms Feb 12, 2026
fbe02bb
Make experimentalFeaturesStatus telemetry fire-and-forget
Copilot Feb 12, 2026
7d2d536
Revert unrelated package-lock.json changes
Copilot Feb 12, 2026
9b01edc
Refactor reconnect handling in UpdateCredentials wizard and remove un…
tnaum-ms Feb 12, 2026
5db9cd7
docs: clarify webviewName naming distinction in tRPC messaging skill
tnaum-ms Feb 12, 2026
84482df
docs: document panel ownership architecture in WebviewController.disp…
tnaum-ms Feb 12, 2026
97d6fa5
fix: add double-dispose guard to WebviewController.dispose()
tnaum-ms Feb 12, 2026
5c12c2a
fix: clear Stage 3 AbortController ref on completion/failure
tnaum-ms Feb 12, 2026
65545d1
refactor: rename webview identifiers for consistency in WebviewRegistry
tnaum-ms Feb 12, 2026
abb5225
docs: add description for webviewName in BaseRouterContext
tnaum-ms Feb 12, 2026
7a4125d
Add experimental setting for AI query generation and activation telem…
tnaum-ms Feb 12, 2026
ba7df90
Merge branch 'next' into copilot/add-wizard-step-for-reconnecting
tnaum-ms Feb 12, 2026
77f95e0
refactor: use instance extensionContext instead of global ext.context…
tnaum-ms Feb 12, 2026
f8c668a
fix: prevent overwriting telemetry result='Canceled' with 'Failed' on…
tnaum-ms Feb 12, 2026
ec5510c
fix: prettier-fix
tnaum-ms Feb 12, 2026
c936c5d
Add reconnect prompt to credential update wizard for error recovery n…
tnaum-ms Feb 12, 2026
4d357fb
Merge branch 'next' into dev/tnaum/320-feat-support-trpc-query-cancel…
tnaum-ms Feb 12, 2026
0153bd6
feat: TRCP upgrade + abort signal support (#502)
tnaum-ms Feb 12, 2026
8a1ac34
chore(deps): bump qs and body-parser
dependabot[bot] Feb 14, 2026
66b2b9e
chore(deps): bump qs and body-parser (#505)
tnaum-ms Feb 16, 2026
64f03fb
docs: add feedback collection section to README
tnaum-ms Feb 17, 2026
663013c
docs: update feedback collection instructions in README
tnaum-ms Feb 17, 2026
390eeac
docs: add feedback collection section to README (#509)
tnaum-ms Feb 17, 2026
33d143b
docs: add connection string deduplication details to v0.7.0 release n…
tnaum-ms Feb 18, 2026
b12cf2e
docs: reorder dark theme rendering fix in changelog
tnaum-ms Feb 18, 2026
4b3653b
Defensive trimming and validation simplification for connection strin…
tnaum-ms Feb 18, 2026
4a94afa
Initial plan
Copilot Feb 18, 2026
6130185
Remove redundant trimming in connection string handling
Copilot Feb 18, 2026
387f51e
Move trimming to explicit separate line as requested
Copilot Feb 20, 2026
a2f0bd8
Move trimming to explicit separate line in connection string wizard s…
tnaum-ms Feb 20, 2026
5fe6a0e
chore: release notes 0.7 + change log update (#510)
tnaum-ms Feb 20, 2026
2c5d7d1
Merge branch 'next' into dev/tnaum/connection-string-handling
tnaum-ms Feb 23, 2026
e19ed25
Enhance storage connection string handling: add validation and cleanu…
tnaum-ms Feb 23, 2026
1102940
test: add whitespace trimming tests for sanitizeConnectionString
tnaum-ms Feb 23, 2026
446b21b
refactor: remove redundant .toString() in ExecuteStep
tnaum-ms Feb 23, 2026
bf94c78
test: add validatePassword unit tests
tnaum-ms Feb 23, 2026
c9750b6
Redact credentials from log messages that interpolate parser errors
tnaum-ms Feb 23, 2026
062d828
Document design intent for automatic cleanup of invalid connections
tnaum-ms Feb 23, 2026
e01fc14
Fix misleading success toast after failed connection-string save
tnaum-ms Feb 23, 2026
9e9f14e
chore(deps-dev): bump minimatch from 3.1.2 to 3.1.4
dependabot[bot] Feb 25, 2026
ca2e48e
feat: refactor data migration command and add announced migration pro…
tnaum-ms Feb 25, 2026
1bacb29
refactor: remove unused url property from announced provider QuickPic…
tnaum-ms Feb 25, 2026
fff1593
fix: validate announced providers array and shape from package.json
tnaum-ms Feb 25, 2026
97483ba
refactor: remove unused url field from AnnouncedMigrationProvider
tnaum-ms Feb 25, 2026
0392dfa
test: validate x-announcedMigrationProviders shape in package.json
tnaum-ms Feb 25, 2026
ca773cb
fix: prettier-fix
tnaum-ms Feb 25, 2026
bf3d738
chore(deps-dev): bump minimatch from 3.1.2 to 3.1.4 (#514)
tnaum-ms Feb 25, 2026
52b2b1a
version bump to `0.7.1`
tnaum-ms Feb 25, 2026
459b5a2
chore: update release notes for v0.7.1 patch release
tnaum-ms Feb 25, 2026
96eaf62
chore: update release notes to include v0.7.1 patch release
tnaum-ms Feb 25, 2026
65dc442
chore: add instructions for updating release notes index
tnaum-ms Feb 25, 2026
78de61c
Merge branch 'next' into dev/tnaum/connection-string-handling
tnaum-ms Feb 25, 2026
97a442d
Defensive trimming and validation simplification for connection strin…
tnaum-ms Feb 25, 2026
a1e7c98
Merge branch 'next' into dev/tnaum/announce-migration-providers
tnaum-ms Feb 25, 2026
30caad8
feat: Data Migration discoverability — announced providers & always-v…
tnaum-ms Feb 25, 2026
6929920
Update src/services/migrationServices.ts
tnaum-ms Feb 25, 2026
fe52895
Merge branch 'next' into dev/tnaum/prepare-0.7.1-release
tnaum-ms Feb 25, 2026
6fbdc7c
Prepare `0.7.1` release (#516)
tnaum-ms Feb 25, 2026
e9e2182
docs: clarify RFC 3986 assumption in redactCredentialsFromConnectionS…
tnaum-ms Feb 25, 2026
960118e
fix: clear Stage 3 tips/error timer on cancel and re-trigger
tnaum-ms Feb 25, 2026
3af9111
Add unmount cleanup for query insights timer
tnaum-ms Mar 9, 2026
e0664a6
[WIP] Pre-release updates `0.7.1` (#519)
tnaum-ms Mar 9, 2026
6f5099f
fix: dispose EventEmitter in WebviewController.dispose()
tnaum-ms Mar 9, 2026
45cddc7
fix: abort in-flight AI request on QueryInsightsTab unmount
tnaum-ms Mar 9, 2026
69f3942
fix: abort previous Stage 3 request before starting a new one
tnaum-ms Mar 9, 2026
c4b1c98
fix: correct GitHub branding in comment
tnaum-ms Mar 9, 2026
9c0fe64
docs: update SKILL.md to use current WebviewRegistry keys
tnaum-ms Mar 9, 2026
a05760e
docs: fix accessibility skill name reference
tnaum-ms Mar 9, 2026
106c48b
chore: run npm install
tnaum-ms Mar 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@ VS Code Extension for Azure Cosmos DB and MongoDB. TypeScript (strict mode), Rea

> ⚠️ **NEVER use `npm run compile`** - always use `npm run build` to build the project.

## PR Completion Checklist

Before finishing work on a PR, agents **must** run the following steps in order:

1. **Localization** — If any user-facing strings were added, modified, or removed, run:
```bash
npm run l10n
```
2. **Formatting** — Run Prettier to ensure all files meet formatting standards:
```bash
npm run prettier-fix
```
3. **Linting** — Run ESLint to confirm there are no linting errors:
```bash
npm run lint
```

> ⚠️ **An agent must not finish or terminate until all three steps above have been run and pass successfully.** Skipping these steps leads to CI failures.

## Project Structure

| Folder | Purpose |
Expand Down
248 changes: 248 additions & 0 deletions .github/skills/react-webview-architecture/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
---
name: react-webview-architecture
description: Architecture patterns for React-based webviews in the vscode-documentdb extension. Use when creating new webview components, modifying existing views (CollectionView, DocumentView), working with state management (Context API), integrating Fluent UI components, handling Monaco Editor or SlickGrid, solving stale closure bugs with refs, or debugging webview rendering issues. Does NOT cover tRPC messaging (see webview-trpc-messaging skill) or accessibility/ARIA (see detecting-accessibility-issues skill).
---

# React Webview Architecture

Patterns and conventions for React webviews in vscode-documentdb.

**Related skills** (do not duplicate):

- **webview-trpc-messaging** — tRPC routers, procedures, telemetry, AbortSignal, subscriptions, WebviewController
- **detecting-accessibility-issues** — ARIA labels, Announcer, focus management, screen reader patterns

Comment thread
tnaum-ms marked this conversation as resolved.
**Full reference**: See [references/REACT_ARCHITECTURE_GUIDELINES.md](./references/REACT_ARCHITECTURE_GUIDELINES.md)

## When to Use

- Creating or modifying a webview (DocumentView, CollectionView)
- Adding new components inside `src/webviews/`
- Working with CollectionView context or state management
- Integrating Monaco Editor or SlickGrid
- Debugging stale closure issues in event handlers

## Rendering Pipeline

Every webview boots through `src/webviews/index.tsx`:

```tsx
root.render(
<DynamicThemeProvider useAdaptive={true}>
<WithWebviewContext vscodeApi={vscodeApi}>
<Component />
</WithWebviewContext>
</DynamicThemeProvider>,
);
```

- **`DynamicThemeProvider`** — adapts Fluent UI theming to VS Code's active color theme
- **`WithWebviewContext`** — provides `vscodeApi` (postMessage) via React Context
- **`WebviewRegistry`** — maps webview names → React components (in `api/configuration/WebviewRegistry`)

Configuration from the extension host is read via `useConfiguration<T>()`.

## File Organization

```
viewName/
├── ViewName.tsx # Main component
├── viewName.scss # Styles
├── viewNameContext.ts # Context + state types (if complex)
├── viewNameController.ts # WebviewController subclass (extension-side)
├── viewNameRouter.ts # tRPC router (extension-side, see webview-trpc-messaging skill)
├── constants.ts
├── components/ # Sub-components
├── hooks/ # Custom React hooks
├── types/ # TypeScript types
└── utils/ # Helpers
```

## Component Hierarchy

**DocumentView** (simpler, good reference pattern):

```
DocumentView
├── ProgressBar (conditional: isLoading)
├── ToolbarDocuments
└── MonacoEditor
```

**CollectionView** (complex, multi-tab):

```
CollectionView
├── ProgressBar (conditional)
├── ToolbarMainView
├── QueryEditor
│ └── MonacoAutoHeight (multiple: filter, project, sort)
├── TabList (Results | Query Insights [PREVIEW])
├── Results Tab:
│ ├── ToolbarViewNavigation + ToolbarDocumentManipulation + ViewSwitcher
│ ├── DataViewPanelTable / DataViewPanelTree / DataViewPanelJSON
│ └── ToolbarTableNavigation (Table View only)
└── Query Insights Tab:
└── QueryInsightsMain (3-stage progressive loading)
```

## State Management

### Simple views (DocumentView): local `useState` + props

### Complex views (CollectionView): React Context with `[state, setState]` tuple

```tsx
export const CollectionViewContext = createContext<
[CollectionViewContextType, React.Dispatch<React.SetStateAction<CollectionViewContextType>>]
>([DefaultCollectionViewContext, () => {}]);

// Provider in parent
const [currentContext, setCurrentContext] = useState(DefaultCollectionViewContext);
<CollectionViewContext.Provider value={[currentContext, setCurrentContext]}>

// Consumer in child
const [currentContext, setCurrentContext] = useContext(CollectionViewContext);
```

**Always use functional updates** when state depends on previous value:

```tsx
setCurrentContext((prev) => ({
...prev,
isLoading: true,
activeQuery: { ...prev.activeQuery, pageNumber: 1 },
}));
```

## Stale Closure Pattern (CRITICAL)

Third-party components (SlickGrid) bind event handlers at initialization — they don't update when state changes. **Always use refs** to access current data in those handlers:

```tsx
const dataRef = useRef(data);
useEffect(() => {
dataRef.current = data;
}, [data]);

const onCellDblClick = useCallback((event) => {
const item = dataRef.current[event.detail.args.row]; // ✅ always current
// NOT: data[event.detail.args.row]; ❌ stale closure
}, []); // stable deps only
```

**Why**: SlickGrid binds handlers once at init time. Without refs, handlers see the data from initialization, not the latest state. This caused multiple hard-to-debug issues.

## Monaco Editor

### Required patterns:

1. **Manual layout** — Monaco doesn't auto-resize:

```tsx
useEffect(() => {
const handler = debounce(() => editorRef.current?.layout(), 200);
window.addEventListener('resize', handler);
handleResize(); // initial layout
return () => window.removeEventListener('resize', handler);
}, []);
```

2. **Dispose on unmount**:

```tsx
return () => {
editorRef.current?.dispose();
};
```

3. **MonacoAutoHeight** — self-sizing editor for query fields:

```tsx
<MonacoAutoHeight
adaptiveHeight={{ enabled: true, maxLines: 10, minLines: 1, lineHeight: 19 }}
onExecuteRequest={() => onExecuteRequest()}
onMount={(editor, monaco) => handleEditorDidMount(editor, monaco)}
/>
```

4. **JSON Schema delay** — Monaco's JSON worker may not be ready immediately after mount. An AbortController-guarded delay is used (see QueryEditor for the pattern).

## Fluent UI Integration

Use `@fluentui/react-components` (v9), themed via `DynamicThemeProvider`:

| Component | Usage |
| -------------------------- | ------------------------- |
| `ProgressBar` | Loading states |
| `Button`, `ToggleButton` | Toolbar actions |
| `Tab`, `TabList` | View switching |
| `Dropdown`, `Option` | Selection (ViewSwitcher) |
| `Badge` | Status/preview indicators |
| `MessageBar` | Info/warning messages |
| `Skeleton`, `SkeletonItem` | Loading placeholders |

Animations: `Collapse` from `@fluentui/react-motion-components-preview`

## Styling

- Each component gets its own `.scss` file, imported directly
- Shared styles in `sharedStyles.scss`, applied via `@extend`
- **Consistent spacing unit: `10px`** with flexbox `row-gap`/`column-gap`
- **No inline styles** — move to SCSS files
- Avoid negative margins — fix layout with proper flexbox

```scss
.documentView {
display: flex;
flex-direction: column;
height: 100vh;
row-gap: 10px;
}
```

## Custom Hooks

| Hook | Purpose |
| ------------------------------------- | -------------------------------------------------------------------------------------------- |
| `useSelectiveContextMenuPrevention()` | Prevents browser context menu everywhere except Monaco editors. Call once in top-level view. |
| `useHideScrollbarsDuringResize()` | Returns a function that temporarily hides scrollbars during layout transitions (500ms). |

## Conditional Rendering Patterns

**Object-based switch:**

```tsx
{{
'Table View': <DataViewPanelTable {...props} />,
'Tree View': <DataViewPanelTree {...props} />,
'JSON View': <DataViewPanelJSON {...props} />,
}[currentContext.currentView]}
```

## Loading State

```tsx
const [isLoading, setIsLoading] = useState(false);
setIsLoading(true);
try {
await op();
} finally {
setIsLoading(false);
}

// In render:
{
isLoading && <ProgressBar thickness="large" shape="square" className="progressBar" />;
}
```

## Common Pitfalls

1. **Forgetting refs with third-party components** → stale data in event handlers
2. **Not cleaning up** event listeners, Monaco instances, AbortControllers in `useEffect` return
3. **Not calling `editor.layout()`** after resize → blank Monaco panels
4. **Using `any`** → use proper types or `unknown` with type guards
5. **Missing `l10n.t()`** on user-facing strings
6. **Inline styles** instead of SCSS files
7. **Negative margins** to fix spacing — restructure layout with flexbox gap instead
Loading