Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
146 changes: 146 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,152 @@ export async function yourCommand(context: IActionContext, targetItem: SomeItem)
}
```

### Wizard Back Navigation and Context Persistence

When users navigate back in a wizard (via `GoBackError`), the `AzureWizard` framework resets context properties. Understanding this behavior is critical for proper wizard implementation.

#### How AzureWizard Handles Back Navigation

When a step throws `GoBackError`, the wizard:

1. Pops steps from the finished stack until finding the previous prompted step
2. **Resets context properties** to what existed before that step's `prompt()` ran
3. Re-runs the step's `prompt()` method

**Critical Implementation Detail**: Before each step's `prompt()` runs, the wizard captures `propertiesBeforePrompt`:

```javascript
// From AzureWizard.js - this runs for EACH step before prompt()
step.propertiesBeforePrompt = Object.keys(this._context).filter((k) => !isNullOrUndefined(this._context[k])); // Only non-null/undefined values!
```

When going back, properties NOT in `propertiesBeforePrompt` are set to `undefined`:

```javascript
// From AzureWizard.js goBack() method
for (const key of Object.keys(this._context)) {
if (!step.propertiesBeforePrompt.find((p) => p === key)) {
this._context[key] = undefined; // Property gets cleared!
}
}
```

#### Making Context Properties Survive Back Navigation

To ensure a context property survives when users navigate back, you must initialize it with a **non-null, non-undefined value** in the wizard context creation:

```typescript
// ❌ Bad - Property will be cleared on back navigation
const wizardContext: MyWizardContext = {
...context,
cachedData: undefined, // undefined is filtered out of propertiesBeforePrompt!
};

// ❌ Bad - Property not initialized, same problem
const wizardContext: MyWizardContext = {
...context,
// cachedData not set - will be undefined
};

// ✅ Good - Property will survive back navigation (using empty array)
const wizardContext: MyWizardContext = {
...context,
cachedData: [], // Empty array is not null/undefined, captured in propertiesBeforePrompt
};

// ✅ Good - Property will survive back navigation (using empty object)
const wizardContext: MyWizardContext = {
...context,
cachedConfig: {}, // Empty object is not null/undefined
};

// ✅ Good - Property will survive back navigation (using empty string)
const wizardContext: MyWizardContext = {
...context,
cachedId: '', // Empty string is not null/undefined
};

// ✅ Good - Property will survive back navigation (using zero)
const wizardContext: MyWizardContext = {
...context,
retryCount: 0, // Zero is not null/undefined
};

// ✅ Good - Property will survive back navigation (using false)
const wizardContext: MyWizardContext = {
...context,
hasBeenValidated: false, // false is not null/undefined
};
```

#### Pattern for Cached Data with Back Navigation Support

When you need to cache expensive data (like API calls) that should survive back navigation:

1. **Context Interface**: Make the property required with a non-nullable type

```typescript
export interface MyWizardContext extends IActionContext {
// Required - initialized with non-null/undefined value to survive back navigation
cachedItems: CachedItem[];

// Optional - user selections that may be cleared
selectedItem?: SomeItem;
}
```

2. **Wizard Initialization**: Initialize with a non-null/undefined value

```typescript
const wizardContext: MyWizardContext = {
...context,
cachedItems: [], // Any non-null/undefined value survives back navigation
};
```

3. **Step Implementation**: Check appropriately for the initial value

```typescript
public async prompt(context: MyWizardContext): Promise<void> {
const getQuickPickItems = async () => {
// Check for initial empty value (array uses .length, string uses === '', etc.)
if (context.cachedItems.length === 0) {
context.cachedItems = await this.fetchExpensiveData();
}
return context.cachedItems.map(item => ({ label: item.name }));
};

await context.ui.showQuickPick(getQuickPickItems(), { /* options */ });
}
```

4. **Clearing Cache**: Reset to the initial non-null/undefined value

```typescript
// When you need to invalidate the cache (e.g., after a mutation)
context.cachedItems = []; // Reset to initial value, not undefined!
```

#### Using GoBackError in Steps

To navigate back programmatically from a step:

```typescript
import { GoBackError } from '@microsoft/vscode-azext-utils';

