@senx/discovery-code
Version:
Discovery Code Editor
1,131 lines • 62.4 kB
JavaScript
/*
* Copyright 2022-2024 SenX S.A.S.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { h } from "@stencil/core";
import { Config } from "../../model/config";
import { Logger } from "../../model/logger";
import { editor, KeyCode, KeyMod, MarkerSeverity, Range } from "monaco-editor";
import { EditorUtils } from "../../providers/editorUtils";
import { WarpScriptParser } from "../../model/warpScriptParser";
import { Utils } from "../../model/utils";
import { ProviderRegistrar } from "../../providers/ProviderRegistrar";
import { createReviewManager, } from "../../providers/CodeReview";
import dayjs from "dayjs";
import "@giwisoft/wc-split";
import "@giwisoft/wc-tabs";
import { v4 } from "uuid";
import { WSLanguageConfiguration } from "../../providers/WSLanguageConfiguration";
import { FLoWSLanguageConfiguration } from "../../providers/FLoWSLanguageConfiguration";
var create = editor.create;
var setModelMarkers = editor.setModelMarkers;
export class DiscoveryCodeEditor {
constructor() {
this.loading = false;
this.previousParentHeight = -1;
this.previousParentWidth = -1;
this.decorations = {};
this.reviewManagerConfig = {
formatDate: (createdAt) => dayjs(createdAt).format('YYYY-MM-DD HH:mm'),
};
this.selectedCode = '';
this.breakpointsReadOnly = false;
this.url = undefined;
this.bootstrap = undefined;
this.language = 'warpscript';
this.existingComments = [];
this.debug = false;
this.useBootstrap = true;
this.showDataviz = false;
this.showExecute = false;
this.showResult = false;
this.displayMessages = false;
this.imageTab = false;
this.widthPx = undefined;
this.heightPx = undefined;
this.heightLine = undefined;
this.theme = 'light';
this.code = '';
this.config = new Config();
this.initialSize = undefined;
this.selectedResultTab = -1;
this.result = undefined;
this.status = undefined;
this.error = undefined;
this.innerConfig = new Config();
this.LOG = new Logger(DiscoveryCodeEditor, this.debug);
}
// noinspection JSUnusedGlobalSymbols
componentWillLoad() {
self.MonacoEnvironment = {
getWorkerUrl: () => URL.createObjectURL(new Blob([`
self.MonacoEnvironment = {
baseUrl: 'https://unpkg.com/monaco-editor@0.38.0/min/'
};
importScripts('https://unpkg.com/monaco-editor@0.38.0/min/vs/base/worker/workerMain.js');
`], { type: 'text/javascript' })),
};
}
componentDidLoad() {
let conf = (typeof this.config === 'string') ? JSON.parse(this.config || JSON.stringify(new Config())) : this.config || new Config();
this.innerConfig = Utils.mergeDeep(this.innerConfig, conf);
new ResizeObserver(() => this.resize(true)).observe(this.el.parentElement);
setTimeout(async () => {
var _a, _b;
this.LOG.debug(['componentDidLoad'], 'height', this.heightPx);
if (!!this.heightPx) {
// if height-px is set, size is fixed.
this.el.style.height = this.heightPx + 'px';
this.wrapper.style.height = this.heightPx + 'px';
await this.resize(true);
}
else {
// compute the layout manually in a 200ms timer
this.resizeWatcherInt = setTimeout(this.resizeWatcher.bind(this), 200);
}
try {
this.innerCode = Utils.unsescape(this.content.innerHTML);
// add blank lines when needed
for (let i = this.innerCode.split('\n').length; i < this.innerConfig.editor.minLineNumber; i++) {
this.innerCode += '\n';
}
// trim spaces and line breaks at the beginning (side effect of angular)
let firstIndex = 0;
while (this.innerCode[firstIndex] === ' ' || this.innerCode[firstIndex] === '\n') {
firstIndex++;
}
this.innerCode = this.innerCode.substring(firstIndex);
this.LOG.debug(['componentDidLoad'], 'code', this.code);
this.LOG.debug(['componentDidLoad'], 'inner: ', this.innerCode.split('\n'));
this.LOG.debug(['componentDidLoad'], 'innerConfig: ', this.config);
ProviderRegistrar.register(this.innerConfig);
const edOpts = this.setOptions();
this.lastKnownWS = this.code || this.innerCode;
editor.setTheme(this.getTheme());
this.LOG.debug(['componentDidLoad'], 'edOpts: ', edOpts);
this.ed = create(this.editor, edOpts);
this.selectedCodeCondition = this.ed.createContextKey('selectedCodeCondition', false);
if (!this.innerConfig.readOnly) {
this.ed.addAction({
id: v4(),
label: 'Execute',
keybindings: [KeyMod.CtrlCmd | KeyCode.KeyE],
precondition: '!selectedCodeCondition',
keybindingContext: null,
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.5,
run: () => this.execute(),
});
this.ed.addAction({
id: v4(),
label: 'Execute Selection',
keybindings: [KeyMod.CtrlCmd | KeyCode.KeyE],
precondition: 'selectedCodeCondition',
keybindingContext: null,
contextMenuGroupId: 'navigation',
contextMenuOrder: 1.5,
run: () => this.executeCode(this.selectedCode),
});
}
this.ed.onDidChangeCursorSelection((e) => {
const selection = this.ed.getModel().getValueInRange(this.ed.getSelection());
if ('' !== selection.trim()) {
this.selectedCodeCondition.set(true);
let pad = '';
for (let i = 0; i < e.selection.startLineNumber - 1; i++)
pad += '\n';
this.selectedCode = pad + this.ed.getModel().getValueInRange(this.ed.getSelection());
}
else {
this.selectedCodeCondition.set(false);
this.selectedCode = '';
}
});
this.ed.setValue(this.lastKnownWS);
editor.setModelLanguage(this.ed.getModel(), this.language);
this.LOG.debug(['componentDidLoad', 'mouse down'], this.innerConfig);
this.ed.onMouseDown(e => {
if (e.event.leftButton) {
if (e.target.type === 2 || e.target.type === 3 || e.target.type === 4) {
this.toggleBreakPoint(e.target.position.lineNumber);
}
}
});
this.ed.getModel().updateOptions({ tabSize: this.innerConfig.editor.tabSize });
if (this.ed) {
this.discoveryCodeLoaded.emit('loaded');
// angular events does not bubble up outside angular component.
this.LOG.debug(['componentDidLoad'], 'loaded');
this.ed.getModel().onDidChangeContent(async (event) => {
await this.unHighlight(this.errorLine);
if (this.lastKnownWS !== this.ed.getValue()) {
this.setInlineDecoCollection();
this.setMarginDecoCollection();
this.setLineDecoCollection();
this.debounce(() => {
this.LOG.debug(['componentDidLoad'], 'ws changed', event);
this.discoveryCodeChanged.emit(this.ed.getValue());
// this.wsAudit(this.ed.getValue());
}, 200)();
}
});
// manage the ctrl click, create an event with the statement, the endpoint, the warpfleet repos.
this.ed.onMouseDown(e => {
var _a;
if (e.target.range && ((!this.isMac() && !!e.event.ctrlKey) || (this.isMac() && !!e.event.metaKey))) {
// ctrl click on which word ?
const name = (this.ed.getModel().getWordAtPosition((_a = e.target.range) === null || _a === void 0 ? void 0 : _a.getStartPosition()) || { word: undefined }).word;
if (this.isClickableWord(name)) {
// parse the warpscript
const ws = this.ed.getValue();
const specialHeaders = WarpScriptParser.extractSpecialComments(ws);
const repos = [];
const statements = WarpScriptParser.parseWarpScriptStatements(ws);
statements.forEach((st, i) => {
if (st === 'WF.ADDREPO' && i > 0) {
const previousStatement = statements[i - 1];
if ((previousStatement.startsWith('"') && previousStatement.endsWith('"'))
|| (previousStatement.startsWith('\'') && previousStatement.endsWith('\''))) {
// this is a valid string.
repos.push(previousStatement.substring(1, previousStatement.length - 1));
}
}
});
const docParams = {
endpoint: specialHeaders.endpoint || this.url,
macroName: name,
wfRepos: repos,
};
this.discoveryCodeRef.emit(docParams);
}
}
// this.wsAudit(this.ed.getValue());
});
if (this.innerConfig.codeReview && !!this.innerConfig.codeReview.enabled) {
this.reviewManagerConfig.addButton = this.innerConfig.codeReview.addButton;
this.reviewManagerConfig.cancelButton = this.innerConfig.codeReview.cancelButton;
this.reviewManagerConfig.replyButton = this.innerConfig.codeReview.replyButton;
this.reviewManagerConfig.removeButton = this.innerConfig.codeReview.removeButton;
this.reviewManagerConfig.editButton = this.innerConfig.codeReview.editButton;
this.existingComments = typeof this.existingComments === 'string' ? JSON.parse((_a = this.existingComments) !== null && _a !== void 0 ? _a : '[]') : (_b = this.existingComments) !== null && _b !== void 0 ? _b : [];
this.discoveryCodeReview.emit(this.existingComments);
this.reviewManager = createReviewManager(this.ed, this.innerConfig.codeReview.currentUser, this.existingComments, updatedComments => this.discoveryCodeReview.emit(updatedComments), this.reviewManagerConfig);
this.reviewManager.setReadOnlyMode(this.innerConfig.codeReview.readonly);
}
}
}
catch (e) {
this.LOG.error(['componentDidLoad'], 'componentDidLoad', e);
}
});
}
// noinspection JSUnusedGlobalSymbols
disconnectedCallback() {
this.LOG.debug(['disconnectedCallback'], 'Component removed from the DOM');
if (this.resizeWatcherInt) {
clearInterval(this.resizeWatcherInt);
}
if (this.ed) {
this.ed.dispose();
}
}
setDebug(newValue) {
this.LOG.setDebug(newValue);
}
updateTheme(newValue) {
this.theme = newValue;
this.getTheme();
if (editor) {
editor.setTheme(this.getTheme());
}
}
updateCode(newValue) {
if (this.ed)
this.ed.setValue(newValue);
}
configUpdate(newValue) {
let conf = (typeof newValue === 'string') ? JSON.parse(newValue || JSON.stringify(new Config())) : newValue || new Config();
this.innerConfig = Utils.mergeDeep(this.innerConfig, conf);
this.LOG.debug(['config'], this.innerConfig, newValue);
if (this.ed) {
this.LOG.debug(['config'], this.config);
this.ed.updateOptions(this.setOptions());
if (this.innerConfig.codeReview && !!this.innerConfig.codeReview.enabled) {
this.reviewManagerConfig.addButton = this.innerConfig.codeReview.addButton;
this.reviewManagerConfig.cancelButton = this.innerConfig.codeReview.cancelButton;
this.reviewManagerConfig.replyButton = this.innerConfig.codeReview.replyButton;
this.reviewManagerConfig.removeButton = this.innerConfig.codeReview.removeButton;
this.reviewManager.currentUser = this.innerConfig.codeReview.currentUser;
this.reviewManager.setReadOnlyMode(this.innerConfig.codeReview.readonly);
this.reviewManagerConfig.editButton = this.innerConfig.codeReview.editButton;
this.reviewManager.updateConfig(this.reviewManagerConfig);
}
}
}
async execute(session) {
if (this.ed) {
let code = this.ed.getValue().replace(/ /gi, ' ');
if (EditorUtils.FLOWS_LANGUAGE === this.language) {
code = `<'
${code}
'>
FLOWS
`;
}
this.LOG.debug(['execute'], 'this.ed.getValue()', session, code);
return this.executeCode(code, session);
}
}
async executeCode(code, session) {
var _a;
if (this.ed) {
this.result = undefined;
this.status = undefined;
this.error = undefined;
this.loading = true;
// parse comments to look for inline url or preview modifiers
const specialHeaders = WarpScriptParser.extractSpecialComments(code);
const previewType = specialHeaders.displayPreviewOpt || 'none';
if (previewType === 'I') {
this.selectedResultTab = 2; // select image tab.
}
else if (this.selectedResultTab === 2) {
this.selectedResultTab = 0; // on next execution, select results tab.
}
const executionUrl = specialHeaders.endpoint || this.url;
this.LOG.debug(['execute'], 'specialHeaders', this.innerConfig.addLocalHeader);
// Get Warp10 version
let headers = Object.assign(Object.assign({}, this.innerConfig.httpHeaders || {}), { 'Content-Type': 'text/plain;charset=UTF-8' });
if (this.innerConfig.addLocalHeader) {
headers['Access-Control-Request-Private-Network'] = 'true';
}
if (!!session) {
headers['X-Warp10-WarpScriptSession'] = session;
}
await this.unHighlight(this.errorLine);
Utils.httpPost(executionUrl, (!specialHeaders.endpoint && this.useBootstrap ? ((_a = this.bootstrap) !== null && _a !== void 0 ? _a : '') + '\n' : '') + code, headers)
.then((res) => {
var _a, _b, _c;
if (!!res) {
this.LOG.debug(['execute'], 'response', res);
this.discoveryCodeResult.emit(res.data);
if (!!res.headers) {
this.sendStatus(Object.assign({ endpoint: executionUrl, message: `Your script execution took
${EditorUtils.formatElapsedTime(res.status.elapsed)}
serverside, fetched
${res.status.fetched} datapoints and performed
${res.status.ops} ${this.getLabel()} operations.` }, res.status));
}
try {
this.LOG.debug(['execute'], 'res', res);
this.result = (_a = res.data) !== null && _a !== void 0 ? _a : '[]';
}
catch (e) {
if (e.name && e.message && e.at && e.text) {
this.error = `${e.name}: ${e.message} at char ${e.at} => ${e.text.replace((_b = this.bootstrap) !== null && _b !== void 0 ? _b : '', '')}`;
}
else {
this.error = e.toString();
}
this.result = (_c = res.data) !== null && _c !== void 0 ? _c : '[]';
this.LOG.error(['execute 1'], this.error);
this.sendError(this.error, executionUrl);
}
}
this.loading = false;
}).catch(e => this.handleError(e));
}
else {
this.loading = false;
this.LOG.error(['execute'], 'no active editor');
}
}
async abort(session) {
const specialHeaders = WarpScriptParser.extractSpecialComments(this.ed.getValue());
const executionUrl = specialHeaders.endpoint || this.url;
if (!!session) {
Utils.httpPost(executionUrl, `<% '${session}' 'WSKILLSESSION' EVAL %> <% -1 %> <% %> TRY`, Object.assign(Object.assign({}, this.innerConfig.httpHeaders || {}), { 'Accept': 'application/json' }))
.then((res) => {
if (!!res) {
this.LOG.debug(['abort'], 'response', res.data);
const r = JSON.parse(res.data);
if (!!r[0]) {
if (r[0] === 0) {
this.sendError('It appears that your Warp 10 is running on multiple backend', executionUrl);
}
else if (r[0] === -1) {
this.sendError(`Unable to WSABORT on ${executionUrl}. Did you activate StackPSWarpScriptExtension?`, executionUrl);
}
this.sendStatus(Object.assign({ endpoint: executionUrl, message: `${this.getLabel()} aborted.` }, res.status));
}
else {
this.sendError(`An error occurs for session: ${session}`, executionUrl);
}
}
this.loading = false;
})
.catch(e => this.handleError(e));
}
else {
this.sendStatus({
endpoint: executionUrl,
message: `${this.getLabel()} aborted.`,
ops: 0,
elapsed: 0,
fetched: 0,
});
this.loading = false;
}
}
async setBreakpointsReadOnly(status) {
this.breakpointsReadOnly = status;
}
async addInlineMarker(bp) {
const currentKey = `il-${bp.line}-${bp.column}`;
this.decorations[currentKey] = this.getInlineDecoration(bp.line, bp.column);
this.setInlineDecoCollection();
this.discoveryCodeBreakPoint.emit(this.decorations);
}
async removeInlineMarker(bp) {
if (bp === undefined) {
Object.keys(this.decorations)
.filter(k => k.startsWith('il-'))
.forEach(k => delete this.decorations[k]);
}
else {
delete this.decorations[`il-${bp.line}-${bp.column}`];
}
this.setInlineDecoCollection();
this.discoveryCodeBreakPoint.emit(this.decorations);
}
async addBreakpoints(bps) {
bps.forEach(bp => {
const currentKey = `bp-${bp.line}`;
if (!this.breakpointsReadOnly) {
this.decorations[currentKey] = this.getMarginDecoration(bp.line, this.verifyBreakpoint(bp.line - 1));
}
});
this.setMarginDecoCollection();
this.discoveryCodeBreakPoint.emit(this.decorations);
}
async removeBreakpoints(bps) {
if (bps === undefined) {
Object.keys(this.decorations)
.filter(k => k.startsWith('bp-'))
.forEach(k => delete this.decorations[k]);
}
else {
bps.forEach(bp => {
const currentKey = 'bp-' + bp.line + (bp.column ? '-' + bp.column : '');
delete this.decorations[currentKey];
});
}
this.setMarginDecoCollection();
this.discoveryCodeBreakPoint.emit(this.decorations);
}
async unHighlight(line) {
if (typeof line === 'number') {
delete this.decorations['hl-' + line];
delete this.decorations['err-' + line];
}
else {
Object.keys(this.decorations)
.filter(k => k.startsWith('hl-') || k.startsWith('err-'))
.forEach(k => delete this.decorations[k]);
}
this.setLineDecoCollection();
}
async highlight(line, isError = false, errorMessage) {
const currentKey = (isError ? 'err-' : 'hl-') + line;
this.decorations[currentKey] = {
range: new Range(line, 1, line, 1),
options: {
isWholeLine: true,
className: isError ? undefined : 'discoveryContentClass',
glyphMarginClassName: isError ? 'discoveryGlyphMarginErrorClass' : undefined,
},
};
if (isError) {
setModelMarkers(this.ed.getModel(), 'owner', [
{
startLineNumber: line,
startColumn: 0,
endLineNumber: line,
endColumn: this.ed.getValue().split('\n')[line].length,
message: errorMessage !== null && errorMessage !== void 0 ? errorMessage : 'Error!',
severity: MarkerSeverity.Error,
},
]);
}
this.setLineDecoCollection();
}
async resize(initial) {
window.setTimeout(() => {
if (initial && (!!this.heightPx)) {
this.editor.style.height = `calc(100% - ${this.buttons ? this.buttons.clientHeight : 100}px )`;
}
if (initial) {
this.discoveryCodeLoaded.emit();
this.LOG.debug(['resize'], 'loaded');
}
this.resizeWatcher();
}, initial ? 500 : 100);
}
getInlineDecoration(line, column) {
return {
range: new Range(line, column, line, column + 1),
verified: true,
options: { isWholeLine: false, inlineClassName: 'discoveryBreakpointInline' },
};
}
getMarginDecoration(line, verified) {
return {
range: new Range(line, undefined, line, undefined),
verified,
options: {
isWholeLine: true,
glyphMarginClassName: verified ? 'discoveryGlyphMarginBreakpoint' : 'discoveryGlyphMarginUnverifiedBreakpoint',
},
};
}
setMarginDecoCollection() {
if (this.ed) {
if (this.marginDecoCollection) {
this.marginDecoCollection.clear();
}
this.marginDecoCollection = this.ed.createDecorationsCollection(Object.keys(this.decorations)
.filter(k => k.startsWith('bp-'))
.map(k => this.decorations[k]));
}
}
setInlineDecoCollection() {
if (this.ed) {
if (this.inlineDecoCollection) {
this.inlineDecoCollection.clear();
}
this.inlineDecoCollection = this.ed.createDecorationsCollection(Object.keys(this.decorations)
.filter(k => k.startsWith('il-'))
.map(k => this.decorations[k]));
}
}
setLineDecoCollection() {
if (this.ed) {
if (this.lineDecoCollection) {
this.lineDecoCollection.clear();
}
this.lineDecoCollection = this.ed.createDecorationsCollection(Object.keys(this.decorations)
.filter(k => k.startsWith('hl') || k.startsWith('err'))
.map(k => this.decorations[k]));
}
}
toggleBreakPoint(line) {
this.LOG.debug(['toggleBreakPoint', 'breakpointsReadOnly'], this.breakpointsReadOnly);
if (!this.breakpointsReadOnly && this.innerConfig.editor.enableDebug) {
const currentKey = 'bp-' + line;
if (this.decorations[currentKey]) {
delete this.decorations[currentKey];
}
else {
this.decorations[currentKey] = this.getMarginDecoration(line, this.verifyBreakpoint(line - 1));
}
this.setMarginDecoCollection();
this.discoveryCodeBreakPoint.emit(this.decorations);
}
}
verifyBreakpoint(line) {
let verified = false;
if (this.ed) {
const sourceLines = this.ed.getValue().replace(/ /gi, ' ').split(('\n'));
if (line < sourceLines.length) {
verified = true;
const srcLine = sourceLines[line].trim();
// Comments and multiline handling
if (/<'/.test(srcLine))
return false;
if (/'>/.test(srcLine))
return false;
if (/\/\*/.test(srcLine))
return true;
if (/\*\//.test(srcLine))
return false;
for (let i = line; i > 0; i--) {
if (/'>/.test(sourceLines[i]) || /\*\//.test(sourceLines[i])) {
break;
}
if (/<'/.test(sourceLines[i]) || /\/\*/.test(sourceLines[i])) {
return false;
}
}
}
}
return verified;
}
resizeWatcher() {
const editorParentWidth = this.editor.parentElement.clientWidth;
const editorParentHeight = this.editor.parentElement.clientHeight
- parseInt(window.getComputedStyle(this.editor.parentElement).getPropertyValue('padding-top').replace('px', ''), 10)
- parseInt(window.getComputedStyle(this.editor.parentElement).getPropertyValue('padding-bottom').replace('px', ''), 10);
let componentParentHeight = this.el.parentElement.clientHeight
- parseInt(window.getComputedStyle(this.el.parentElement).getPropertyValue('padding-top').replace('px', ''), 10)
- parseInt(window.getComputedStyle(this.el.parentElement).getPropertyValue('padding-bottom').replace('px', ''), 10);
componentParentHeight = Math.max(componentParentHeight, DiscoveryCodeEditor.MIN_HEIGHT);
this.wrapper.style.height = componentParentHeight + 'px';
// watch for editor parent size change
if (editorParentHeight !== this.previousParentHeight || editorParentWidth !== this.previousParentWidth) {
this.previousParentHeight = editorParentHeight;
this.previousParentWidth = editorParentWidth;
this.editor.style.height = 'calc(100% - ' + this.buttons.clientHeight + 'px)';
this.editor.style.overflow = 'hidden';
}
this.wrapper.style.height = componentParentHeight + 'px';
this.ed.layout(); //{height: editorH, width: editorW});
this.editor.style.overflow = 'hidden';
}
handleError(err) {
this.LOG.error(['handleError'], { e: err });
if (err.status === 0) {
this.error = `Unable to reach ${err.url}`;
}
else {
if (err.detail.mess && err.detail.line) {
const line = parseInt(err.detail.line) - (this.useBootstrap ? 1 : 0);
if (!isNaN(line)) {
this.errorLine = line;
this.ed.revealLineInCenter(line);
this.highlight(line, true, err.detail.mess).then(() => {
// empty
});
}
this.error = (line < 0 ? '' : 'Line #' + line + ': ') + err.detail.mess;
}
else {
this.error = err.statusText;
}
}
this.sendError(this.error, err.url, { code: parseInt(err.status), text: err.statusText });
this.loading = false;
}
setOptions() {
return {
quickSuggestionsDelay: this.innerConfig.editor.quickSuggestionsDelay,
quickSuggestions: this.innerConfig.editor.quickSuggestions,
suggestOnTriggerCharacters: this.innerConfig.editor.quickSuggestions,
// monaco auto layout is ok if parent has a fixed size, not 100% or a calc ( % px ) formula.
automaticLayout: !!this.heightPx,
hover: { enabled: this.innerConfig.hover },
readOnly: this.innerConfig.readOnly,
contextmenu: true,
// fixedOverflowWidgets: true,
folding: true,
glyphMargin: this.innerConfig.editor.enableDebug || this.innerConfig.codeReview.enabled,
};
}
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
timeout = null;
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
;
sendStatus(status) {
this.status = Object.assign({}, status);
this.discoveryCodeStatus.emit(this.status);
}
sendError(error, executionUrl, status) {
this.error = error;
this.discoveryCodeError.emit({ error: this.error, endpoint: executionUrl, status });
}
getLabel() {
switch (this.language) {
case 'flows':
return 'FLoWS';
case 'warpscript':
default:
return 'WarpScript';
}
}
getTheme() {
switch (this.theme) {
case 'dark':
return 'vs-dark';
case 'light':
default:
return 'vs';
}
}
getItems() {
const headers = [];
if (this.showResult) {
headers.push({ name: 'editor', size: this.initialSize ? this.initialSize.p || 50 : 50 });
headers.push({ name: 'result', size: this.initialSize ? 100 - this.initialSize.p || 50 : 50 });
}
else {
headers.push({ name: 'editor', size: 100 });
}
return headers;
}
onKeyDown(event) {
this.LOG.debug(['onKeyDown'], event);
if ((!this.isMac() && !!event.ctrlKey) || (this.isMac() && !!event.metaKey)) {
const vs = this.editor.querySelector('.view-lines');
if (vs) {
Array.from(vs.querySelectorAll('span[class^=mtk]'))
.map(tag => ({ tag, text: tag.textContent.replace(/ /gi, ' ').trim() }))
.filter(tag => this.isClickableWord(tag.text))
.forEach(tag => tag.tag.classList.add('mouseOver'));
}
}
}
isClickableWord(txt) {
const fromLang = this.language == 'warpscript'
? WSLanguageConfiguration.getKeyWords().includes(txt)
: FLoWSLanguageConfiguration.getKeyWords().includes(txt);
const isMacro = txt.startsWith('@');
return txt !== '' && (isMacro || fromLang);
}
onKeyUp(event) {
this.LOG.debug(['onKeyUp'], event);
const vs = this.editor.querySelector('.view-lines');
if (vs) {
Array.from(vs.querySelectorAll('.mouseOver'))
.forEach(e => e.classList.remove('mouseOver'));
}
}
isMac() {
return navigator.userAgent.toUpperCase().indexOf('MAC') >= 0;
}
requestDataviz() {
this.discoveryCodeDataviz.emit(this.result);
}
responsiveStyle() {
return { height: '100%', width: '100%', overflow: 'hidden' };
}
async onResized(e) {
this.LOG.debug(['onResized'], e.detail.editor);
this.discoveryCodeSize.emit(e.detail.editor);
await this.resize(false);
}
render() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
return h("div", { key: '7da5077837e3ae561ac20d83bc310003a9e98fd9', class: 'discovery-code-editor wrapper-main ' + this.theme, ref: el => this.wrapper = el }, h("div", { key: '8557e2bb3b4e72614214b302d27573d2f801a79c', class: "warpscript", ref: el => this.content = el, style: { color: 'transparent', overflow: 'hidden' } }, h("slot", { key: '2163a72a5f76de4900b7b985c44ab7c751ba094d' })), this.loading ? h("div", { class: "loader" }, h("div", { class: "spinner" })) : '', h("div", { key: '7ed1d8a8fb680a7673e468cb6bb6eb0c0310473c', class: "code-wrapper" }, h("wc-split", { key: 'eb2191c72ef0613abc350f3148a83f2df4a1490e', items: this.getItems(), "min-height": "250", onResized: () => this.resizeWatcher() }, h("div", { key: '20fb889fcfa42cf2b218f65826313a698a44d0eb', slot: "editor", class: "editor-wrapper", style: { height: '100%', position: 'relative' } }, h("div", { key: '7160c83ae314c54af0da63316b84429fa67f4445', ref: el => this.editor = el, onKeyDown: e => this.onKeyDown(e), onKeyUp: e => this.onKeyUp(e) }), h("div", { key: '437682bc27c922b220e6ea465b9a674c35917505', class: 'discovery-btn ' + ((_b = (_a = this.innerConfig) === null || _a === void 0 ? void 0 : _a.buttons) === null || _b === void 0 ? void 0 : _b.class), ref: el => this.buttons = el }, this.showDataviz && this.result ?
h("button", { type: "button", class: 'discovery-btn-dataviz ' + ((_d = (_c = this.innerConfig) === null || _c === void 0 ? void 0 : _c.datavizButton) === null || _d === void 0 ? void 0 : _d.class), onClick: () => this.requestDataviz(), innerHTML: (_f = (_e = this.innerConfig) === null || _e === void 0 ? void 0 : _e.datavizButton) === null || _f === void 0 ? void 0 : _f.label }) : '', this.showExecute ?
h("button", { type: "button", class: 'discovery-btn-execute ' + ((_h = (_g = this.innerConfig) === null || _g === void 0 ? void 0 : _g.execButton) === null || _h === void 0 ? void 0 : _h.class), onClick: () => this.execute(), innerHTML: (_k = (_j = this.innerConfig) === null || _j === void 0 ? void 0 : _j.execButton) === null || _k === void 0 ? void 0 : _k.label }) : '')), this.showResult ?
h("div", { slot: "result", style: { height: '100%', paddingBottom: this.displayMessages ? '20px' : '0' } }, h("wc-tabs", { class: "wctabs", selection: this.selectedResultTab, style: { height: '100%' } }, h("wc-tabs-header", { slot: "header", name: "tab1" }, "Results"), h("wc-tabs-header", { slot: "header", name: "tab2" }, "Raw JSON"), this.imageTab ? h("wc-tabs-header", { slot: "header", name: "tab3" }, "Images") : '', h("wc-tabs-content", { slot: "content", name: "tab1" }, h("div", { class: "tab-wrapper" }, h("discovery-code-result", { theme: this.theme, result: this.result, config: this.config }))), h("wc-tabs-content", { slot: "content", name: "tab2", responsive: true }, h("div", { class: 'tab-wrapper ' + this.responsiveStyle() }, h("discovery-code-raw-result", { theme: this.theme, result: this.result, config: this.config, debug: this.debug }))), this.imageTab ? h("wc-tabs-content", { slot: "content", name: "tab3" }, h("div", { class: "tab-wrapper" }, h("discovery-code-image-result", { theme: this.theme, result: this.result, config: this.config, debug: this.debug }))) : '')) : '')), this.displayMessages ?
h("div", { class: "messages" }, this.status ? h("div", { class: ((_l = this.innerConfig) === null || _l === void 0 ? void 0 : _l.messageClass) || 'status-bar', innerHTML: this.status.message }) : '', this.error ? h("div", { class: ((_m = this.innerConfig) === null || _m === void 0 ? void 0 : _m.errorClass) || 'status-bar status-error', innerHTML: this.error }) : '') : '');
}
static get is() { return "discovery-code-editor"; }
static get originalStyleUrls() {
return {
"$": ["discovery-code-editor.scss"]
};
}
static get styleUrls() {
return {
"$": ["discovery-code-editor.css"]
};
}
static get properties() {
return {
"url": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "url",
"reflect": false
},
"bootstrap": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "bootstrap",
"reflect": false
},
"language": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'warpscript' | 'flows'",
"resolved": "\"flows\" | \"warpscript\"",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "language",
"reflect": false,
"defaultValue": "'warpscript'"
},
"existingComments": {
"type": "string",
"mutable": false,
"complexType": {
"original": "ReviewCommentEvent[] | string",
"resolved": "ReviewCommentEvent[] | string",
"references": {
"ReviewCommentEvent": {
"location": "import",
"path": "../../providers/CodeReview",
"id": "src/providers/CodeReview.ts::ReviewCommentEvent"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "existing-comments",
"reflect": false,
"defaultValue": "[]"
},
"debug": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "debug",
"reflect": false,
"defaultValue": "false"
},
"useBootstrap": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "use-bootstrap",
"reflect": false,
"defaultValue": "true"
},
"showDataviz": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "show-dataviz",
"reflect": false,
"defaultValue": "false"
},
"showExecute": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "show-execute",
"reflect": false,
"defaultValue": "false"
},
"showResult": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "show-result",
"reflect": false,
"defaultValue": "false"
},
"displayMessages": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "display-messages",
"reflect": false,
"defaultValue": "false"
},
"imageTab": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "image-tab",
"reflect": false,
"defaultValue": "false"
},
"widthPx": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "width-px",
"reflect": false
},
"heightPx": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "height-px",
"reflect": false
},
"heightLine": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "height-line",
"reflect": false
},
"theme": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'light' | 'dark'",
"resolved": "\"dark\" | \"light\"",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "theme",
"reflect": false,
"defaultValue": "'light'"
},
"code": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "code",
"reflect": false,
"defaultValue": "''"
},
"config": {
"type": "string",
"mutable": false,
"complexType": {
"original": "Config | string",
"resolved": "Config | string",
"references": {
"Config": {
"location": "import",
"path": "../../model/config",
"id": "src/model/config.ts::Config"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "config",
"reflect": false,
"defaultValue": "new Config()"
},
"initialSize": {
"type": "unknown",
"mutable": false,
"complexType": {
"original": "{ w?: number, h?: number, name?: string, p?: number }",
"resolved": "{ w?: number; h?: number; name?: string; p?: number; }",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
}
}
};
}
static get states() {
return {
"selectedResultTab": {},
"result": {},
"status": {},
"error": {},
"innerConfig": {}
};
}
static get events() {
return [{
"method": "discoveryCodeStatus",
"name": "discoveryCodeStatus",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": ""
},
"complexType": {
"original": "any",
"resolved": "any",
"references": {}
}
}, {
"method": "discoveryCodeError",
"name": "discoveryCodeError",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": ""
},
"complexType": {
"original": "any",
"resolved": "any",
"references": {}
}
}, {
"method": "discoveryCodeChanged",
"name": "discoveryCodeChanged",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": ""
},
"complexType": {
"original": "any",
"resolved": "any",
"references": {}
}
}, {
"meth