|
3 | 3 | </template>
|
4 | 4 |
|
5 | 5 | <script lang="ts">
|
6 |
| - import {defineComponent} from "vue"; |
| 6 | + import {defineComponent, h, render} from "vue"; |
7 | 7 | import {mapMutations, mapState} from "vuex";
|
8 | 8 |
|
9 | 9 | import "monaco-editor/esm/vs/editor/editor.all.js";
|
|
21 | 21 | import {configureMonacoYaml} from "monaco-yaml";
|
22 | 22 | import {yamlSchemas} from "override/utils/yamlSchemas";
|
23 | 23 | import Utils from "../../utils/utils";
|
24 |
| - import {YamlUtils as YAML_UTILS} from "@kestra-io/ui-libs"; |
| 24 | + import {TaskIcon, YamlUtils as YAML_UTILS} from "@kestra-io/ui-libs"; |
25 | 25 | import {QUOTE, YamlNoAutoCompletion} from "../../services/autoCompletionProvider.js"
|
26 | 26 | import {FlowAutoCompletion} from "override/services/flowAutoCompletionProvider.js";
|
27 | 27 | import RegexProvider from "../../utils/regex";
|
| 28 | + import uniqBy from "lodash/uniqBy"; |
28 | 29 | import IModel = editor.IModel;
|
29 | 30 | import CompletionList = languages.CompletionList;
|
30 | 31 | import ProviderResult = languages.ProviderResult;
|
|
76 | 77 | flowsInputsCache: {},
|
77 | 78 | autoCompletionProviders: [] as monaco.IDisposable[],
|
78 | 79 | monaco: null as typeof monaco | null,
|
79 |
| - suggestWidgetObserver: undefined as MutationObserver | undefined |
| 80 | + suggestWidgetResizeObserver: undefined as MutationObserver | undefined, |
| 81 | + suggestWidgetIconsObserver: undefined as MutationObserver | undefined, |
| 82 | + suggestWidget: undefined as HTMLElement | undefined, |
80 | 83 | }
|
81 | 84 | },
|
82 | 85 | computed: {
|
83 | 86 | ...mapState("namespace", ["datatypeNamespaces"]),
|
84 | 87 | ...mapState("core", ["monacoYamlConfigured"]),
|
85 | 88 | ...mapState("editor", ["current"]),
|
| 89 | + ...mapState("plugin", ["icons"]), |
86 | 90 | prefix() {
|
87 | 91 | return this.schemaType ? `${this.schemaType}-` : "";
|
88 | 92 | },
|
89 | 93 | },
|
90 |
| -
|
91 | 94 | props: {
|
92 | 95 | path: {
|
93 | 96 | type: String,
|
|
176 | 179 | if (this.$options.editor) {
|
177 | 180 | monaco.editor.setTheme(newVal);
|
178 | 181 | }
|
| 182 | + }, |
| 183 | + suggestWidget(newVal: HTMLElement | undefined) { |
| 184 | + const replaceRowsIcons = (nodes: HTMLElement[]) => { |
| 185 | + nodes = uniqBy(nodes, node => node.id); |
| 186 | + for (let node of nodes) { |
| 187 | + const maybeTaskName = node?.getAttribute("aria-label"); |
| 188 | + if (!maybeTaskName || node.getAttribute("data-index") === null) { |
| 189 | + continue; |
| 190 | + } |
| 191 | +
|
| 192 | + const vsCodeIcon = node.querySelector(".suggest-icon") as HTMLElement; |
| 193 | + const taskIcon = node.querySelector(".wrapper:has(.icon)") as HTMLElement | null; |
| 194 | +
|
| 195 | + if (maybeTaskName.includes(".")) { |
| 196 | + if (this.icons[maybeTaskName] !== undefined) { |
| 197 | + vsCodeIcon.style.display = "none"; |
| 198 | +
|
| 199 | + const tempContainer = document.createElement("div"); |
| 200 | + render(h(TaskIcon, { |
| 201 | + cls: maybeTaskName, |
| 202 | + class: "w-auto h-auto me-1", |
| 203 | + "only-icon": true, |
| 204 | + icons: this.icons |
| 205 | + }), tempContainer); |
| 206 | +
|
| 207 | + if (taskIcon !== null) { |
| 208 | + taskIcon.replaceWith(tempContainer.firstElementChild!); |
| 209 | + } else { |
| 210 | + vsCodeIcon.after(tempContainer.firstElementChild!); |
| 211 | + } |
| 212 | + tempContainer.remove(); |
| 213 | + } |
| 214 | + } else { |
| 215 | + vsCodeIcon.style.display = "revert"; |
| 216 | + taskIcon?.remove(); |
| 217 | + } |
| 218 | + } |
| 219 | + } |
| 220 | +
|
| 221 | + if (newVal !== undefined) { |
| 222 | + if (newVal.querySelector(".monaco-list-row") !== null) { |
| 223 | + replaceRowsIcons([...newVal.getElementsByClassName("monaco-list-row")] as HTMLElement[]); |
| 224 | + } |
| 225 | +
|
| 226 | + this.suggestWidgetIconsObserver?.disconnect(); |
| 227 | + this.suggestWidgetIconsObserver = undefined; |
| 228 | +
|
| 229 | + this.suggestWidgetIconsObserver = new MutationObserver(mutations => { |
| 230 | + replaceRowsIcons( |
| 231 | + mutations.flatMap(({addedNodes}) => { |
| 232 | + const nodes = [...addedNodes] as (Node | HTMLElement)[]; |
| 233 | + const maybeRows: HTMLElement[] = nodes.filter(n => (<HTMLElement>n).classList?.contains("monaco-list-row")) as HTMLElement[]; |
| 234 | +
|
| 235 | + for(let node of nodes) { |
| 236 | + let maybeRow: HTMLElement | null = null; |
| 237 | + if (node instanceof Text) { |
| 238 | + maybeRow = node.parentElement?.closest(".monaco-list-row") as HTMLElement | null; |
| 239 | + } |
| 240 | +
|
| 241 | + if (maybeRow !== null) { |
| 242 | + return [...maybeRows, maybeRow]; |
| 243 | + } |
| 244 | + } |
| 245 | +
|
| 246 | + return maybeRows; |
| 247 | + }) |
| 248 | + ); |
| 249 | + }) |
| 250 | +
|
| 251 | + this.suggestWidgetIconsObserver.observe(newVal, {childList: true, subtree: true}) |
| 252 | + } |
179 | 253 | }
|
180 | 254 | },
|
181 | 255 | mounted: async function () {
|
|
222 | 296 |
|
223 | 297 | if (suggestion.label.includes(".")) {
|
224 | 298 | const dotSplit = suggestion.label.split(/\.(?=\w)/);
|
225 |
| - suggestion.filterText = [dotSplit.pop(), ...dotSplit].join("."); |
| 299 | + const taskName = dotSplit.pop(); |
| 300 | + suggestion.filterText = [taskName, ...dotSplit, taskName].join("."); |
226 | 301 | }
|
227 | 302 | });
|
228 | 303 |
|
|
247 | 322 | },
|
248 | 323 | methods: {
|
249 | 324 | ...mapMutations("editor", ["setTabDirty"]),
|
| 325 | + disposeObservers() { |
| 326 | + if (this.suggestWidgetResizeObserver !== undefined) { |
| 327 | + this.suggestWidgetResizeObserver!.disconnect(); |
| 328 | + this.suggestWidgetResizeObserver = undefined; |
| 329 | + } |
| 330 | + if (this.suggestWidgetIconsObserver !== undefined) { |
| 331 | + this.suggestWidgetIconsObserver!.disconnect(); |
| 332 | + this.suggestWidgetIconsObserver = undefined; |
| 333 | + } |
| 334 | + this.suggestWidget = undefined; |
| 335 | + }, |
250 | 336 | async addKestraAutoCompletions() {
|
251 | 337 | const NO_SUGGESTIONS = {suggestions: []};
|
252 | 338 |
|
|
440 | 526 | * Once the resize has been done, the observer is disconnected and put back to undefined so that new instances of Monaco repeats the process to target the proper DOM element.
|
441 | 527 | */
|
442 | 528 | observeAndResizeSuggestWidget() {
|
443 |
| - if (this.suggestWidgetObserver !== undefined) { |
| 529 | + if (this.suggestWidgetResizeObserver !== undefined) { |
444 | 530 | return;
|
445 | 531 | }
|
446 | 532 |
|
447 |
| - this.suggestWidgetObserver = new MutationObserver(([{ |
| 533 | + this.suggestWidgetResizeObserver = new MutationObserver(([{ |
448 | 534 | target,
|
449 | 535 | addedNodes
|
450 | 536 | }]) => {
|
451 | 537 | const simulateResizeOnSashAndDisconnect = (resizer: HTMLElement) => {
|
452 |
| - this.suggestWidgetObserver?.disconnect(); |
453 |
| - this.suggestWidgetObserver = undefined; |
| 538 | + this.suggestWidgetResizeObserver?.disconnect(); |
| 539 | + this.suggestWidgetResizeObserver = undefined; |
454 | 540 |
|
455 | 541 | const resizerInitialCoordinates = {
|
456 | 542 | x: resizer.getBoundingClientRect().left,
|
|
505 | 591 |
|
506 | 592 | const maybeSuggestWidgetHtmlElement = addedNodes?.[0] as HTMLElement;
|
507 | 593 | if (maybeSuggestWidgetHtmlElement?.classList.contains("suggest-widget")) {
|
508 |
| - const resizer = ([...maybeSuggestWidgetHtmlElement.querySelectorAll(".monaco-sash.vertical")] as HTMLElement[]) |
509 |
| - .sort((a, b) => parseInt(b.style.left) - parseInt(a.style.left))[0]; |
| 594 | + this.suggestWidget = maybeSuggestWidgetHtmlElement; |
| 595 | + const resizer = maybeSuggestWidgetHtmlElement.querySelector(".monaco-sash.vertical") as HTMLElement; |
510 | 596 |
|
511 | 597 | if (resizer.classList.contains("disabled")) {
|
512 |
| - this.suggestWidgetObserver!.disconnect(); |
513 |
| - this.suggestWidgetObserver?.observe(resizer, {attributeFilter: ["class"]}) |
| 598 | + this.suggestWidgetResizeObserver!.disconnect(); |
| 599 | + this.suggestWidgetResizeObserver?.observe(resizer, {attributeFilter: ["class"]}) |
514 | 600 | } else {
|
515 | 601 | simulateResizeOnSashAndDisconnect(resizer);
|
516 | 602 | }
|
517 | 603 | }
|
518 | 604 | });
|
519 | 605 |
|
520 |
| - this.suggestWidgetObserver.observe(this.$el.querySelector(".overflowingContentWidgets"), {childList: true}) |
| 606 | + this.suggestWidgetResizeObserver.observe(this.$el.querySelector(".overflowingContentWidgets"), {childList: true}) |
521 | 607 | },
|
522 | 608 | initMonaco: async function () {
|
523 | 609 | let self = this;
|
|
640 | 726 | this.$options.editor.focus();
|
641 | 727 | },
|
642 | 728 | destroy: function () {
|
643 |
| - this.suggestWidgetObserver?.disconnect(); |
| 729 | + this.disposeObservers(); |
644 | 730 | this.autoCompletionProviders.forEach(provider => provider.dispose());
|
645 | 731 | this.$options.editor?.getModel()?.dispose?.();
|
646 | 732 | this.$options.editor?.dispose?.();
|
|
0 commit comments