public async prompt(context: MyWizardContext): Promise<void> {
const result = await context.ui.showQuickPick(items, options);

if (result.isBackOption) {
// Clear step-specific selections before going back
context.selectedItem = undefined;
throw new GoBackError();
}

// Process selection...
}
```

### Tree View Architecture

- Use proper data providers that implement `vscode.TreeDataProvider`.
Expand Down
155 changes: 89 additions & 66 deletions docs/user-manual/managing-azure-discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,65 @@ For a general overview of service discovery, see the [Service Discovery](./servi

---

## Managing Azure Accounts
## Managing Azure Accounts and Tenants

The **Manage Credentials** feature allows you to view and manage which Azure accounts are being used for service discovery within the extension.
The **Manage Credentials** feature allows you to view your Azure accounts, sign in to specific tenants, and add new accounts for service discovery.

### How to Access

You can access the credential management feature in two ways:

1. **From the context menu**: Right-click on an Azure service discovery provider and select `Manage Credentials...`
2. **From the Service Discovery panel**: Click the `key icon` next to the service discovery provider name
2. **From the Service Discovery panel**: Click the `key icon` next to the service discovery provider name.

### Available Actions
### Account and Tenant Management Flow

When you open the credential management wizard, you can:
The wizard provides options to manage your Azure authentication state.

1. **View signed-in accounts**: See all Azure accounts currently authenticated in VS Code and available for service discovery
2. **Sign in with a different account**: Add additional Azure accounts for accessing more resources
3. **View active account details**: See which account is currently being used for a specific service discovery provider
4. **Exit without changes**: Close the wizard without making modifications
#### Step 1: Select an Account

### Account Selection
First, you'll see a list of all Azure accounts currently authenticated in VS Code. For each account, you can see how many tenants are available and how many you are currently signed in to.

You can:

- Select an existing account to manage its tenants.
- Choose `Sign in with a different account…` to add a new Azure account.

```
┌───────────────────────────────────────────────────────────┐
│ Azure accounts used for service discovery │
├───────────────────────────────────────────────────────────┤
│ 👤 [email protected]
│ 2 tenants available (1 signed in) │
│ 👤 [email protected]
│ 1 tenant available (1 signed in) │
├───────────────────────────────────────────────────────────┤
│ 🔐 Sign in with a different account… │
│ ✖️ Exit │
└───────────────────────────────────────────────────────────┘
```

#### Step 2: Manage Tenants for the Selected Account

After selecting an account, you will see a list of all tenants associated with that account, along with their sign-in status.

```
┌────────────────────────────────────────────┐
│ Azure accounts used for service discovery │
├────────────────────────────────────────────┤
│ 👤 [email protected]
│ 👤 [email protected]
├────────────────────────────────────────────┤
│ 🔐 Sign in with a different account… │
│ ✖️ Exit without making changes │
└────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────┐
│ Tenants for "[email protected]" │
├───────────────────────────────────────────────────────────┤
│ Experiments │
│ ✅ Signed in │
│ Production │
│ 🔐 Select to sign in │
├───────────────────────────────────────────────────────────┤
│ ⬅️ Back to account selection │
│ ✖️ Exit │
└───────────────────────────────────────────────────────────┘
```

- **Sign in to a tenant**: Select any tenant marked with `$(sign-in) Select to sign in`. The extension will authenticate you for that specific tenant, making its subscriptions available for discovery.
- **Already signed-in tenants**: Selecting a tenant that is already signed in will simply confirm your status and allow you to return to the list.

### Signing Out from an Azure Account

The credential management wizard does **not** provide a sign-out option. If you need to sign out from an Azure account:
Expand All @@ -62,64 +87,63 @@ The credential management wizard does **not** provide a sign-out option. If you

## Filtering Azure Resources

The **Filter** feature allows you to control which Azure resources are displayed in the Service Discovery panel by selecting specific tenants and subscriptions.
The **Filter** feature allows you to control which Azure resources are displayed in the Service Discovery panel by selecting from your **currently signed-in tenants** and their corresponding subscriptions.

### How to Access

You can access the filtering feature by clicking the **funnel icon** next to the service discovery provider name in the Service Discovery panel.

### Filtering Flow

The filtering wizard guides you through selecting which Azure resources to display:
The filtering wizard guides you through selecting which Azure resources to display. The flow adapts based on your Azure environment.

#### Single-Tenant Scenario

If you have access to only one Azure tenant, the wizard will skip tenant selection and proceed directly to subscription filtering:
If you have access to only one Azure tenant (or are only signed in to one), the wizard will skip tenant selection and proceed directly to subscription filtering:

```
┌────────────────────────────────────────────┐
│ Select subscriptions to include in │
│ service discovery │
├────────────────────────────────────────────┤
│ ☑️ Production Subscription │
│ (sub-id-123) (Contoso) │
│ ☑️ Development Subscription │
│ (sub-id-456) (Contoso) │
│ ☐ Test Subscription │
│ (sub-id-789) (Contoso) │
└────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────┐
│ Select subscriptions to include in service discovery │
├───────────────────────────────────────────────────────────┤
│ ☑️ Demos (Experiments) │
│ (sub-id-123) │
│ ☑️ TestRuns (Experiments) │
│ (sub-id-456) │
└───────────────────────────────────────────────────────────┘
```

#### Multi-Tenant Scenario

If you have access to multiple Azure tenants, the wizard will first ask you to select tenants, then filter subscriptions based on your tenant selection:

**Step 1: Select Tenants**

The wizard first asks you to select from the tenants you are currently signed in to. Only tenants authenticated via the "Manage Credentials" flow will appear here.

```
┌───────────────────────────────────────────────────────────┐
│ Select tenants (manage accounts to see more) │
├───────────────────────────────────────────────────────────┤
│ ☑️ Experiments │
│ (tenant-id-123) │
│ ☑️ Production │
│ (tenant-id-456) │
└───────────────────────────────────────────────────────────┘
```

**Step 2: Select Subscriptions**

Next, you'll see a list of subscriptions belonging to the tenants you selected in the previous step.

```
Step 1: Select Tenants
┌────────────────────────────────────────────┐
│ Select tenants to include in subscription │
│ discovery │
├────────────────────────────────────────────┤
│ ☑️ Contoso │
│ (tenant-id-123) contoso.onmicrosoft.com │
│ ☑️ Fabrikam │
│ (tenant-id-456) fabrikam.onmicrosoft.com │
│ ☐ Adventure Works │
│ (tenant-id-789) adventureworks.com │
└────────────────────────────────────────────┘

