codenotch-react 1.0.54 → 1.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{auml.d.ts → components/Auml.d.ts} +2 -2
- package/dist/components/Auml.d.ts.map +1 -0
- package/dist/{auml.js → components/Auml.js} +2 -2
- package/dist/components/CodeEditor.d.ts +27 -0
- package/dist/components/CodeEditor.d.ts.map +1 -0
- package/dist/components/CodeEditor.js +170 -0
- package/dist/core/ProcessUtils.d.ts +9 -0
- package/dist/core/ProcessUtils.d.ts.map +1 -0
- package/dist/core/ProcessUtils.js +65 -0
- package/dist/core/SignalR.d.ts +30 -0
- package/dist/core/SignalR.d.ts.map +1 -0
- package/dist/core/SignalR.js +245 -0
- package/dist/index.d.ts +6 -41
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +109 -63
- package/dist/models/Codenotch.d.ts +38 -0
- package/dist/models/Codenotch.d.ts.map +1 -0
- package/dist/models/Codenotch.js +2 -0
- package/dist/models/Misc.d.ts +18 -0
- package/dist/models/Misc.d.ts.map +1 -0
- package/dist/models/Misc.js +2 -0
- package/package.json +5 -2
- package/dist/auml.d.ts.map +0 -1
|
@@ -14,7 +14,7 @@ export declare class Auml extends React.Component<IAumlProps, IAumlState> {
|
|
|
14
14
|
componentWillUnmount(): void;
|
|
15
15
|
progress(s: SpaRenderStatus): void;
|
|
16
16
|
getLogo(): React.JSX.Element;
|
|
17
|
-
getMode(theme: boolean | undefined): "
|
|
17
|
+
getMode(theme: boolean | undefined): "light" | "dark";
|
|
18
18
|
retrieveInputs(): {
|
|
19
19
|
[k: string]: string;
|
|
20
20
|
};
|
|
@@ -26,4 +26,4 @@ export declare class Auml extends React.Component<IAumlProps, IAumlState> {
|
|
|
26
26
|
refreshExpiredToken(): Promise<void>;
|
|
27
27
|
}
|
|
28
28
|
export {};
|
|
29
|
-
//# sourceMappingURL=
|
|
29
|
+
//# sourceMappingURL=Auml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auml.d.ts","sourceRoot":"","sources":["../../src/components/Auml.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,0EAA0E,CAAC;AAS3G,UAAU,UAAU;IAChB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,UAAU;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAED,qBAAa,IAAK,SAAQ,KAAK,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC;IAE7D,kBAAkB,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;gBAEnC,KAAK,EAAE,UAAU;IAQ7B,iBAAiB;IAmCjB,oBAAoB;IAQpB,QAAQ,CAAC,CAAC,EAAE,eAAe;IAO3B,OAAO;IAYP,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS;IAclC,cAAc;;;IAMd,wBAAwB,IAAI,MAAM,GAAG,IAAI;IAoCzC,2BAA2B,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM;IAO/D,QAAQ,CAAC,EAAE,EAAE,MAAM;IAmBnB,QAAQ,CAAC,KAAK,EAAE,MAAM;IAsBtB,MAAM;IA2CA,mBAAmB;CAqC5B"}
|
|
@@ -150,12 +150,12 @@ export interface UserInfo {
|
|
|
150
150
|
aumlManifest = appManifestObj.auml;
|
|
151
151
|
}
|
|
152
152
|
catch { }
|
|
153
|
-
return
|
|
153
|
+
return react_1.default.createElement("div", { className: "app" },
|
|
154
154
|
react_1.default.createElement(SpaRenderWithBrowserRouter_1.SpaRenderWithBrowserRouter, { appDescription: this.props.value, tenant: tenant, serviceName: serviceName, packageVersions: packageVersions, user: user, languages: languages, onProgress: (s) => this.progress(s), input: inputs, theme: theme, manifest: aumlManifest, inspectorEnabled: this.state.inspectorEnabled, children: [] }),
|
|
155
155
|
!this.state.loaded &&
|
|
156
156
|
react_1.default.createElement("div", { className: `app-loading ${this.getMode(theme)}` },
|
|
157
157
|
this.getLogo(),
|
|
158
|
-
react_1.default.createElement("i", { className: "fas fa-circle-notch fa-spin" })))
|
|
158
|
+
react_1.default.createElement("i", { className: "fas fa-circle-notch fa-spin" })));
|
|
159
159
|
}
|
|
160
160
|
async refreshExpiredToken() {
|
|
161
161
|
console.log("Token will expire soon, requesting a new one...");
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface ICodeEditorProps {
|
|
3
|
+
style?: React.CSSProperties;
|
|
4
|
+
className?: string;
|
|
5
|
+
value?: string;
|
|
6
|
+
language?: string;
|
|
7
|
+
readOnly?: boolean;
|
|
8
|
+
onChange?: (value: string) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Light version of Monaco Editor in an iframe.
|
|
12
|
+
*/
|
|
13
|
+
export default class CodeEditor extends React.Component<ICodeEditorProps> {
|
|
14
|
+
private isIframeReady;
|
|
15
|
+
private onChangeTimeoutHandle;
|
|
16
|
+
refFrame: React.RefObject<HTMLIFrameElement>;
|
|
17
|
+
setValue(value: string): void;
|
|
18
|
+
componentDidMount(): void;
|
|
19
|
+
componentWillUnmount(): void;
|
|
20
|
+
componentDidUpdate(prevProps: ICodeEditorProps): void;
|
|
21
|
+
private handleMessage;
|
|
22
|
+
private postToIframe;
|
|
23
|
+
private writeIframe;
|
|
24
|
+
render(): React.JSX.Element;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=CodeEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../src/components/CodeEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,gBAAgB;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC;IACrE,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,qBAAqB,CAAa;IAC1C,QAAQ,qCAAwC;IAEhD,QAAQ,CAAC,KAAK,EAAE,MAAM;IAStB,iBAAiB,IAAI,IAAI;IAKzB,oBAAoB,IAAI,IAAI;IAI5B,kBAAkB,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI;IAoBrD,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;IA4EnB,MAAM;CAeT"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const __1 = require("..");
|
|
8
|
+
/**
|
|
9
|
+
* Light version of Monaco Editor in an iframe.
|
|
10
|
+
*/
|
|
11
|
+
class CodeEditor extends react_1.default.Component {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
this.isIframeReady = false;
|
|
15
|
+
this.onChangeTimeoutHandle = null;
|
|
16
|
+
this.refFrame = react_1.default.createRef();
|
|
17
|
+
}
|
|
18
|
+
setValue(value) {
|
|
19
|
+
if (this.isIframeReady) {
|
|
20
|
+
this.postToIframe({
|
|
21
|
+
type: 'update',
|
|
22
|
+
value: value,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
componentDidMount() {
|
|
27
|
+
window.addEventListener('message', this.handleMessage);
|
|
28
|
+
this.writeIframe();
|
|
29
|
+
}
|
|
30
|
+
componentWillUnmount() {
|
|
31
|
+
window.removeEventListener('message', this.handleMessage);
|
|
32
|
+
}
|
|
33
|
+
componentDidUpdate(prevProps) {
|
|
34
|
+
const changed = (prevProps.value !== this.props.value ||
|
|
35
|
+
prevProps.language !== this.props.language ||
|
|
36
|
+
prevProps.readOnly !== this.props.readOnly);
|
|
37
|
+
if (changed && this.isIframeReady) {
|
|
38
|
+
let isDark = (0, __1.useCodenotch)().getTheme() === 'dark';
|
|
39
|
+
this.postToIframe({
|
|
40
|
+
type: 'update',
|
|
41
|
+
value: this.props.value ?? '',
|
|
42
|
+
language: this.props.language || 'plaintext',
|
|
43
|
+
readOnly: !!this.props.readOnly,
|
|
44
|
+
theme: isDark ? 'vs-dark' : 'vs'
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
handleMessage(event) {
|
|
49
|
+
const data = event.data;
|
|
50
|
+
if (!data || typeof data !== 'object')
|
|
51
|
+
return;
|
|
52
|
+
if (data.__from !== 'MonacoIframe')
|
|
53
|
+
return;
|
|
54
|
+
switch (data.type) {
|
|
55
|
+
case 'ready': {
|
|
56
|
+
this.isIframeReady = true;
|
|
57
|
+
// send initial payload
|
|
58
|
+
this.postToIframe({
|
|
59
|
+
type: 'init',
|
|
60
|
+
value: this.props.value ?? '',
|
|
61
|
+
language: this.props.language || 'plaintext',
|
|
62
|
+
readOnly: !!this.props.readOnly,
|
|
63
|
+
theme: (0, __1.useCodenotch)().getTheme() === 'dark' ? 'vs-dark' : 'vs'
|
|
64
|
+
});
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 'change': {
|
|
68
|
+
const next = String(data.value ?? '');
|
|
69
|
+
if (this.onChangeTimeoutHandle) {
|
|
70
|
+
clearTimeout(this.onChangeTimeoutHandle);
|
|
71
|
+
}
|
|
72
|
+
this.onChangeTimeoutHandle = setTimeout(() => {
|
|
73
|
+
this.props.onChange?.(next);
|
|
74
|
+
}, 300);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
;
|
|
80
|
+
postToIframe(message) {
|
|
81
|
+
const w = this.refFrame.current?.contentWindow;
|
|
82
|
+
if (!w)
|
|
83
|
+
return;
|
|
84
|
+
w.postMessage({ __from: 'MonacoIframe', ...message }, '*');
|
|
85
|
+
}
|
|
86
|
+
writeIframe() {
|
|
87
|
+
const iframe = this.refFrame.current;
|
|
88
|
+
if (!iframe)
|
|
89
|
+
return;
|
|
90
|
+
const vsBase = 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs';
|
|
91
|
+
const html = `<!DOCTYPE html>
|
|
92
|
+
<html>
|
|
93
|
+
<head>
|
|
94
|
+
<meta charset="utf-8" />
|
|
95
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
96
|
+
<style>
|
|
97
|
+
html, body, #container { height: 100%; width: 100%; margin: 0; padding: 0; overflow: hidden; }
|
|
98
|
+
</style>
|
|
99
|
+
<script>
|
|
100
|
+
(function(){
|
|
101
|
+
var vsBase = ${JSON.stringify(vsBase)};
|
|
102
|
+
// AMD loader
|
|
103
|
+
var s = document.createElement('script');
|
|
104
|
+
s.src = vsBase + '/loader.js';
|
|
105
|
+
s.onload = function(){
|
|
106
|
+
// Configure and load monaco
|
|
107
|
+
window.require.config({ paths: { vs: vsBase } });
|
|
108
|
+
window.require(['vs/editor/editor.main'], function(){
|
|
109
|
+
var editor;
|
|
110
|
+
|
|
111
|
+
function post(msg){ parent.postMessage(Object.assign({__from:'MonacoIframe'}, msg), '*'); }
|
|
112
|
+
|
|
113
|
+
function ensureEditor(){
|
|
114
|
+
if (editor) return editor;
|
|
115
|
+
editor = monaco.editor.create(document.getElementById('container'), {
|
|
116
|
+
value: '',
|
|
117
|
+
language: 'plaintext',
|
|
118
|
+
theme: 'vs',
|
|
119
|
+
automaticLayout: true,
|
|
120
|
+
minimap: { enabled: false },
|
|
121
|
+
scrollBeyondLastLine: true,
|
|
122
|
+
wordWrap: "on"
|
|
123
|
+
});
|
|
124
|
+
editor.onDidChangeModelContent(function(){
|
|
125
|
+
var v = editor.getValue();
|
|
126
|
+
post({ type: 'change', value: v });
|
|
127
|
+
});
|
|
128
|
+
return editor;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
window.addEventListener('message', function(ev){
|
|
132
|
+
var data = ev.data || {}; if (data.__from !== 'MonacoIframe') return;
|
|
133
|
+
if (data.type === 'init' || data.type === 'update'){
|
|
134
|
+
var ed = ensureEditor();
|
|
135
|
+
if (typeof data.value === 'string' && ed.getValue() !== data.value){ ed.setValue(data.value); }
|
|
136
|
+
if (typeof data.language === 'string') { monaco.editor.setModelLanguage(ed.getModel(), data.language); }
|
|
137
|
+
if (typeof data.theme === 'string') { monaco.editor.setTheme(data.theme); }
|
|
138
|
+
if (typeof data.readOnly === 'boolean') { ed.updateOptions({ readOnly: data.readOnly }); }
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Signal ready after monaco is loaded
|
|
143
|
+
post({ type: 'ready' });
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
document.head.appendChild(s);
|
|
147
|
+
})();
|
|
148
|
+
</script>
|
|
149
|
+
</head>
|
|
150
|
+
<body>
|
|
151
|
+
<div id="container"></div>
|
|
152
|
+
</body>
|
|
153
|
+
</html>`;
|
|
154
|
+
const doc = iframe.contentWindow?.document;
|
|
155
|
+
if (!doc)
|
|
156
|
+
return;
|
|
157
|
+
doc.open();
|
|
158
|
+
doc.write(html);
|
|
159
|
+
doc.close();
|
|
160
|
+
}
|
|
161
|
+
render() {
|
|
162
|
+
let style = this.props.style || {};
|
|
163
|
+
style.width = style.width || '100%';
|
|
164
|
+
style.height = style.height || '100%';
|
|
165
|
+
style.border = style.border || '0';
|
|
166
|
+
style.outline = style.outline || '0';
|
|
167
|
+
return react_1.default.createElement("iframe", { style: style, title: "Codenotch", ref: this.refFrame, className: this.props.className, sandbox: "allow-scripts allow-same-origin" });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.default = CodeEditor;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IProcessCallbacks, IProcessResult } from "../models/Misc";
|
|
2
|
+
/**
|
|
3
|
+
* static class mainly containing a method to start processes
|
|
4
|
+
*/
|
|
5
|
+
export default class ProcessUtils {
|
|
6
|
+
static startProcess(subscribeFunc: (processInstanceId: string, callbacks: IProcessCallbacks) => Promise<void>, clusterUrl: string, tenantName: string, projectName: string, processId: string, processInput: any, processInstanceId?: string, startNodeId?: string, token?: string): Promise<IProcessResult>;
|
|
7
|
+
private static launchMainProcess;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=ProcessUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcessUtils.d.ts","sourceRoot":"","sources":["../../src/core/ProcessUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEnE;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,YAAY;WAET,YAAY,CAAC,aAAa,EAAE,CAAC,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;mBAsCpS,iBAAiB;CAsCzC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const uuid_1 = require("uuid");
|
|
4
|
+
/**
|
|
5
|
+
* static class mainly containing a method to start processes
|
|
6
|
+
*/
|
|
7
|
+
class ProcessUtils {
|
|
8
|
+
static async startProcess(subscribeFunc, clusterUrl, tenantName, projectName, processId, processInput, processInstanceId, startNodeId, token) {
|
|
9
|
+
let instanceId = processInstanceId ? processInstanceId : (0, uuid_1.v4)();
|
|
10
|
+
return new Promise(async (resolve, reject) => {
|
|
11
|
+
try {
|
|
12
|
+
// Another class/component is responsible for listening to processes' states and calling back when they finish
|
|
13
|
+
await subscribeFunc(instanceId, {
|
|
14
|
+
onCallback: (callback) => {
|
|
15
|
+
//TODO check redirect ?
|
|
16
|
+
},
|
|
17
|
+
onOver: (processResult) => {
|
|
18
|
+
// The process has finished
|
|
19
|
+
resolve(processResult);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
// Create a new process instance
|
|
23
|
+
await ProcessUtils.launchMainProcess(clusterUrl, tenantName, projectName, processId, processInput, instanceId, startNodeId, token);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.error(err);
|
|
27
|
+
let processResult = {
|
|
28
|
+
isError: true,
|
|
29
|
+
processInstanceId: instanceId,
|
|
30
|
+
output: {},
|
|
31
|
+
errorMessage: err.message
|
|
32
|
+
};
|
|
33
|
+
resolve(processResult);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
static async launchMainProcess(clusterUrl, tenantName, projectName, processId, processInput, processInstanceId, startNodeId, token) {
|
|
38
|
+
console.log("launching main process");
|
|
39
|
+
let input = processInput ? processInput : {};
|
|
40
|
+
// We launch the process with an http request
|
|
41
|
+
let url = `${clusterUrl}/${projectName.toLowerCase()}/processes/${processId}/instances`;
|
|
42
|
+
let body = {
|
|
43
|
+
id: processInstanceId,
|
|
44
|
+
input: input,
|
|
45
|
+
startNode: startNodeId
|
|
46
|
+
};
|
|
47
|
+
let requestHeaders = new Headers();
|
|
48
|
+
requestHeaders.set('Content-Type', 'application/json');
|
|
49
|
+
if (token && token !== "") {
|
|
50
|
+
requestHeaders.set(`${tenantName}AccessToken`, token);
|
|
51
|
+
}
|
|
52
|
+
const response = await fetch(url, {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
credentials: 'include', // forward auth cookiesbody
|
|
55
|
+
body: JSON.stringify(body),
|
|
56
|
+
headers: requestHeaders
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
// Something went wrong
|
|
60
|
+
let errorMessage = await response.text();
|
|
61
|
+
throw new Error(errorMessage);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.default = ProcessUtils;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IProcessCallbacks, ICodenotchSignal } from "../models/Misc";
|
|
2
|
+
export declare class SignalR {
|
|
3
|
+
private _connection;
|
|
4
|
+
private _hubUrl;
|
|
5
|
+
private _accessToken;
|
|
6
|
+
private _signalCallbacks;
|
|
7
|
+
private _processCallbacks;
|
|
8
|
+
private _inactivityTimer;
|
|
9
|
+
private _unsubscribeTimers;
|
|
10
|
+
private _isConnecting;
|
|
11
|
+
private _pendingConnectionPromises;
|
|
12
|
+
private _keepAlive;
|
|
13
|
+
constructor(clusterUrl: string, serviceName: string, keepAlive: boolean, accessToken?: string);
|
|
14
|
+
connect(): Promise<void>;
|
|
15
|
+
private resolvePendingRequests;
|
|
16
|
+
private rejectPendingRequests;
|
|
17
|
+
private ensureConnected;
|
|
18
|
+
private onSignalReceived;
|
|
19
|
+
private getSignalPaths;
|
|
20
|
+
private onProcessCallbackReceived;
|
|
21
|
+
private onProcessOverReceived;
|
|
22
|
+
subscribeToProcessInstance(processInstanceId: string, callbacks: IProcessCallbacks): Promise<void>;
|
|
23
|
+
subscribeToSignal(signalId: string, callback: (signal: ICodenotchSignal) => void): Promise<() => Promise<void>>;
|
|
24
|
+
unsubscribeFromSignal(signalId: string, subscriptionId: string): Promise<void>;
|
|
25
|
+
private unsubscribeFromServerIfNoMoreSubscriptions;
|
|
26
|
+
private unsubscribeSignalServer;
|
|
27
|
+
private disconnectIfInactive;
|
|
28
|
+
disconnect(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=SignalR.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignalR.d.ts","sourceRoot":"","sources":["../../src/core/SignalR.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAkB,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIrF,qBAAa,OAAO;IAEhB,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAqB;IAIzC,OAAO,CAAC,gBAAgB,CAAwF;IAGhH,OAAO,CAAC,iBAAiB,CAAmD;IAE5E,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,kBAAkB,CAA4C;IAEtE,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,0BAA0B,CAAsE;IAGxG,OAAO,CAAC,UAAU,CAAU;gBAET,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM;IAY9F,OAAO;IAmEb,OAAO,CAAC,sBAAsB;IAa9B,OAAO,CAAC,qBAAqB;YAaf,eAAe;IA6B7B,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,yBAAyB;IASjC,OAAO,CAAC,qBAAqB;IAcvB,0BAA0B,CAAC,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB;IAuBlF,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IA4C/G,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;IAkBpE,OAAO,CAAC,0CAA0C;YAYpC,uBAAuB;IAOrC,OAAO,CAAC,oBAAoB;IAarB,UAAU,IAAI,IAAI;CAY5B"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SignalR = void 0;
|
|
4
|
+
const signalr_1 = require("@microsoft/signalr");
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
class SignalR {
|
|
7
|
+
constructor(clusterUrl, serviceName, keepAlive, accessToken) {
|
|
8
|
+
this._unsubscribeTimers = {};
|
|
9
|
+
this._isConnecting = false;
|
|
10
|
+
this._pendingConnectionPromises = [];
|
|
11
|
+
this._hubUrl = `${clusterUrl}/${serviceName}/exec`;
|
|
12
|
+
this._accessToken = accessToken;
|
|
13
|
+
this._connection = null;
|
|
14
|
+
this._signalCallbacks = {};
|
|
15
|
+
this._processCallbacks = {};
|
|
16
|
+
this._inactivityTimer = null;
|
|
17
|
+
this._keepAlive = keepAlive;
|
|
18
|
+
}
|
|
19
|
+
async connect() {
|
|
20
|
+
console.log(`SignalR establishing connection...`);
|
|
21
|
+
this._isConnecting = true;
|
|
22
|
+
// Here we inject the access token if defined
|
|
23
|
+
let options = this._accessToken ? { accessTokenFactory: () => this._accessToken } : {};
|
|
24
|
+
// Skip negotiation and only use websockets
|
|
25
|
+
// This allows us to have multiple SignalR server without sticky sessions
|
|
26
|
+
// But it won't work in the rare cases where websockets are not supported
|
|
27
|
+
options.skipNegotiation = true;
|
|
28
|
+
options.transport = signalr_1.HttpTransportType.WebSockets;
|
|
29
|
+
//TODO if the server has multi instances, and the one we are connected fails, do sticky sessions prevent us from connecting to a healthy instance ?
|
|
30
|
+
this._connection = new signalr_1.HubConnectionBuilder()
|
|
31
|
+
.withUrl(this._hubUrl, options)
|
|
32
|
+
.withAutomaticReconnect([0, 1000, 3000, 5000, 10000, 30000, 60000, 90000]) // If the server is a single instance and decide to change node, it might take a little while
|
|
33
|
+
.configureLogging(signalr_1.LogLevel.Error)
|
|
34
|
+
.build();
|
|
35
|
+
this._connection.off("ReceiveSignal");
|
|
36
|
+
this._connection.off("ReceiveLog");
|
|
37
|
+
this._connection.off("ReceiveCallback");
|
|
38
|
+
this._connection.off("ReceiveProcessOver");
|
|
39
|
+
// On Signal
|
|
40
|
+
this._connection.on("ReceiveSignal", (signal) => this.onSignalReceived(signal));
|
|
41
|
+
// On log
|
|
42
|
+
this._connection.on("ReceiveLog", (log) => {
|
|
43
|
+
console.log(log);
|
|
44
|
+
});
|
|
45
|
+
// On callback received from process
|
|
46
|
+
//TODO only used to set wec content and redirect, do we still need those ?
|
|
47
|
+
this._connection.on("ReceiveCallback", (callback) => this.onProcessCallbackReceived(callback));
|
|
48
|
+
// On process completed
|
|
49
|
+
this._connection.on("ReceiveProcessOver", (processResult) => this.onProcessOverReceived(processResult));
|
|
50
|
+
this._connection.onclose((error) => console.log(`disconnected: ${error ? error.message : "no error"}`));
|
|
51
|
+
this._connection.onreconnected(() => this.resolvePendingRequests());
|
|
52
|
+
try {
|
|
53
|
+
await this._connection.start();
|
|
54
|
+
console.log(`SignalR connection established`);
|
|
55
|
+
this.resolvePendingRequests();
|
|
56
|
+
this._isConnecting = false;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.log(`SignalR connection error: ${err}`);
|
|
60
|
+
this.rejectPendingRequests(err);
|
|
61
|
+
this._isConnecting = false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
resolvePendingRequests() {
|
|
65
|
+
if (this._pendingConnectionPromises.length > 0) {
|
|
66
|
+
console.log(`Resolving ${this._pendingConnectionPromises.length} pending connection promises`);
|
|
67
|
+
}
|
|
68
|
+
for (let p of this._pendingConnectionPromises) {
|
|
69
|
+
p?.resolve();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
rejectPendingRequests(error) {
|
|
73
|
+
if (this._pendingConnectionPromises.length > 0) {
|
|
74
|
+
console.log(`Rejecting ${this._pendingConnectionPromises.length} pending connection promises`);
|
|
75
|
+
}
|
|
76
|
+
for (let p of this._pendingConnectionPromises) {
|
|
77
|
+
p?.reject(error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async ensureConnected() {
|
|
81
|
+
if (this._inactivityTimer) {
|
|
82
|
+
// cancel disconnection
|
|
83
|
+
clearTimeout(this._inactivityTimer);
|
|
84
|
+
this._inactivityTimer = null;
|
|
85
|
+
}
|
|
86
|
+
if (this._connection && this._connection.state === signalr_1.HubConnectionState.Connected) {
|
|
87
|
+
return Promise.resolve();
|
|
88
|
+
}
|
|
89
|
+
console.log(`SignalR not currently connected, waiting on connection...`);
|
|
90
|
+
const connectionPromise = new Promise((resolve, reject) => {
|
|
91
|
+
this._pendingConnectionPromises.push({ resolve, reject });
|
|
92
|
+
});
|
|
93
|
+
if (!this._isConnecting) {
|
|
94
|
+
this.connect();
|
|
95
|
+
}
|
|
96
|
+
// Return a promise that will resolve when the connection is established
|
|
97
|
+
return connectionPromise;
|
|
98
|
+
}
|
|
99
|
+
onSignalReceived(signal) {
|
|
100
|
+
try {
|
|
101
|
+
console.log(`Received signal '${signal.signalId}'`);
|
|
102
|
+
console.log(signal);
|
|
103
|
+
// parse the eventual data in the signal
|
|
104
|
+
if (signal.data) {
|
|
105
|
+
try {
|
|
106
|
+
signal.data = JSON.parse(signal.data);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Data is not json but might still be valid
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// If signal id contains multiple paths, trigger each one
|
|
113
|
+
var signalPaths = this.getSignalPaths(signal.signalId);
|
|
114
|
+
for (let p of signalPaths) {
|
|
115
|
+
if (this._signalCallbacks[p]) {
|
|
116
|
+
for (let callback of Object.values(this._signalCallbacks[p])) {
|
|
117
|
+
callback(signal);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (ex) {
|
|
123
|
+
console.log(`An exception occured during 'ReceiveSignal' callback:`);
|
|
124
|
+
console.log(ex);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
getSignalPaths(signalId) {
|
|
128
|
+
// Signals can be segmented using '.', each segment corresponds to a more specific subject
|
|
129
|
+
// Subscribers can subscribe to a very specific signal or to a more general topic
|
|
130
|
+
// eg. Signal ref : invoice.update.0000-1111-2222-3333, will be received by subscribers on:
|
|
131
|
+
// -> 'invoice'
|
|
132
|
+
// -> 'invoice.update'
|
|
133
|
+
// -> 'invoice.update.0000-1111-2222-3333'
|
|
134
|
+
var signalPaths = [];
|
|
135
|
+
if (!signalId || signalId === '')
|
|
136
|
+
return signalPaths;
|
|
137
|
+
var segments = signalId.split('.');
|
|
138
|
+
for (let i = 0; i < segments.length; i++) {
|
|
139
|
+
signalPaths.push(segments.slice(0, i + 1).join('.')); // "path" from index 0 to i
|
|
140
|
+
}
|
|
141
|
+
return signalPaths;
|
|
142
|
+
}
|
|
143
|
+
onProcessCallbackReceived(callback) {
|
|
144
|
+
// Trigger the corresponding callback (set in ProcessUtils before launching the process)
|
|
145
|
+
if (this._processCallbacks[callback.processInstanceId]) {
|
|
146
|
+
this._processCallbacks[callback.processInstanceId].onCallback(callback);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
onProcessOverReceived(processResult) {
|
|
150
|
+
// Trigger the corresponding callback (set in ProcessUtils before launching the process)
|
|
151
|
+
if (this._processCallbacks[processResult.processInstanceId]) {
|
|
152
|
+
this._processCallbacks[processResult.processInstanceId].onOver(processResult);
|
|
153
|
+
// Clean it, now that the process is over we should not receive anymore callbacks
|
|
154
|
+
delete this._processCallbacks[processResult.processInstanceId];
|
|
155
|
+
this.disconnectIfInactive();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async subscribeToProcessInstance(processInstanceId, callbacks) {
|
|
159
|
+
if (this._processCallbacks[processInstanceId]) {
|
|
160
|
+
// Already subscribed
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
await this.ensureConnected();
|
|
164
|
+
try {
|
|
165
|
+
await this._connection.invoke("SubscribeToInstanceEvents", processInstanceId);
|
|
166
|
+
// Setup callbacks
|
|
167
|
+
this._processCallbacks[processInstanceId] = callbacks;
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
console.error(`Couldn't subscribe to process '${processInstanceId}', : ${err}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async subscribeToSignal(signalId, callback) {
|
|
174
|
+
console.log(`subscribeToSignal: signalId:${signalId}`);
|
|
175
|
+
if (!signalId || signalId === "")
|
|
176
|
+
return () => Promise.resolve();
|
|
177
|
+
await this.ensureConnected();
|
|
178
|
+
if (this._unsubscribeTimers[signalId]) {
|
|
179
|
+
// cancel eventual unsubscription
|
|
180
|
+
clearTimeout(this._unsubscribeTimers[signalId]);
|
|
181
|
+
delete this._unsubscribeTimers[signalId];
|
|
182
|
+
}
|
|
183
|
+
if (!this._signalCallbacks[signalId]) {
|
|
184
|
+
// Create the subscription
|
|
185
|
+
try {
|
|
186
|
+
await this._connection.invoke("SubscribeToSignal", signalId);
|
|
187
|
+
// Remember which signals we are subscribed so we don't subscribe twice
|
|
188
|
+
if (!this._signalCallbacks[signalId]) {
|
|
189
|
+
this._signalCallbacks[signalId] = {};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
throw `Couldn't subscribe to signal '${signalId}', : ${err}`;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Generate a new id to keep track of each subscription
|
|
197
|
+
let subscriptionId = (0, uuid_1.v4)();
|
|
198
|
+
this._signalCallbacks[signalId][subscriptionId] = callback;
|
|
199
|
+
// Return the unsubscribe function
|
|
200
|
+
return async () => await this.unsubscribeFromSignal(signalId, subscriptionId);
|
|
201
|
+
}
|
|
202
|
+
async unsubscribeFromSignal(signalId, subscriptionId) {
|
|
203
|
+
console.log(`unsubscribeFromSignal: signalId:${signalId}, subscriptionId:${subscriptionId}`);
|
|
204
|
+
if (!this._signalCallbacks[signalId]) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
delete this._signalCallbacks[signalId][subscriptionId];
|
|
208
|
+
// From this point we won't send events to the component who just unsubscribed, but we are still subscribed to the signal on the server so we'll recieve new signals
|
|
209
|
+
this.unsubscribeFromServerIfNoMoreSubscriptions(signalId);
|
|
210
|
+
// If no more subscriptions, we can disconnect from the server
|
|
211
|
+
this.disconnectIfInactive();
|
|
212
|
+
}
|
|
213
|
+
unsubscribeFromServerIfNoMoreSubscriptions(signalId) {
|
|
214
|
+
if (Object.keys(this._signalCallbacks[signalId]).length === 0) {
|
|
215
|
+
delete this._signalCallbacks[signalId];
|
|
216
|
+
// No more subscriptions for this signal, we can unsubscribe from the server
|
|
217
|
+
// but in order to not send too many requests, we will wait a little bit before actually unsubscribing, the client might come back to the tab that need this signal in a few seconds
|
|
218
|
+
this._unsubscribeTimers[signalId] = setTimeout(() => this.unsubscribeSignalServer(signalId), 1 * 60 * 1000);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async unsubscribeSignalServer(signalId) {
|
|
222
|
+
console.log(`unsubscribeSignalServer: signalId:${signalId}`);
|
|
223
|
+
await this._connection.invoke("UnsubscribeFromSignal", signalId);
|
|
224
|
+
}
|
|
225
|
+
disconnectIfInactive() {
|
|
226
|
+
if (this._keepAlive)
|
|
227
|
+
return;
|
|
228
|
+
if (Object.keys(this._signalCallbacks).length === 0 && Object.keys(this._processCallbacks).length === 0) {
|
|
229
|
+
// No more subscriptions, disconnect from the server after a little while (5 minutes) to save resources
|
|
230
|
+
this._inactivityTimer = setTimeout(() => this.disconnect(), 5 * 60 * 1000);
|
|
231
|
+
console.log("SignalR has no more active subscriptions, will disconnect in 5 minutes...");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
disconnect() {
|
|
235
|
+
if (this._connection) {
|
|
236
|
+
this._connection.off("ReceiveCallback");
|
|
237
|
+
this._connection.off("ReceiveProcessOver");
|
|
238
|
+
this._connection.off("ReceiveSignal");
|
|
239
|
+
this._connection.off("ReceiveLog");
|
|
240
|
+
this._connection.stop();
|
|
241
|
+
this._connection = null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
exports.SignalR = SignalR;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,51 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
serviceName?: string;
|
|
4
|
-
tenantName?: string;
|
|
5
|
-
accessToken?: string;
|
|
6
|
-
baseUrl?: string;
|
|
7
|
-
i18n?: {
|
|
8
|
-
[language: string]: {
|
|
9
|
-
[key: string]: string;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
currentLanguage?: string;
|
|
13
|
-
[key: string]: any;
|
|
14
|
-
}
|
|
15
|
-
export interface ICodenotchApi {
|
|
16
|
-
ENV: ICodenotchEnv;
|
|
17
|
-
requestSioql: (sioql: string, verbose?: boolean) => Promise<any>;
|
|
18
|
-
startProcess: (processName: string) => Promise<{
|
|
19
|
-
success: boolean;
|
|
20
|
-
}>;
|
|
21
|
-
onSignal: (signalId: string, callback: () => void) => {
|
|
22
|
-
dispose: () => void;
|
|
23
|
-
};
|
|
24
|
-
showDialog: (node: JSX.Element) => ICodenotchDialog;
|
|
25
|
-
}
|
|
26
|
-
export interface ICodenotchDialog {
|
|
27
|
-
id: string;
|
|
28
|
-
close: () => void;
|
|
29
|
-
}
|
|
30
|
-
declare const CODENOTCH_ENV: ICodenotchEnv;
|
|
31
|
-
/**
|
|
32
|
-
* Parse URL parameters and return them as an object
|
|
33
|
-
* @returns {Object} An object containing the URL parameters as key-value pairs
|
|
34
|
-
*/
|
|
35
|
-
export declare function parseUrlParams(): {
|
|
36
|
-
[key: string]: string;
|
|
37
|
-
};
|
|
1
|
+
import { ICodenotchApi, ICodenotchDialog, ICodenotchEnv } from "./models/Codenotch";
|
|
2
|
+
declare const env: ICodenotchEnv;
|
|
38
3
|
/**
|
|
39
4
|
* Setup Codenotch environment from the given object
|
|
40
5
|
* @param env An object containing the Codenotch environment variables as key-value pairs. This can be obtained from URL parameters or any other source.
|
|
41
6
|
* @returns {void}
|
|
42
7
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
8
|
+
declare function setupCodenotchEnv(env: any): void;
|
|
9
|
+
declare function i18n(key: string, ...args: any[]): string;
|
|
45
10
|
/**
|
|
46
11
|
* Return Codenotch API
|
|
47
12
|
* @returns {ICodenotchApi} Codenotch API
|
|
48
13
|
*/
|
|
49
|
-
|
|
50
|
-
export { CODENOTCH_ENV };
|
|
14
|
+
declare function useCodenotch(): ICodenotchApi;
|
|
15
|
+
export { env as CODENOTCH_ENV, i18n, useCodenotch, setupCodenotchEnv, ICodenotchEnv, ICodenotchApi, ICodenotchDialog };
|
|
51
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKpF,QAAA,MAAM,GAAG,EAAE,aAAkB,CAAC;AAO9B;;;;GAIG;AACH,iBAAS,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAgDzC;AAED,iBAAS,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,CAoCjD;AAED;;;GAGG;AACH,iBAAS,YAAY,IAAI,aAAa,CAsKrC;AAGD,OAAO,EACH,GAAG,IAAI,aAAa,EACpB,IAAI,EACJ,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,gBAAgB,EACnB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,29 +4,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.CODENOTCH_ENV = void 0;
|
|
7
|
-
exports.parseUrlParams = parseUrlParams;
|
|
8
|
-
exports.setupCodenotchEnv = setupCodenotchEnv;
|
|
9
7
|
exports.i18n = i18n;
|
|
10
8
|
exports.useCodenotch = useCodenotch;
|
|
9
|
+
exports.setupCodenotchEnv = setupCodenotchEnv;
|
|
11
10
|
const react_dom_1 = __importDefault(require("react-dom"));
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const params = new URL(window.location.href).searchParams;
|
|
22
|
-
params.forEach((value, key) => {
|
|
23
|
-
if (result[key] === undefined) {
|
|
24
|
-
result[key] = value;
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
return result;
|
|
29
|
-
}
|
|
11
|
+
const SignalR_1 = require("./core/SignalR");
|
|
12
|
+
const ProcessUtils_1 = __importDefault(require("./core/ProcessUtils"));
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
var signalR = undefined;
|
|
15
|
+
const env = {};
|
|
16
|
+
exports.CODENOTCH_ENV = env;
|
|
17
|
+
const MISSING_CLUSTER_URL_ERROR = "Codenotch cluster URL is not defined. Please set it in the Codenotch configuration.";
|
|
18
|
+
const MISSING_SERVICE_NAME_ERROR = "Codenotch service name is not defined. Please set it in the Codenotch configuration.";
|
|
19
|
+
const MISSING_TENANT_NAME_ERROR = "Codenotch tenant name is not defined. Please set it in the Codenotch configuration.";
|
|
30
20
|
/**
|
|
31
21
|
* Setup Codenotch environment from the given object
|
|
32
22
|
* @param env An object containing the Codenotch environment variables as key-value pairs. This can be obtained from URL parameters or any other source.
|
|
@@ -56,37 +46,40 @@ function setupCodenotchEnv(env) {
|
|
|
56
46
|
console.warn(`Codenotch environment variable ${key} is not a valid JSON string. Using raw value.`);
|
|
57
47
|
}
|
|
58
48
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
env.i18n = env.i18n ?? {};
|
|
50
|
+
env.i18n[language] = env.i18n[language] ?? {};
|
|
51
|
+
env.i18n[language][keyName] = keyValue;
|
|
62
52
|
}
|
|
63
53
|
else {
|
|
64
|
-
|
|
54
|
+
env[key] = env[key];
|
|
65
55
|
console.log(`Codenotch environment variable ${key} set to ${env[key]}`);
|
|
66
56
|
}
|
|
67
57
|
});
|
|
68
|
-
if (
|
|
58
|
+
if (env.language === undefined) {
|
|
69
59
|
// If current language is not defined, we set it to the first language found in i18n
|
|
70
60
|
if (i18nLanguages.size > 0) {
|
|
71
|
-
|
|
72
|
-
console.log(`Codenotch current language set to ${
|
|
61
|
+
env.language = Array.from(i18nLanguages)[0];
|
|
62
|
+
console.log(`Codenotch current language set to ${env.language}`);
|
|
73
63
|
}
|
|
74
64
|
}
|
|
65
|
+
if (env.clusterUrl && env.serviceName) {
|
|
66
|
+
signalR = new SignalR_1.SignalR(env.clusterUrl, env.serviceName, false, env.accessToken);
|
|
67
|
+
}
|
|
75
68
|
}
|
|
76
69
|
function i18n(key, ...args) {
|
|
77
70
|
try {
|
|
78
|
-
if (
|
|
71
|
+
if (env.i18n === undefined || Object.keys(env.i18n).length === 0) {
|
|
79
72
|
console.warn("Codenotch i18n is not defined. Please set it in the Codenotch configuration.");
|
|
80
73
|
return key;
|
|
81
74
|
}
|
|
82
|
-
let language =
|
|
83
|
-
let isLanguageExists =
|
|
75
|
+
let language = env.language ?? "en";
|
|
76
|
+
let isLanguageExists = env.i18n[language] !== undefined;
|
|
84
77
|
if (isLanguageExists === false) {
|
|
85
|
-
let fallbackLanguage = Object.keys(
|
|
78
|
+
let fallbackLanguage = Object.keys(env.i18n)[0];
|
|
86
79
|
console.warn(`Codenotch i18n language ${language} is not defined. Falling back to ${fallbackLanguage}. Please set the correct language in the Codenotch configuration.`);
|
|
87
80
|
language = fallbackLanguage;
|
|
88
81
|
}
|
|
89
|
-
let dico =
|
|
82
|
+
let dico = env.i18n[language];
|
|
90
83
|
let value = dico[key];
|
|
91
84
|
if (typeof value !== "string") {
|
|
92
85
|
console.warn(`Codenotch i18n key ${key} is not defined for language ${language}. Please set it in the Codenotch configuration.`);
|
|
@@ -111,53 +104,76 @@ function i18n(key, ...args) {
|
|
|
111
104
|
*/
|
|
112
105
|
function useCodenotch() {
|
|
113
106
|
return {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
throw new Error(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
107
|
+
env: env,
|
|
108
|
+
uuid: () => (0, uuid_1.v4)(),
|
|
109
|
+
getProjectFileUrl: (relativePath) => {
|
|
110
|
+
if (env.clusterUrl === undefined)
|
|
111
|
+
throw new Error(MISSING_CLUSTER_URL_ERROR);
|
|
112
|
+
if (env.serviceName === undefined)
|
|
113
|
+
throw new Error(MISSING_SERVICE_NAME_ERROR);
|
|
114
|
+
relativePath = relativePath.replace(/\\/g, "/");
|
|
115
|
+
if (relativePath.startsWith("/"))
|
|
116
|
+
relativePath = relativePath.substring(1);
|
|
117
|
+
let url = `${env.clusterUrl}/${env.serviceName}/project/file?name=""&path=${encodeURIComponent(relativePath)}`;
|
|
118
|
+
return url;
|
|
119
|
+
},
|
|
120
|
+
getProjectFile: async (relativePath) => {
|
|
121
|
+
let url = useCodenotch().getProjectFileUrl(relativePath);
|
|
122
|
+
let resp = await fetch(url);
|
|
123
|
+
if (resp.status.toString().startsWith('2') === false) {
|
|
124
|
+
throw new Error(`Failed to fetch file content: ${resp.status} ${resp.statusText}`);
|
|
125
125
|
}
|
|
126
|
+
let content = await resp.text();
|
|
127
|
+
return content;
|
|
128
|
+
},
|
|
129
|
+
requestSioql: async (sioql, verbose) => {
|
|
130
|
+
if (env.clusterUrl === undefined)
|
|
131
|
+
throw new Error(MISSING_CLUSTER_URL_ERROR);
|
|
132
|
+
if (env.serviceName === undefined)
|
|
133
|
+
throw new Error(MISSING_SERVICE_NAME_ERROR);
|
|
126
134
|
const request = {
|
|
127
135
|
method: 'POST',
|
|
128
136
|
mode: 'cors',
|
|
129
137
|
credentials: 'same-origin',
|
|
130
|
-
headers: {
|
|
131
|
-
|
|
132
|
-
}
|
|
138
|
+
headers: { 'Content-Type': 'application/json' },
|
|
139
|
+
body: `"${sioql.replace(/\"/g, '\\\"')}"`
|
|
133
140
|
};
|
|
134
|
-
if (
|
|
135
|
-
if (
|
|
136
|
-
throw new Error(
|
|
137
|
-
}
|
|
141
|
+
if (`${env.accessToken ?? ''}`.trim() !== "") {
|
|
142
|
+
if (env.tenantName === undefined)
|
|
143
|
+
throw new Error(MISSING_TENANT_NAME_ERROR);
|
|
138
144
|
request.headers = {
|
|
139
|
-
...request.headers,
|
|
140
|
-
[`${CODENOTCH_ENV.tenantName}AccessToken`]: CODENOTCH_ENV.accessToken
|
|
145
|
+
...request.headers, [`${env.tenantName}AccessToken`]: env.accessToken
|
|
141
146
|
};
|
|
142
147
|
}
|
|
143
|
-
|
|
144
|
-
const response = await fetch(url, request);
|
|
148
|
+
const response = await fetch(`${env.clusterUrl}/${env.serviceName}/sioql${verbose ? "?v=true" : ""}`, request);
|
|
145
149
|
if (!response.ok) {
|
|
146
150
|
const error = await response.text();
|
|
147
151
|
throw new Error(error);
|
|
148
152
|
}
|
|
149
153
|
return await response.json();
|
|
150
154
|
},
|
|
151
|
-
startProcess: async (processName) => {
|
|
152
|
-
|
|
155
|
+
startProcess: async (processName, inputs, startNodeId) => {
|
|
156
|
+
if (env.clusterUrl === undefined)
|
|
157
|
+
throw new Error(MISSING_CLUSTER_URL_ERROR);
|
|
158
|
+
if (env.serviceName === undefined)
|
|
159
|
+
throw new Error(MISSING_SERVICE_NAME_ERROR);
|
|
160
|
+
if (env.tenantName === undefined)
|
|
161
|
+
throw new Error(MISSING_TENANT_NAME_ERROR);
|
|
162
|
+
if (signalR === undefined)
|
|
163
|
+
throw new Error("SignalR not available. Cannot start process.");
|
|
164
|
+
return ProcessUtils_1.default.startProcess((processInstanceId, callbacks) => signalR.subscribeToProcessInstance(processInstanceId, callbacks), env.clusterUrl, env.tenantName, env.serviceName, processName, inputs, undefined, startNodeId ?? 'start', env.accessToken);
|
|
153
165
|
},
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
166
|
+
getUrlParams: () => {
|
|
167
|
+
let result = {};
|
|
168
|
+
if (typeof window !== 'undefined') {
|
|
169
|
+
const params = new URL(window.location.href).searchParams;
|
|
170
|
+
params.forEach((value, key) => {
|
|
171
|
+
if (result[key] === undefined) {
|
|
172
|
+
result[key] = value;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
161
177
|
},
|
|
162
178
|
showDialog: (node) => {
|
|
163
179
|
let dialogId = "codenotch-dialog-" + Math.random().toString(36).substring(2, 9);
|
|
@@ -210,6 +226,36 @@ function useCodenotch() {
|
|
|
210
226
|
dialogElement.showModal();
|
|
211
227
|
});
|
|
212
228
|
return result;
|
|
229
|
+
},
|
|
230
|
+
listenSignal: async (signalId, callback) => {
|
|
231
|
+
if (!signalR) {
|
|
232
|
+
throw new Error("SignalR not available. Cannot listen to signal.");
|
|
233
|
+
}
|
|
234
|
+
let unsubscribeFunc = await signalR.subscribeToSignal(signalId, callback);
|
|
235
|
+
return {
|
|
236
|
+
dispose: () => {
|
|
237
|
+
unsubscribeFunc();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
},
|
|
241
|
+
setTheme: (theme) => {
|
|
242
|
+
if (env.theme === theme)
|
|
243
|
+
return;
|
|
244
|
+
if (env.theme)
|
|
245
|
+
document.documentElement.classList.remove(env.theme);
|
|
246
|
+
env.theme = theme;
|
|
247
|
+
document.documentElement.classList.add(theme);
|
|
248
|
+
},
|
|
249
|
+
setLanguage: (lang) => {
|
|
250
|
+
if (env.language === lang)
|
|
251
|
+
return;
|
|
252
|
+
env.language = lang;
|
|
253
|
+
},
|
|
254
|
+
getLanguage: () => {
|
|
255
|
+
return env.language;
|
|
256
|
+
},
|
|
257
|
+
getTheme: () => {
|
|
258
|
+
return env.theme;
|
|
213
259
|
}
|
|
214
260
|
};
|
|
215
261
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ICodenotchSignal, IDisposable, IProcessResult } from "./Misc";
|
|
2
|
+
export interface ICodenotchEnv {
|
|
3
|
+
appName?: string;
|
|
4
|
+
clusterUrl?: string;
|
|
5
|
+
serviceName?: string;
|
|
6
|
+
tenantName?: string;
|
|
7
|
+
accessToken?: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
i18n?: {
|
|
10
|
+
[language: string]: {
|
|
11
|
+
[key: string]: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
language?: string;
|
|
15
|
+
theme?: 'light' | 'dark';
|
|
16
|
+
}
|
|
17
|
+
export interface ICodenotchApi {
|
|
18
|
+
readonly env: ICodenotchEnv;
|
|
19
|
+
readonly requestSioql: (sioql: string, verbose?: boolean) => Promise<any>;
|
|
20
|
+
readonly startProcess: (processName: string, inputs: any, startNodeId?: string) => Promise<IProcessResult>;
|
|
21
|
+
readonly showDialog: (node: JSX.Element) => ICodenotchDialog;
|
|
22
|
+
readonly getProjectFile: (relativePath: string) => Promise<string | undefined>;
|
|
23
|
+
readonly getProjectFileUrl: (relativePath: string) => string;
|
|
24
|
+
readonly listenSignal: (signalId: string, callback: (data: ICodenotchSignal) => void) => Promise<IDisposable>;
|
|
25
|
+
readonly setTheme: (theme: 'light' | 'dark') => void;
|
|
26
|
+
readonly getTheme: () => 'light' | 'dark' | undefined;
|
|
27
|
+
readonly setLanguage: (lang: string) => void;
|
|
28
|
+
readonly getLanguage: () => string | undefined;
|
|
29
|
+
readonly getUrlParams: () => {
|
|
30
|
+
[key: string]: string;
|
|
31
|
+
};
|
|
32
|
+
readonly uuid: () => string;
|
|
33
|
+
}
|
|
34
|
+
export interface ICodenotchDialog {
|
|
35
|
+
id: string;
|
|
36
|
+
close: () => void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=Codenotch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Codenotch.d.ts","sourceRoot":"","sources":["../../src/models/Codenotch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAEvE,MAAM,WAAW,aAAa;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAE5B,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1E,QAAQ,CAAC,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3G,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,KAAK,gBAAgB,CAAC;IAC7D,QAAQ,CAAC,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/E,QAAQ,CAAC,iBAAiB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7D,QAAQ,CAAC,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9G,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,YAAY,EAAE,MAAM;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,IAAI,CAAC;CACrB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface IProcessCallbacks {
|
|
2
|
+
onOver: (processResult: IProcessResult) => void;
|
|
3
|
+
onCallback: (callback: any) => void;
|
|
4
|
+
}
|
|
5
|
+
export interface IProcessResult {
|
|
6
|
+
processInstanceId: string;
|
|
7
|
+
output: any;
|
|
8
|
+
isError: boolean;
|
|
9
|
+
errorMessage: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ICodenotchSignal {
|
|
12
|
+
signalId: string;
|
|
13
|
+
data: any;
|
|
14
|
+
}
|
|
15
|
+
export interface IDisposable {
|
|
16
|
+
dispose: () => void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=Misc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Misc.d.ts","sourceRoot":"","sources":["../../src/models/Misc.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAE9B,MAAM,EAAE,CAAC,aAAa,EAAE,cAAc,KAAK,IAAI,CAAC;IAChD,UAAU,EAAC,CAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAA;CACtC;AAED,MAAM,WAAW,cAAc;IAE3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,GAAG,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAE7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codenotch-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.55",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"author": "Codenotch SA",
|
|
@@ -14,13 +14,16 @@
|
|
|
14
14
|
"dist/**/*"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"@echino/echino.ui.core": "^0.13.128",
|
|
17
18
|
"@echino/echino.ui.framework": "1.1.61",
|
|
18
|
-
"@
|
|
19
|
+
"@microsoft/signalr": "^5.0.6",
|
|
20
|
+
"uuid": "^8.2.0"
|
|
19
21
|
},
|
|
20
22
|
"devDependencies": {
|
|
21
23
|
"@types/node": "^25.3.2",
|
|
22
24
|
"@types/react": "^16.14.69",
|
|
23
25
|
"@types/react-dom": "^16.9.25",
|
|
26
|
+
"@types/uuid": "8.0.0",
|
|
24
27
|
"react-dom": "^16.14.0",
|
|
25
28
|
"typescript": "^5.9.3"
|
|
26
29
|
},
|
package/dist/auml.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auml.d.ts","sourceRoot":"","sources":["../src/auml.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,0EAA0E,CAAC;AAS3G,UAAU,UAAU;IAChB,KAAK,EAAE,MAAM,CAAC;CACjB;AACD,UAAU,UAAU;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAED,qBAAa,IAAK,SAAQ,KAAK,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC;IAE7D,kBAAkB,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;gBAEnC,KAAK,EAAE,UAAU;IAQ7B,iBAAiB;IAmCjB,oBAAoB;IAQpB,QAAQ,CAAC,CAAC,EAAE,eAAe;IAO3B,OAAO;IAYP,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS;IAclC,cAAc;;;IAMd,wBAAwB,IAAI,MAAM,GAAG,IAAI;IAoCzC,2BAA2B,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM;IAO/D,QAAQ,CAAC,EAAE,EAAE,MAAM;IAmBnB,QAAQ,CAAC,KAAK,EAAE,MAAM;IAsBtB,MAAM;IAiDA,mBAAmB;CAqC5B"}
|