Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -97,6 +97,7 @@ export interface MIVisualizerAPI {
updatePomValues: (params: UpdatePomValuesRequest) => Promise<boolean>;
updateConfigFileValues: (params: UpdateConfigValuesRequest) => Promise<boolean>;
updateConnectorDependencies: () => Promise<string>;
refetchIntegrationProjectDependencies: () => Promise<string>;
getDependencyStatusList: () => Promise<DependencyStatusResponse>;
updateDependenciesFromOverview: (params: UpdateDependenciesRequest) => Promise<boolean>;
importOpenAPISpec: (params: ImportOpenAPISpecRequest) => Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export const updatePomValues: RequestType<UpdatePomValuesRequest, boolean> = { m
export const updateConfigFileValues: RequestType<UpdateConfigValuesRequest, boolean> = { method: `${_preFix}/updateConfigFileValues` };
export const updateConnectorDependencies: RequestType<void, string> = { method: `${_preFix}/updateConnectorDependencies` };
export const getDependencyStatusList: RequestType<void, DependencyStatusResponse> = { method: `${_preFix}/getDependencyStatusList` };
export const refetchIntegrationProjectDependencies: RequestType<void, string> = { method: `${_preFix}/refetchIntegrationProjectDependencies` };
export const updateDependenciesFromOverview: RequestType<UpdateDependenciesRequest, boolean> = { method: `${_preFix}/updateDependenciesFromOverview` };
export const getProjectSetupDetails: RequestType<void, SetupDetails> = { method: `${_preFix}/getProjectSetupDetails` };
export const updateRuntimeVersionsInPom: RequestType<string, boolean> = { method: `${_preFix}/updateRuntimeVersionsInPom` };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,14 @@ export const ButtonGroup: React.FC<ButtonroupProps> = ({
<div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
{connectorDetails &&
<>
<DeleteIconContainer
onClick={() => onDelete(title, connectorDetails.artifactId, connectorDetails.version,
iconUri, connectorDetails.connectorPath)}
className="delete-icon">
<Codicon name="trash" iconSx={{ fontSize: 20 }} />
</DeleteIconContainer>
{onDelete &&
<DeleteIconContainer
onClick={() => onDelete(title, connectorDetails.artifactId, connectorDetails.version,
iconUri, connectorDetails.connectorPath)}
className="delete-icon">
<Codicon name="trash" iconSx={{ fontSize: 20 }} />
</DeleteIconContainer>
}
{connectorDetails.isBallerinaModule &&
<RefreshIconContainer
onClick={() => onRefresh(title, connectorDetails.ballerinaModulePath)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,20 @@ export function Mediators(props: MediatorProps) {
setIsLoading(false);
}

/**
* Determines whether a connector belongs to the current project.
*
* @param connectorName - The name (or display name) of the connector to check.
* @returns `true` if the connector is local to the current project, `false` otherwise.
*/
const isLocalConnector = (connectorName: string): boolean => {
if (!localConnectors) return false;
const connector = localConnectors.find((c: any) =>
c.displayName ? c.displayName === connectorName : c.name?.toLowerCase() === connectorName.toLowerCase()
);
return connector?.fromProject === true;
};

const firstCharToUpperCaseForDefault = (name: string) => {
if (INBUILT_MODULES.includes(name)) {
return FirstCharToUpperCase(name);
Expand Down Expand Up @@ -353,7 +367,7 @@ export function Mediators(props: MediatorProps) {
connectorDetails={values["isConnector"] ?
{ artifactId: values["artifactId"], version: values["version"], connectorPath: values["connectorPath"],
isBallerinaModule: values["isBallerinaModule"], ballerinaModulePath: values["ballerinaModulePath"] } : undefined}
onDelete={deleteConnector}
onDelete={isLocalConnector(key) ? deleteConnector : undefined}
onRefresh={refreshConnector}
versionTag={values.version}
disableGrid={values.isSupportCategories}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,20 @@ export interface ArtifactType {
artifactFolder: string;
}

export interface ConflictingDependency {
groupId: string;
artifactId: string;
version: string;
conflictingArtifacts: string[];
conflictingConnectors: string[];
}

export interface LoadDependentResourcesResponse {
status: 'SUCCESS' | 'NO_DEPS_FOUND' | 'ERROR' | 'CONFLICT';
message: string;
conflictingDependencies?: ConflictingDependency[];
}

export class ExtendedLanguageClient extends LanguageClient {

constructor(id: string, name: string, private projectUri: string, serverOptions: ServerOptions, clientOptions: LanguageClientOptions) {
Expand Down Expand Up @@ -368,7 +382,11 @@ export class ExtendedLanguageClient extends LanguageClient {
return this.sendRequest('synapse/updateConnectorDependencies');
}

async loadDependentCAppResources(): Promise<string> {
async refetchIntegrationProjectDependencies(): Promise<string> {
return this.sendRequest('synapse/refetchIntegrationProjectDependencies');
}

async loadDependentCAppResources(): Promise<LoadDependentResourcesResponse> {
return this.sendRequest('synapse/loadDependentResources');
}

Expand Down
6 changes: 3 additions & 3 deletions workspaces/mi/mi-extension/src/lang-client/activator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { log } from '../util/logger';
import { getJavaHomeFromConfig, getProjectSetupDetails, isMISetup, isJavaSetup } from '../util/onboardingUtils';
import { SELECTED_SERVER_PATH } from '../debugger/constants';
import { extension } from '../MIExtensionContext';
import { extractCAppDependenciesAsProjects } from '../visualizer/activate';
import { loadCAppResources } from '../visualizer/activate';
import vscode from "vscode";
const exec = util.promisify(require('child_process').exec);

Expand Down Expand Up @@ -330,8 +330,8 @@ export class MILanguageClient {
this.languageClient = new ExtendedLanguageClient('synapseXML', 'Synapse Language Server', this.projectUri,
serverOptions, clientOptions);
await this.languageClient.start();
await extractCAppDependenciesAsProjects(this.projectUri);
await this.languageClient?.loadDependentCAppResources();
await this.languageClient?.updateConnectorDependencies();
await loadCAppResources(this.projectUri, this.languageClient!);

//Setup autoCloseTags
let tagProvider: (document: TextDocument, position: Position) => Thenable<AutoCloseResult> = (document: TextDocument, position: Position) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import {
UpdateConfigValuesRequest,
importOpenAPISpec,
updateConnectorDependencies,
refetchIntegrationProjectDependencies,
ImportOpenAPISpecRequest,
updateRuntimeVersionsInPom,
getProjectSetupDetails,
Expand Down Expand Up @@ -138,6 +139,7 @@ export function registerMiVisualizerRpcHandlers(messenger: Messenger, projectUri
messenger.onRequest(updatePomValues, (args: UpdatePomValuesRequest) => rpcManger.updatePomValues(args));
messenger.onRequest(updateConfigFileValues, (args: UpdateConfigValuesRequest) => rpcManger.updateConfigFileValues(args));
messenger.onRequest(updateConnectorDependencies, () => rpcManger.updateConnectorDependencies());
messenger.onRequest(refetchIntegrationProjectDependencies, () => rpcManger.refetchIntegrationProjectDependencies());
messenger.onRequest(getDependencyStatusList, () => rpcManger.getDependencyStatusList());
messenger.onRequest(updateDependenciesFromOverview, (args: UpdateDependenciesRequest) => rpcManger.updateDependenciesFromOverview(args));
messenger.onRequest(importOpenAPISpec, (args: ImportOpenAPISpecRequest) => rpcManger.importOpenAPISpec(args));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ import { extension } from "../../MIExtensionContext";
import { DebuggerConfig } from "../../debugger/config";
import { history } from "../../history";
import { getStateMachine, navigate, openView, refreshUI } from "../../stateMachine";
import { goToSource, handleOpenFile, appendContent, selectFolderDialog } from "../../util/fileOperations";
import { formatAndSavePomDocument, goToSource, handleOpenFile, appendContent, selectFolderDialog } from "../../util/fileOperations";
import { openPopupView } from "../../stateMachinePopup";
import { SwaggerServer } from "../../swagger/server";
import { log, outputChannel } from "../../util/logger";
Expand All @@ -90,7 +90,7 @@ import { copy } from 'fs-extra';
const fs = require('fs');
import { TextEdit } from "vscode-languageclient";
import { downloadJavaFromMI, downloadMI, getProjectSetupDetails, getSupportedMIVersionsHigherThan, setPathsInWorkSpace, updateRuntimeVersionsInPom, getMIVersionFromPom } from '../../util/onboardingUtils';
import { extractCAppDependenciesAsProjects } from "../../visualizer/activate";
import { extractCAppDependenciesAsProjects, loadCAppResources } from "../../visualizer/activate";
import { findMultiModuleProjectsInWorkspaceDir } from "../../util/migrationUtils";
import { MILanguageClient } from "../../lang-client/activator";

Expand Down Expand Up @@ -217,15 +217,22 @@ export class MiVisualizerRpcManager implements MIVisualizerAPI {
const updateDependenciesResult = await langClient?.updateConnectorDependencies();
if (!updateDependenciesResult.toLowerCase().startsWith("success")) {
const connectorsNotDownloaded: string[] = [];
const connectorsFromIntegrationProjectDeps: string[] = [];
const unavailableDependencies: string[] = [];
const missingDescriptorDependencies: string[] = [];
const versioningMismatchDependencies: string[] = [];

// Extract connectors not downloaded
connectorsNotDownloaded.push(...extractDependenciesFromError(
updateDependenciesResult,
/Some connectors were not downloaded:\s*(.+?)(?:\.\s+(?:[A-Z]|$)|$)/
));

// Extract connectors provided by integration project dependencies
connectorsFromIntegrationProjectDeps.push(...extractDependenciesFromError(
updateDependenciesResult,
/Following connectors are provided by integration project dependencies and cannot be downloaded:\s*(.+?)(?:\.\s+(?:[A-Z]|$)|$)/
));

// Extract unavailable integration project dependencies
unavailableDependencies.push(...extractDependenciesFromError(
Expand All @@ -247,6 +254,7 @@ export class MiVisualizerRpcManager implements MIVisualizerAPI {

const allFailedDependencies = [
...connectorsNotDownloaded,
...connectorsFromIntegrationProjectDeps,
...unavailableDependencies,
...missingDescriptorDependencies,
...versioningMismatchDependencies
Expand Down Expand Up @@ -285,6 +293,8 @@ export class MiVisualizerRpcManager implements MIVisualizerAPI {
let warningMessage = "";
if (connectorsNotDownloaded.includes(dependencyString)) {
warningMessage = "Connector downloading failed.";
} else if (connectorsFromIntegrationProjectDeps.includes(dependencyString)) {
warningMessage = "This connector is provided by an integration project dependency and cannot be downloaded separately.";
} else if (unavailableDependencies.includes(dependencyString)) {
warningMessage = "Dependency downloading failed.";
} else if (missingDescriptorDependencies.includes(dependencyString)) {
Expand All @@ -306,19 +316,8 @@ export class MiVisualizerRpcManager implements MIVisualizerAPI {
}
}
}

try {
await extractCAppDependenciesAsProjects(this.projectUri);
const loadResult = await langClient?.loadDependentCAppResources();
if (loadResult.startsWith("DUPLICATE ARTIFACTS")) {
await window.showWarningMessage(
loadResult,
{ modal: true }
);
}
} catch (error) {
console.error("Error extracting CApp dependencies:", error);
}

await loadCAppResources(this.projectUri, langClient);
resolve(reloadDependenciesResult);
});
}
Expand Down Expand Up @@ -431,6 +430,13 @@ export class MiVisualizerRpcManager implements MIVisualizerAPI {
});
}

async refetchIntegrationProjectDependencies(): Promise<string> {
const langClient = await MILanguageClient.getInstance(this.projectUri);
const res = await langClient.refetchIntegrationProjectDependencies();
await loadCAppResources(this.projectUri, langClient);
return res;
}

async updateDependenciesFromOverview(params: UpdateDependenciesRequest): Promise<boolean> {
return new Promise(async (resolve) => {
const langClient = await MILanguageClient.getInstance(this.projectUri);
Expand Down Expand Up @@ -845,32 +851,17 @@ export class MiVisualizerRpcManager implements MIVisualizerAPI {

edit.replace(Uri.file(pomPath), range, content);
}
const success = await workspace.applyEdit(edit);
// Make sure to save the document after applying the edits
if (success) {
const document = await workspace.openTextDocument(pomPath);
await document.save();
// Format the pom content
const editorConfig = workspace.getConfiguration('editor');
let formattingOptions = {
tabSize: editorConfig.get("tabSize") ?? 4,
insertSpaces: editorConfig.get("insertSpaces") ?? false,
trimTrailingWhitespace: editorConfig.get("trimTrailingWhitespace") ?? false
};
const edits = await vscode.commands.executeCommand<vscode.TextEdit[]>("vscode.executeFormatDocumentProvider",
vscode.Uri.file(pomPath), formattingOptions);
if (edits && edits.length > 0) {
const edit = new vscode.WorkspaceEdit();
edit.set(vscode.Uri.file(pomPath), edits);
await vscode.workspace.applyEdit(edit);
await vscode.workspace.openTextDocument(pomPath).then(doc => doc.save());
}
if (getStateMachine(this.projectUri).context().view === MACHINE_VIEW.Overview) {
refreshUI(this.projectUri);
}
} else {
if (!await workspace.applyEdit(edit)) {
throw new Error("Failed to apply edits to pom.xml");
}

const document = await workspace.openTextDocument(pomPath);
await document.save();
await formatAndSavePomDocument(pomPath);

if (getStateMachine(this.projectUri).context().view === MACHINE_VIEW.Overview) {
refreshUI(this.projectUri);
}
}

async importOpenAPISpec(params: ImportOpenAPISpecRequest): Promise<void> {
Expand Down
22 changes: 22 additions & 0 deletions workspaces/mi/mi-extension/src/util/fileOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1156,3 +1156,25 @@ export function zipProjectFolder(sourceFolder: string, targetFolder: string): st

return targetZipPath;
}

export async function formatAndSavePomDocument(pomPath: string): Promise<void> {
const editorConfig = workspace.getConfiguration('editor');
const formattingOptions = {
tabSize: editorConfig.get("tabSize") ?? 4,
insertSpaces: editorConfig.get("insertSpaces") ?? false,
trimTrailingWhitespace: editorConfig.get("trimTrailingWhitespace") ?? false
};
try {
const edits = await commands.executeCommand<TextEdit[]>(
"vscode.executeFormatDocumentProvider", Uri.file(pomPath), formattingOptions
);
if (edits && edits.length > 0) {
const formatEdit = new WorkspaceEdit();
formatEdit.set(Uri.file(pomPath), edits);
await workspace.applyEdit(formatEdit);
}
} catch {
// Formatter unavailable or not ready — skip formatting, proceed to save
}
await workspace.openTextDocument(pomPath).then(doc => doc.save());
}
Loading
Loading