Step 2: Select Subscriptions (filtered by selected tenants)
┌────────────────────────────────────────────┐
│ Select subscriptions to include in │
│ service discovery │
├────────────────────────────────────────────┤
│ ☑️ Contoso Production │
│ (sub-id-123) (Contoso) │
│ ☑️ Contoso Development │
│ (sub-id-456) (Contoso) │
│ ☑️ Fabrikam Production │
│ (sub-id-789) (Fabrikam) │
└────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────┐
│ Select subscriptions to include in service discovery │
├───────────────────────────────────────────────────────────┤
│ ☑️ Demos (Experiments) │
│ (sub-id-123) │
│ ☑️ Portal (Production) │
│ (sub-id-789) │
└───────────────────────────────────────────────────────────┘
```

### Filter Persistence
Expand All @@ -134,22 +158,21 @@ The filtering behavior differs depending on how you access service discovery:

When working within the **Service Discovery** panel in the sidebar:

- Your filter selections (tenants and subscriptions) are **applied automatically**
- Only resources from selected tenants and subscriptions are displayed
- The filter persists until you change it
- Your filter selections (tenants and subscriptions) are **applied automatically**.
- Only resources from selected tenants and subscriptions are displayed.
- The filter persists until you change it.

#### From the "Add New Connection" Wizard

When adding a new connection via the **"Add New Connection"** wizard:

- **No filtering is applied** by default
- You will see **all subscriptions from all tenants** you have access to
- You must select one subscription to continue, but the full list is available
- This ensures you can always access any resource when explicitly adding a connection
- **No filtering is applied** by default.
- You will see **all subscriptions from all tenants** you have access to, regardless of your filter settings or sign-in status for each tenant.
- This ensures you can always access any resource when explicitly adding a connection.

## Related Documentation

- [Service Discovery Overview](./service-discovery)
- [Azure CosmosDB for MongoDB (RU) Service Discovery](./service-discovery-azure-cosmosdb-for-mongodb-ru)
- [Azure Cosmos DB for MongoDB (RU) Service Discovery](./service-discovery-azure-cosmosdb-for-mongodb-ru)
- [Azure DocumentDB Service Discovery](./service-discovery-azure-cosmosdb-for-mongodb-vcore)
- [Azure VMs (DocumentDB) Service Discovery](./service-discovery-azure-vms)
Loading