Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9341950
remove codeless unit tests
andrew-eldridge Jul 9, 2026
21aa7b7
fix tests
andrew-eldridge Jul 9, 2026
ae1cf66
Merge branch 'main' of github.com:Azure/LogicAppsUX into aeldridge/co…
andrew-eldridge Jul 10, 2026
c4a3d02
Merge branch 'main' of github.com:Azure/LogicAppsUX into aeldridge/co…
andrew-eldridge Jul 13, 2026
05a97a2
remove redundant sendMsgToWebview
andrew-eldridge Jul 13, 2026
30c009a
refactor designer, monitoring view, and connection view panels/comman…
andrew-eldridge Jul 14, 2026
e09063a
fix tests
andrew-eldridge Jul 14, 2026
398aa6c
Merge branch 'main' of github.com:Azure/LogicAppsUX into aeldridge/vs…
andrew-eldridge Jul 14, 2026
ea81cc5
address pr comments
andrew-eldridge Jul 14, 2026
c61ae55
optimize getDesignerPanelMetadata, fix concurrency issues
andrew-eldridge Jul 14, 2026
8b3283b
overview panels initial refactor
andrew-eldridge Jul 16, 2026
d6af5a0
consolidate interval polling handlers
andrew-eldridge Jul 16, 2026
8d59613
update tests
andrew-eldridge Jul 16, 2026
eb1ea19
only update callback info when baseUrl changed, fix codeful panel name
andrew-eldridge Jul 16, 2026
8afc78d
enforce retry limit on handleCallbackInfoUpdate
andrew-eldridge Jul 16, 2026
3b411cc
immediately attach to cached overview panel if available and runtime …
andrew-eldridge Jul 16, 2026
4a15a1b
clean up code
andrew-eldridge Jul 16, 2026
918b3bb
remove old openOverview
andrew-eldridge Jul 16, 2026
5e98655
Merge branch 'main' of github.com:Azure/LogicAppsUX into aeldridge/vs…
andrew-eldridge Jul 16, 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
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,10 @@ export default class DataMapperPanel {
this.panel.webview.html = await getWebViewHTML('vs-code-react', this.panel);
}

public sendMsgToWebview(msg: MessageToWebview) {
this.panel.webview.postMessage(msg);
}

