Skip to content

Commit fd9fe32

Browse files
authored
Add command for creating a new KPI (#1237)
1 parent 9f38c46 commit fd9fe32

File tree

3 files changed

+124
-14
lines changed

3 files changed

+124
-14
lines changed

package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@
299299
"command": "vscode-objectscript.newFile.dtl",
300300
"when": "false"
301301
},
302+
{
303+
"command": "vscode-objectscript.newFile.kpi",
304+
"when": "false"
305+
},
302306
{
303307
"command": "vscode-objectscript.importLocalFilesServerSide",
304308
"when": "false"
@@ -602,6 +606,11 @@
602606
}
603607
],
604608
"file/newFile": [
609+
{
610+
"command": "vscode-objectscript.newFile.kpi",
611+
"when": "workspaceFolderCount != 0",
612+
"group": "file"
613+
},
605614
{
606615
"command": "vscode-objectscript.newFile.businessOperation",
607616
"when": "workspaceFolderCount != 0",
@@ -1067,6 +1076,11 @@
10671076
"command": "vscode-objectscript.loadStudioColors",
10681077
"title": "Load Studio Syntax Colors"
10691078
},
1079+
{
1080+
"category": "ObjectScript",
1081+
"command": "vscode-objectscript.newFile.kpi",
1082+
"title": "Business Intelligence KPI"
1083+
},
10701084
{
10711085
"category": "ObjectScript",
10721086
"command": "vscode-objectscript.newFile.businessOperation",

src/commands/newFile.ts

Lines changed: 109 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ interface InputBoxStepOptions {
1515
type: "inputBox";
1616
title: string;
1717
placeholder?: string;
18+
prompt?: string;
1819
validateInput?(value: string): string | undefined | Promise<string | undefined>;
1920
}
2021

@@ -50,6 +51,7 @@ async function multiStepInput(steps: InputStepOptions[]): Promise<string[] | und
5051
inputBox.totalSteps = steps.length;
5152
inputBox.buttons = step > 0 ? [vscode.QuickInputButtons.Back] : [];
5253
inputBox.placeholder = stepOptions.placeholder;
54+
inputBox.prompt = stepOptions.prompt;
5355
inputBox.title = stepOptions.title;
5456
if (results[step] != undefined) {
5557
// Restore the past input
@@ -221,6 +223,7 @@ export enum NewFileType {
221223
BPL = "Business Process",
222224
DTL = "Data Transformation",
223225
Rule = "Business Rule",
226+
KPI = "Business Intelligence KPI",
224227
}
225228

226229
interface RuleAssistClasses {
@@ -264,16 +267,18 @@ export async function newFile(type: NewFileType): Promise<void> {
264267
api = undefined;
265268
}
266269

267-
// Check if we're connected to an Interoperability namespace
268-
const ensemble: boolean = api
269-
? await api.getNamespace().then((data) => data.result.content.features[0].enabled)
270-
: true;
271-
if (!ensemble) {
272-
vscode.window.showErrorMessage(
273-
`Workspace folder '${wsFolder.name}' is not connected to an Interoperability namespace.`,
274-
"Dismiss"
275-
);
276-
return;
270+
if (type != NewFileType.KPI) {
271+
// Check if we're connected to an Interoperability namespace
272+
const ensemble: boolean = api
273+
? await api.getNamespace().then((data) => data.result.content.features[0].enabled)
274+
: true;
275+
if (!ensemble) {
276+
vscode.window.showErrorMessage(
277+
`Workspace folder '${wsFolder.name}' is not connected to an Interoperability namespace.`,
278+
"Dismiss"
279+
);
280+
return;
281+
}
277282
}
278283

279284
const inputSteps: InputStepOptions[] = [];
@@ -282,6 +287,7 @@ export async function newFile(type: NewFileType): Promise<void> {
282287
let classes: string[] = [];
283288
let ruleAssists: RuleAssistClasses = {};
284289
let dtlClassQPItems: vscode.QuickPickItem[] = [];
290+
let serverResources: vscode.QuickPickItem[] = [];
285291
if (api) {
286292
const classesPromise: Promise<string[]> = api
287293
.actionQuery("SELECT Name FROM %Dictionary.ClassDefinition", [])
@@ -377,6 +383,20 @@ export async function newFile(type: NewFileType): Promise<void> {
377383
}),
378384
classesPromise,
379385
]);
386+
} else if (type == NewFileType.KPI) {
387+
// Get a list of classes on the server to validate the name
388+
classes = await classesPromise;
389+
// Get a list of server resources
390+
const originalNs = api.ns;
391+
api.setNamespace("%SYS");
392+
serverResources = await api
393+
.actionQuery(
394+
"SELECT Name AS label, Description AS detail, 'Public Permission: '||PublicPermission AS description FROM Security.Resources_List()",
395+
[]
396+
)
397+
.then((data) => data.result.content)
398+
.catch(() => []);
399+
api.setNamespace(originalNs);
380400
} else {
381401
// Get a list of classes on the server to validate the name
382402
classes = await classesPromise;
@@ -466,7 +486,7 @@ Parameter INVOCATION = "${invocation}";
466486
/// for tips on how to implement operation methods.
467487
Method SampleCall(pRequest As Ens.Request, Output pResponse As Ens.Response) As %Status
468488
{
469-
Quit $$$ERROR($$$NotImplemented)
489+
Return $$$ERROR($$$NotImplemented)
470490
}
471491
472492
XData MessageMap
@@ -508,7 +528,7 @@ Parameter ADAPTER = "${adapter}";
508528
/// for tips on how to implement this method.
509529
Method OnProcessInput(pInput As %RegisteredObject, pOutput As %RegisteredObject) As %Status
510530
{
511-
Quit $$$ERROR($$$NotImplemented)
531+
Return $$$ERROR($$$NotImplemented)
512532
}
513533
514534
}
@@ -572,7 +592,7 @@ Class ${cls} Extends Ens.BusinessProcess [ ClassType = persistent ]
572592
/// for tips on how to implement this method.
573593
Method OnRequest(pRequest As Ens.Request, Output pResponse As Ens.Response) As %Status
574594
{
575-
Quit $$$ERROR($$$NotImplemented)
595+
Return $$$ERROR($$$NotImplemented)
576596
}
577597
578598
}
@@ -667,7 +687,7 @@ Class ${cls} Extends Ens.DataTransform
667687
/// for tips on how to implement this method.
668688
ClassMethod Transform(source As ${sourceCls}, ByRef target As ${targetCls}) As %Status
669689
{
670-
Quit $$$ERROR($$$NotImplemented)
690+
Return $$$ERROR($$$NotImplemented)
671691
}
672692
673693
}
@@ -749,6 +769,81 @@ XData RuleDefinition [ XMLNamespace = "http://www.intersystems.com/rule" ]
749769
</ruleDefinition>
750770
}
751771
772+
}
773+
`;
774+
} else if (type == NewFileType.KPI) {
775+
// Create the prompt for the name, domain, resource, and type
776+
inputSteps.push(
777+
{
778+
type: "inputBox",
779+
title: "Name",
780+
placeholder: "MyFolder/MyKPI",
781+
prompt: "Logical name of the KPI.",
782+
},
783+
{
784+
type: "inputBox",
785+
title: "Domain",
786+
prompt: "Localization domain to which this KPI belongs.",
787+
},
788+
serverResources.length
789+
? {
790+
type: "quickPick",
791+
title: "Resource",
792+
items: serverResources,
793+
}
794+
: {
795+
type: "inputBox",
796+
title: "Resource",
797+
prompt: "Resource that secures this KPI.",
798+
},
799+
{
800+
type: "quickPick",
801+
title: "Source Type",
802+
items: [{ label: "mdx" }, { label: "sql" }, { label: "manual" }],
803+
}
804+
);
805+
806+
// Prompt the user
807+
const results = await multiStepInput(inputSteps);
808+
if (!results) {
809+
return;
810+
}
811+
cls = results[0];
812+
const [, desc, kpiName, kpiDomain, kpiResource, kpiType] = results;
813+
814+
// Generate the file's content
815+
clsContent = `
816+
${typeof desc == "string" ? "/// " + desc.replace(/\n/g, "\n/// ") : ""}
817+
Class ${cls} Extends %DeepSee.KPI
818+
{
819+
820+
Parameter DOMAIN = "${kpiDomain}";
821+
822+
Parameter RESOURCE = "${kpiResource}";
823+
824+
/// This XData definition defines the KPI.
825+
XData KPI [ XMLNamespace = "http://www.intersystems.com/deepsee/kpi" ]
826+
{
827+
<kpi xmlns="http://www.intersystems.com/deepsee/kpi" name="${kpiName}" sourceType="${kpiType}" >
828+
</kpi>
829+
}
830+
831+
/// Notification that this KPI is being executed.
832+
/// This is a good place to override properties, such as range and threshold.
833+
Method %OnLoadKPI() As %Status
834+
{
835+
Return $$$OK
836+
}
837+
838+
/// This callback is invoked from a dashboard when an action defined by this dashboard is invoked.
839+
ClassMethod %OnDashboardAction(pAction As %String, pContext As %ZEN.proxyObject) As %Status
840+
{
841+
#; pAction is the name of the action (as defined in the XML list).
842+
#; pContext contains information from the client
843+
#; and can be used to return information.
844+
Return $$$OK
845+
}
846+
752847
}
753848
`;
754849
}

src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
12911291
newFile(NewFileType.BusinessService)
12921292
),
12931293
vscode.commands.registerCommand("vscode-objectscript.newFile.dtl", () => newFile(NewFileType.DTL)),
1294+
vscode.commands.registerCommand("vscode-objectscript.newFile.kpi", () => newFile(NewFileType.KPI)),
12941295
vscode.window.registerFileDecorationProvider(fileDecorationProvider),
12951296
vscode.workspace.onDidOpenTextDocument((doc) => !doc.isUntitled && fileDecorationProvider.emitter.fire(doc.uri)),
12961297
vscode.commands.registerCommand("vscode-objectscript.importLocalFilesServerSide", (wsFolderUri) => {

0 commit comments

Comments
 (0)