Skip to content

Commit 9fd0b50

Browse files
authored
Integrate new DTL Editor (#1469)
1 parent 3134001 commit 9fd0b50

File tree

4 files changed

+86
-64
lines changed

4 files changed

+86
-64
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1739,8 +1739,8 @@
17391739
],
17401740
"customEditors": [
17411741
{
1742-
"viewType": "vscode-objectscript.rule",
1743-
"displayName": "Rule Editor",
1742+
"viewType": "vscode-objectscript.lowCode",
1743+
"displayName": "Low-Code Editor",
17441744
"selector": [
17451745
{
17461746
"filenamePattern": "*.cls"

src/extension.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ import {
135135
modifyProjectMetadata,
136136
} from "./commands/project";
137137
import { loadStudioColors, loadStudioSnippets } from "./commands/studioMigration";
138-
import { RuleEditorProvider } from "./providers/RuleEditorProvider";
138+
import { LowCodeEditorProvider } from "./providers/LowCodeEditorProvider";
139139
import { newFile, NewFileType } from "./commands/newFile";
140140
import { FileDecorationProvider } from "./providers/FileDecorationProvider";
141141
import { RESTDebugPanel } from "./commands/restDebugPanel";
@@ -1318,7 +1318,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
13181318
vscode.commands.registerCommand("vscode-objectscript.explorer.project.addWorkspaceFolderForProject", (node) =>
13191319
addWorkspaceFolderForProject(node)
13201320
),
1321-
vscode.window.registerCustomEditorProvider("vscode-objectscript.rule", new RuleEditorProvider(), {
1321+
vscode.window.registerCustomEditorProvider("vscode-objectscript.lowCode", new LowCodeEditorProvider(), {
13221322
webviewOptions: {
13231323
retainContextWhenHidden: true,
13241324
},

src/providers/RuleEditorProvider.ts src/providers/LowCodeEditorProvider.ts

+66-44
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
import * as vscode from "vscode";
2+
import { lt } from "semver";
23
import { AtelierAPI } from "../api";
34
import { loadChanges } from "../commands/compile";
45
import { StudioActions } from "../commands/studio";
56
import { clsLangId } from "../extension";
6-
import { cspApps, currentFile, handleError, openCustomEditors, outputChannel } from "../utils";
7+
import { currentFile, openCustomEditors, outputChannel } from "../utils";
78

8-
export class RuleEditorProvider implements vscode.CustomTextEditorProvider {
9-
private static readonly _webapp: string = "/ui/interop/rule-editor";
9+
export class LowCodeEditorProvider implements vscode.CustomTextEditorProvider {
10+
private readonly _rule: string = "/ui/interop/rule-editor";
11+
private readonly _dtl: string = "/ui/interop/dtl-editor";
1012

11-
private static _errorMessage(detail: string) {
13+
private _errorMessage(detail: string) {
1214
return vscode.window
13-
.showErrorMessage("Cannot open Rule Editor.", {
15+
.showErrorMessage("Cannot open Low-Code Editor.", {
1416
modal: true,
1517
detail,
1618
})
17-
.then(() => vscode.commands.executeCommand<void>("workbench.action.toggleEditorType"));
19+
.then(() => vscode.commands.executeCommand<void>("workbench.action.reopenTextEditor"));
1820
}
1921

2022
async resolveCustomTextEditor(
@@ -24,57 +26,66 @@ export class RuleEditorProvider implements vscode.CustomTextEditorProvider {
2426
): Promise<void> {
2527
// Check that document is a clean, well-formed class
2628
if (document.languageId != clsLangId) {
27-
return RuleEditorProvider._errorMessage(`${document.fileName} is not a class.`);
29+
return this._errorMessage(`${document.fileName} is not a class.`);
2830
}
2931
if (document.isUntitled) {
30-
return RuleEditorProvider._errorMessage(`${document.fileName} is untitled.`);
32+
return this._errorMessage(`${document.fileName} is untitled.`);
3133
}
3234
if (document.isDirty) {
33-
return RuleEditorProvider._errorMessage(`${document.fileName} is dirty.`);
35+
return this._errorMessage(`${document.fileName} is dirty.`);
3436
}
3537
const file = currentFile(document);
36-
if (file == null) {
37-
return RuleEditorProvider._errorMessage(`${document.fileName} is a malformed class definition.`);
38+
if (!file) {
39+
return this._errorMessage(`${document.fileName} is a malformed class definition.`);
40+
}
41+
if (!vscode.workspace.fs.isWritableFileSystem(document.uri.scheme)) {
42+
return this._errorMessage(`File system '${document.uri.scheme}' is read-only.`);
3843
}
3944

4045
const className = file.name.slice(0, -4);
4146
const api = new AtelierAPI(document.uri);
42-
const documentUriString = document.uri.toString();
43-
44-
// Check that the server has the webapp for the angular rule editor
45-
const cspAppsKey = `${api.serverId}:%SYS`.toLowerCase();
46-
let sysCspApps: string[] | undefined = cspApps.get(cspAppsKey);
47-
if (sysCspApps == undefined) {
48-
sysCspApps = await api.getCSPApps(false, "%SYS").then((data) => data.result.content || []);
49-
cspApps.set(cspAppsKey, sysCspApps);
47+
if (!api.active) {
48+
return this._errorMessage("Server connection is not active.");
5049
}
51-
if (!sysCspApps.includes(RuleEditorProvider._webapp)) {
52-
return RuleEditorProvider._errorMessage(`Server '${api.serverId}' does not support the Angular Rule Editor.`);
50+
if (lt(api.config.serverVersion, "2023.1.0")) {
51+
return this._errorMessage(
52+
"Opening a low-code editor in VS Code requires InterSystems IRIS version 2023.1 or above."
53+
);
5354
}
5455

55-
// Check that the class exists on the server and is a rule class
56-
const queryData = await api.actionQuery("SELECT Super FROM %Dictionary.ClassDefinition WHERE Name = ?", [
57-
className,
58-
]);
59-
if (
60-
queryData.result.content.length &&
61-
!queryData.result.content[0].Super.split(",").includes("Ens.Rule.Definition")
62-
) {
63-
// Class exists but is not a rule class
64-
return RuleEditorProvider._errorMessage(`${className} is not a rule definition class.`);
65-
} else if (queryData.result.content.length == 0) {
56+
// Check that the class exists on the server and is a rule or DTL class
57+
let webApp: string;
58+
const queryData = await api.actionQuery(
59+
"SELECT $LENGTH(rule.Name) AS Rule, $LENGTH(dtl.Name) AS DTL " +
60+
"FROM %Dictionary.ClassDefinition AS dcd " +
61+
"LEFT OUTER JOIN %Dictionary.ClassDefinition_SubclassOf('Ens.Rule.Definition') AS rule ON dcd.Name = rule.Name " +
62+
"LEFT OUTER JOIN %Dictionary.ClassDefinition_SubclassOf('Ens.DataTransformDTL') AS dtl ON dcd.Name = dtl.Name " +
63+
"WHERE dcd.Name = ?",
64+
[className]
65+
);
66+
if (queryData.result.content.length == 0) {
6667
// Class doesn't exist on the server
67-
return RuleEditorProvider._errorMessage(`Class ${className} does not exist on the server.`);
68+
return this._errorMessage(`${file.name} does not exist on the server.`);
69+
} else if (queryData.result.content[0].Rule) {
70+
webApp = this._rule;
71+
} else if (queryData.result.content[0].DTL) {
72+
if (lt(api.config.serverVersion, "2025.1.0")) {
73+
return this._errorMessage(
74+
"Opening the DTL editor in VS Code requires InterSystems IRIS version 2025.1 or above."
75+
);
76+
}
77+
webApp = this._dtl;
78+
} else {
79+
// Class exists but is not a rule or DTL class
80+
return this._errorMessage(`${className} is neither a rule definition class nor a DTL transformation class.`);
6881
}
6982

7083
// Add this document to the array of open custom editors
84+
const documentUriString = document.uri.toString();
7185
openCustomEditors.push(documentUriString);
7286

7387
// Initialize the webview
7488
const targetOrigin = `${api.config.https ? "https" : "http"}://${api.config.host}:${api.config.port}`;
75-
const iframeUri = `${targetOrigin}${api.config.pathPrefix}${
76-
RuleEditorProvider._webapp
77-
}/index.html?$NAMESPACE=${api.config.ns.toUpperCase()}&VSCODE=1&rule=${className}`;
7889
webviewPanel.webview.options = {
7990
enableScripts: true,
8091
localResourceRoots: [],
@@ -95,7 +106,9 @@ export class RuleEditorProvider implements vscode.CustomTextEditorProvider {
95106
</head>
96107
<body>
97108
<div id="content">
98-
<iframe id="editor" title="Rule Editor" src="${iframeUri}" width="100%" height="100%" frameborder="0"></iframe>
109+
<iframe id="editor" title="Low-Code Editor" src="${targetOrigin}${api.config.pathPrefix}${webApp}/index.html?$NAMESPACE=${api.config.ns.toUpperCase()}&VSCODE=1&${
110+
webApp == this._rule ? "rule" : "DTL"
111+
}=${className}" width="100%" height="100%" frameborder="0"></iframe>
99112
</div>
100113
<script>
101114
(function() {
@@ -177,13 +190,12 @@ export class RuleEditorProvider implements vscode.CustomTextEditorProvider {
177190
editorCompatible = true;
178191
return;
179192
case "badrule":
180-
RuleEditorProvider._errorMessage(event.reason);
193+
case "baddtl":
194+
this._errorMessage(event.reason);
181195
return;
182196
case "loaded":
183197
if (!editorCompatible) {
184-
RuleEditorProvider._errorMessage(
185-
"This server's Angular Rule Editor does not support embedding in VS Code."
186-
);
198+
this._errorMessage("This low-code editor does not support embedding in VS Code.");
187199
} else {
188200
// Editor is compatible so send the credentials
189201
webviewPanel.webview.postMessage({
@@ -258,15 +270,25 @@ export class RuleEditorProvider implements vscode.CustomTextEditorProvider {
258270
type: "revert",
259271
});
260272
}
261-
if (actionToProcess.errorText != "") {
273+
if (actionToProcess.errorText !== "") {
262274
outputChannel.appendLine(
263275
`\nError executing AfterUserAction '${event.label}':\n${actionToProcess.errorText}`
264276
);
265-
outputChannel.show(true);
277+
outputChannel.show();
266278
}
267279
}
268280
})
269-
.catch((error) => handleError(error, `Error executing AfterUserAction '${event.label}'.`));
281+
.catch((error) => {
282+
outputChannel.appendLine(`\nError executing AfterUserAction '${event.label}':`);
283+
if (error && error.errorText && error.errorText !== "") {
284+
outputChannel.appendLine(error.errorText);
285+
} else {
286+
outputChannel.appendLine(
287+
typeof error == "string" ? error : error instanceof Error ? error.message : JSON.stringify(error)
288+
);
289+
}
290+
outputChannel.show();
291+
});
270292
}
271293
});
272294
return;

src/providers/ObjectScriptCodeLensProvider.ts

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as vscode from "vscode";
2+
import { gte } from "semver";
23
import { clsLangId, config, intLangId, macLangId } from "../extension";
34
import { currentFile } from "../utils";
45
import { AtelierAPI } from "../api";
@@ -61,30 +62,29 @@ export class ObjectScriptCodeLensProvider implements vscode.CodeLensProvider {
6162
let [, xdataName] = xdataMatch;
6263
xdataName = xdataName.trim();
6364
let cmd: vscode.Command = undefined;
64-
if (
65-
(xdataName == "BPL" && superclasses.includes("Ens.BusinessProcessBPL")) ||
66-
(xdataName == "DTL" && superclasses.includes("Ens.DataTransformDTL"))
67-
) {
65+
if (xdataName == "BPL" && superclasses.includes("Ens.BusinessProcessBPL")) {
6866
cmd = {
69-
title: "Open Graphical Editor",
67+
title: "Open Low-Code Editor in Browser",
7068
command: "vscode-objectscript.openPathInBrowser",
71-
tooltip: "Open graphical editor in an external browser",
72-
arguments: [
73-
`/EnsPortal.${
74-
xdataName == "BPL" ? `BPLEditor.zen?BP=${className}.BPL` : `DTLEditor.zen?DT=${className}.DTL`
75-
}`,
76-
document.uri,
77-
],
69+
tooltip: "Open low-code editor in an external browser",
70+
arguments: [`/EnsPortal.BPLEditor.zen?BP=${className}.BPL`, document.uri],
7871
};
79-
} else if (xdataName == "RuleDefinition" && superclasses.includes("Ens.Rule.Definition")) {
72+
} else if (
73+
(xdataName == "RuleDefinition" &&
74+
superclasses.includes("Ens.Rule.Definition") &&
75+
gte(api.config.serverVersion, "2023.1.0")) ||
76+
(xdataName == "DTL" &&
77+
superclasses.includes("Ens.DataTransformDTL") &&
78+
gte(api.config.serverVersion, "2025.1.0"))
79+
) {
8080
cmd = {
81-
title: "Reopen in Graphical Editor",
81+
title: "Reopen in Low-Code Editor",
8282
command: "workbench.action.toggleEditorType",
83-
tooltip: "Replace text editor with graphical editor",
83+
tooltip: "Replace text editor with low-code editor",
8484
};
8585
} else if (xdataName == "KPI" && superclasses.includes("%DeepSee.KPI")) {
8686
cmd = {
87-
title: "Test KPI",
87+
title: "Test KPI in Browser",
8888
command: "vscode-objectscript.openPathInBrowser",
8989
tooltip: "Open testing page in an external browser",
9090
arguments: [`/${className}.cls`, document.uri],

0 commit comments

Comments
 (0)