private _handleWebviewMsg(msg: MessageToVsix) {
switch (msg.command) {
case ExtensionCommand.initialize: {
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.initialize_frame,
data: {
project: ProjectName.dataMapper,
Expand All @@ -136,7 +132,7 @@ export default class DataMapperPanel {
}
case ExtensionCommand.webviewLoaded: {
// Send runtime port to webview
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.setRuntimePort,
data: `${ext.designTimeInstances.get(ext.defaultLogicAppPath)?.port}`,
});
Expand Down Expand Up @@ -214,7 +210,7 @@ export default class DataMapperPanel {
}

public isTestDisabledForOS() {
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.isTestDisabledForOS,
data: process.platform === Platform.mac,
});
Expand All @@ -237,7 +233,7 @@ export default class DataMapperPanel {
public handleLoadMapDefinitionIfAny() {
if (this.mapDefinitionData) {
const mapMetadata = this.readMapMetadataFile();
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.loadDataMap,
data: {
...this.mapDefinitionData,
Expand Down Expand Up @@ -353,7 +349,7 @@ export default class DataMapperPanel {
result.forEach((file) => {
this.getNestedFilePaths(file, '', folderPath, filesToDisplay, fileTypes);
});
this.sendMsgToWebview({
this.panel.webview.postMessage({
command,
data: filesToDisplay,
});
Expand All @@ -370,7 +366,7 @@ export default class DataMapperPanel {
result.forEach((file) => {
this.getNestedFileTreePaths(file, '', folderPath, filesToDisplay, fileTypes);
});
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: command,
data: filesToDisplay,
});
Expand Down Expand Up @@ -418,7 +414,7 @@ export default class DataMapperPanel {
copyFileSync(primarySchemaFullPath, newPath);
}

this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.fetchSchema,
data: {
fileName: primarySchemaFileName,
Expand Down Expand Up @@ -560,7 +556,7 @@ export default class DataMapperPanel {

if (fileExistsSync(expectedXsltPath)) {
fs.readFile(expectedXsltPath, 'utf-8').then((fileContents) => {
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.setXsltData,
data: {
filename: this.dataMapName,
Expand All @@ -576,14 +572,14 @@ export default class DataMapperPanel {
public getConfigurationSetting(configSetting: string) {
const azureDataMapperConfig = workspace.getConfiguration(ext.prefix);
const configValue = azureDataMapperConfig.get<boolean>(configSetting) ?? true;
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.getConfigurationSetting,
data: configValue,
});
}

public handleGetDataMapperVersion() {
this.sendMsgToWebview({
this.panel.webview.postMessage({
command: ExtensionCommand.getDataMapperVersion,
data: this.dataMapVersion,
});
Expand Down
16 changes: 9 additions & 7 deletions apps/vs-code-designer/src/app/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ import { viewProperties } from './viewProperties';
import { configureWebhookRedirectEndpoint } from './workflows/configureWebhookRedirectEndpoint/configureWebhookRedirectEndpoint';
import { enableAzureConnectors } from './workflows/enableAzureConnectors';
import { exportLogicApp } from './workflows/exportLogicApp';
import { openDesigner } from './workflows/openDesigner/openDesigner';
import { openOverview } from './workflows/openOverview';
import { openDesigner } from './workflows/designer/openDesigner';
import { openOverview } from './workflows/overview/openOverview';
import { reviewValidation } from './workflows/reviewValidation';
import { switchDebugMode } from './workflows/switchDebugMode/switchDebugMode';
import { switchToDotnetProjectCommand } from './workflows/switchToDotnetProject';
Expand All @@ -78,7 +78,7 @@ import { switchToDataMapperV2 } from './setDataMapperVersion';
import { reportAnIssue } from '../utils/reportAnIssue';
import { localize } from '../../localize';
import { guid } from '@microsoft/logic-apps-shared';
import { openLanguageServerConnectionView } from './workflows/languageServer/connectionView';
import { openConnectionView } from './workflows/connectionView/openConnectionView';
import { enableDevContainer } from './enableDevContainer/enableDevContainer';

export function registerCommands(): void {
Expand Down Expand Up @@ -160,18 +160,20 @@ export function registerCommands(): void {
registerCommandWithTreeNodeUnwrapping(extensionCommand.validateAndInstallBinaries, validateAndInstallBinaries);
registerCommandWithTreeNodeUnwrapping(extensionCommand.resetValidateAndInstallBinaries, resetValidateAndInstallBinaries);
registerCommandWithTreeNodeUnwrapping(extensionCommand.disableValidateAndInstallBinaries, disableValidateAndInstallBinaries);
// Data Mapper Commands

// Data Mapper
registerCommand(extensionCommand.createNewDataMap, (context: IActionContext) => createNewDataMapCmd(context));
registerCommand(extensionCommand.loadDataMapFile, (context: IActionContext, uri: vscode.Uri) => loadDataMapFileCmd(context, uri));
// Custom code commands

// Custom code
registerCommandWithTreeNodeUnwrapping(extensionCommand.buildCustomCodeFunctionsProject, tryBuildCustomCodeFunctionsProject);
registerCommand(extensionCommand.createCustomCodeFunction, createCustomCodeFunction);
registerCommand(extensionCommand.debugLogicApp, debugLogicApp);
registerCommand(extensionCommand.switchToDataMapperV2, switchToDataMapperV2);
registerCommand(extensionCommand.enableDevContainer, enableDevContainer);

// Language server protocol
registerCommand(extensionCommand.openLanguageServerConnectionView, openLanguageServerConnectionView);
// Connections
registerCommand(extensionCommand.openLanguageServerConnectionView, openConnectionView);

// Error handler
registerErrorHandler((errorContext: IErrorHandlerContext): void => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { IActionContext } from '@microsoft/vscode-azext-utils';
import type { CodeSelection } from '@microsoft/vscode-extension-logic-apps';
import ConnectionPanel from './panels/connectionPanel';

export async function openConnectionView(
context: IActionContext,
filePath: string,
methodName: string,
connectorName: string,
connectorType: string,
range: CodeSelection,
currentConnectionId: string
): Promise<void> {
const connectionPanel = new ConnectionPanel(
context,
filePath,
methodName,
connectorName,
connectorType,
range,
currentConnectionId
);
await connectionPanel.create();
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ vi.mock('../../../../utils/codeless/connection', () => ({
}));

// Import the module after mocks are set up
const mockModule = await import('../connectionView');
const mockModule = await import('../connectionPanel');

describe('ConnectionView - getConnectionKeyFromConnectionsJson', () => {
const testProjectPath = '/test/project';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const mockGetLogicAppProjectRoot = vi.fn();
const mockGetParametersFromFile = vi.fn();
const mockSaveWorkflowParameter = vi.fn();

vi.mock('../../../../utils/codeless/connection', () => ({
vi.mock('../../../../../utils/codeless/connection', () => ({
addConnectionData: mockAddConnectionData,
getConnectionsAndSettingsToUpdate: mockGetConnectionsAndSettingsToUpdate,
saveConnectionReferences: mockSaveConnectionReferences,
Expand All @@ -18,46 +18,45 @@ vi.mock('../../../../utils/codeless/connection', () => ({
getParametersFromFile: mockGetParametersFromFile,
}));

vi.mock('../../../../utils/codeless/parameter', () => ({
vi.mock('../../../../../utils/codeless/parameter', () => ({
saveWorkflowParameter: mockSaveWorkflowParameter,
}));

vi.mock('../../../../utils/codeless/common', () => ({
vi.mock('../../../../../utils/codeless/common', () => ({
cacheWebviewPanel: vi.fn(),
getAzureConnectorDetailsForLocalProject: vi.fn(),
removeWebviewPanelFromCache: vi.fn(),
}));

vi.mock('../../../../utils/codeless/startDesignTimeApi', () => ({
vi.mock('../../../../../utils/codeless/startDesignTimeApi', () => ({
startDesignTimeApi: vi.fn(),
}));

vi.mock('../../../../utils/codeless/artifacts', () => ({
vi.mock('../../../../../utils/codeless/artifacts', () => ({
getArtifactsInLocalProject: vi.fn(),
}));

vi.mock('../../../../utils/appSettings/localSettings', () => ({
vi.mock('../../../../../utils/appSettings/localSettings', () => ({
getLocalSettingsJson: vi.fn().mockResolvedValue({ Values: {} }),
}));

vi.mock('../../../../utils/bundleFeed', () => ({
vi.mock('../../../../../utils/bundleFeed', () => ({
getBundleVersionNumber: vi.fn().mockResolvedValue('1.0.0'),
}));

vi.mock('../../openDesigner/openDesignerBase', () => {
vi.mock('../../../designer/panels/designerPanel', () => {
return {
OpenDesignerBase: class {
DesignerPanel: class {
panelGroupKey = 'ls';
panelName = 'test';
context = { telemetry: { properties: {} } };
panel = { dispose: vi.fn() };
sendMsgToWebview = vi.fn();
panel = { dispose: vi.fn(), webview: { postMessage: vi.fn() } };
},
};
});

// ── Import the module under test (after all mocks are configured) ──────────
const mod = await import('../connectionView');
const mod = await import('../connectionPanel');
const OpenConnectionView = mod.default;

// ── Helpers ────────────────────────────────────────────────────────────────
Expand All @@ -79,16 +78,16 @@ function createInstance(): InstanceType<typeof OpenConnectionView> {
instance.connectorType = 'builtin';
instance.currentConnectionId = '';
instance.context = { telemetry: { properties: {} } };
instance.panel = { dispose: vi.fn() };
instance.panel = { dispose: vi.fn(), webview: { postMessage: vi.fn() } };
instance.panelMetadata = { azureDetails: {} };
// Override the private saveConnection so tests focus on handler orchestration
instance.saveConnection = mockSaveConnection;
return instance;
}

/** Helper to invoke the private _handleWebviewMsg via the prototype */
/** Helper to invoke the private handleWebviewMsg via the prototype */
function handleMsg(instance: any, message: any): Promise<void> {
return (OpenConnectionView.prototype as any)._handleWebviewMsg.call(instance, message);
return (OpenConnectionView.prototype as any).handleWebviewMsg.call(instance, message);
}

// ── Tests ──────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -209,3 +208,44 @@ describe('ConnectionView – insert_connection handles local and managed connect
});
});
});

describe('ConnectionPanel – getConnectionPanelMetadata reads localSettings after azureConnectorDetails', () => {
beforeEach(() => {
vi.clearAllMocks();
mockGetLogicAppProjectRoot.mockResolvedValue('/test/project');
mockGetConnectionsFromFile.mockResolvedValue('{}');
mockGetParametersFromFile.mockResolvedValue({});
});

it('reads localSettings after getAzureConnectorDetailsForLocalProject to avoid stale data from wizard writes', async () => {
const { getAzureConnectorDetailsForLocalProject } = await import('../../../../../utils/codeless/common');
const { getLocalSettingsJson } = await import('../../../../../utils/appSettings/localSettings');

let azureDetailsResolved = false;

vi.mocked(getAzureConnectorDetailsForLocalProject).mockImplementation(() => {
return new Promise((resolve) => {
setTimeout(() => {
azureDetailsResolved = true;
resolve({ accessToken: 'token', enabled: true, subscriptionId: 'sub-1', tenantId: 'tenant-1' } as any);
}, 50);
});
});
vi.mocked(getLocalSettingsJson).mockImplementation(async () => {
expect(azureDetailsResolved).toBe(true);
return { Values: { WORKFLOWS_TENANT_ID: 'tenant-1', WORKFLOWS_SUBSCRIPTION_ID: 'sub-1' } } as any;
});

const instance = Object.create(OpenConnectionView.prototype) as any;
instance.workflowFilePath = '/test/workflow.cs';
instance.panelName = 'test-panel';
instance.workflowName = '';
instance.context = { telemetry: { properties: {} } };
instance.schemaArtifacts = [];
instance.mapArtifacts = {};

await instance.getConnectionPanelMetadata();

expect(getLocalSettingsJson).toHaveBeenCalled();
});
});
Loading
Loading