UNPKG

@senx/discovery-code

Version:

Discovery Code Editor

1,131 lines 62.4 kB
/* * 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(/&nbsp;/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