@n8n/composables 1.22.0 → 1.23.1

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.
@@ -10,7 +10,8 @@ function useClipboard({ onPaste: onPasteFn = () => {} } = {}) {
10
10
  async function copy(value) {
11
11
  const nav = popOutWindow?.value?.navigator;
12
12
  if (nav?.clipboard) try {
13
- await nav.clipboard.writeText(value);
13
+ const resolvedValue = typeof value === "function" ? await value() : value;
14
+ await nav.clipboard.writeText(resolvedValue);
14
15
  return;
15
16
  } catch {}
16
17
  await coreCopy(value);
@@ -1 +1 @@
1
- {"version":3,"file":"useClipboard.cjs","names":["PopOutWindowKey"],"sources":["../src/useClipboard.ts"],"sourcesContent":["import { useClipboard as useClipboardCore, useThrottleFn } from '@vueuse/core';\nimport { inject, onBeforeUnmount, onMounted, ref } from 'vue';\n\nimport { PopOutWindowKey } from './injectionKeys';\n\ntype ClipboardEventFn = (data: string, event?: ClipboardEvent) => void;\n\nexport function useClipboard({\n\tonPaste: onPasteFn = () => {},\n}: {\n\tonPaste?: ClipboardEventFn;\n} = {}) {\n\tconst popOutWindow = inject(PopOutWindowKey, ref<Window | undefined>());\n\tconst {\n\t\tcopy: coreCopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t} = useClipboardCore({\n\t\tlegacy: true,\n\t});\n\n\t// Find the correct navigator at copy-time so it works even when the\n\t// pop-out window opens after the composable was created.\n\tasync function copy(value: string) {\n\t\tconst nav = popOutWindow?.value?.navigator;\n\t\tif (nav?.clipboard) {\n\t\t\ttry {\n\t\t\t\tawait nav.clipboard.writeText(value);\n\t\t\t\treturn;\n\t\t\t} catch {\n\t\t\t\t// Fall back to the core clipboard copy below.\n\t\t\t}\n\t\t}\n\t\tawait coreCopy(value);\n\t}\n\n\tconst ignoreClasses = ['el-messsage-box', 'ignore-key-press-canvas'];\n\tconst initialized = ref(false);\n\n\tconst onPasteCallback = ref<ClipboardEventFn | null>(onPasteFn || null);\n\n\t/**\n\t * Handles copy/paste events\n\t * @param event\n\t */\n\tfunction onPaste(event: ClipboardEvent) {\n\t\tif (!onPasteCallback.value) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if the event got emitted from a message box or from something\n\t\t// else which should ignore the copy/paste\n\t\tconst path = event.composedPath?.() as HTMLElement[];\n\t\tfor (const pathElement of path) {\n\t\t\tif (\n\t\t\t\tpathElement.className &&\n\t\t\t\tignoreClasses.some((className) => pathElement.className.includes?.(className))\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst clipboardData = event.clipboardData;\n\t\tif (clipboardData !== null) {\n\t\t\tconst clipboardValue = clipboardData.getData('text/plain');\n\t\t\tonPasteCallback.value(clipboardValue, event);\n\t\t}\n\t}\n\n\tconst throttledOnPaste = useThrottleFn(onPaste, 1000);\n\n\t/**\n\t * Initialize copy/paste elements and events\n\t */\n\tonMounted(() => {\n\t\tif (initialized.value) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.addEventListener('paste', throttledOnPaste);\n\n\t\tinitialized.value = true;\n\t});\n\n\t/**\n\t * Remove copy/paste elements and events\n\t */\n\tonBeforeUnmount(() => {\n\t\tif (initialized.value) {\n\t\t\tdocument.removeEventListener('paste', throttledOnPaste);\n\t\t}\n\t});\n\n\treturn {\n\t\tcopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t\tonPaste: onPasteCallback,\n\t};\n}\n"],"mappings":";;;;;;AAOA,SAAgB,aAAa,EAC5B,SAAS,kBAAkB,OAGxB,EAAE,EAAE;CACP,MAAM,+BAAsBA,qDAA0C,CAAC;CACvE,MAAM,EACL,MAAM,UACN,QACA,aACA,yCACoB,EACpB,QAAQ,MACR,CAAC;CAIF,eAAe,KAAK,OAAe;EAClC,MAAM,MAAM,cAAc,OAAO;AACjC,MAAI,KAAK,UACR,KAAI;AACH,SAAM,IAAI,UAAU,UAAU,MAAM;AACpC;UACO;AAIT,QAAM,SAAS,MAAM;;CAGtB,MAAM,gBAAgB,CAAC,mBAAmB,0BAA0B;CACpE,MAAM,2BAAkB,MAAM;CAE9B,MAAM,+BAA+C,aAAa,KAAK;;;;;CAMvE,SAAS,QAAQ,OAAuB;AACvC,MAAI,CAAC,gBAAgB,MACpB;EAKD,MAAM,OAAO,MAAM,gBAAgB;AACnC,OAAK,MAAM,eAAe,KACzB,KACC,YAAY,aACZ,cAAc,MAAM,cAAc,YAAY,UAAU,WAAW,UAAU,CAAC,CAE9E;EAIF,MAAM,gBAAgB,MAAM;AAC5B,MAAI,kBAAkB,MAAM;GAC3B,MAAM,iBAAiB,cAAc,QAAQ,aAAa;AAC1D,mBAAgB,MAAM,gBAAgB,MAAM;;;CAI9C,MAAM,oDAAiC,SAAS,IAAK;;;;AAKrD,0BAAgB;AACf,MAAI,YAAY,MACf;AAGD,WAAS,iBAAiB,SAAS,iBAAiB;AAEpD,cAAY,QAAQ;GACnB;;;;AAKF,gCAAsB;AACrB,MAAI,YAAY,MACf,UAAS,oBAAoB,SAAS,iBAAiB;GAEvD;AAEF,QAAO;EACN;EACA;EACA;EACA;EACA,SAAS;EACT"}
1
+ {"version":3,"file":"useClipboard.cjs","names":["PopOutWindowKey"],"sources":["../src/useClipboard.ts"],"sourcesContent":["import { useClipboard as useClipboardCore, useThrottleFn } from '@vueuse/core';\nimport { inject, onBeforeUnmount, onMounted, ref } from 'vue';\n\nimport { PopOutWindowKey } from './injectionKeys';\n\ntype ClipboardEventFn = (data: string, event?: ClipboardEvent) => void;\n\nexport function useClipboard({\n\tonPaste: onPasteFn = () => {},\n}: {\n\tonPaste?: ClipboardEventFn;\n} = {}) {\n\tconst popOutWindow = inject(PopOutWindowKey, ref<Window | undefined>());\n\tconst {\n\t\tcopy: coreCopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t} = useClipboardCore({\n\t\tlegacy: true,\n\t});\n\n\t// Find the correct navigator at copy-time so it works even when the\n\t// pop-out window opens after the composable was created.\n\tasync function copy(value: string | (() => Promise<string>)) {\n\t\tconst nav = popOutWindow?.value?.navigator;\n\t\tif (nav?.clipboard) {\n\t\t\ttry {\n\t\t\t\tconst resolvedValue = typeof value === 'function' ? await value() : value;\n\t\t\t\tawait nav.clipboard.writeText(resolvedValue);\n\t\t\t\treturn;\n\t\t\t} catch {\n\t\t\t\t// Fall back to the core clipboard copy below.\n\t\t\t}\n\t\t}\n\t\tawait coreCopy(value);\n\t}\n\n\tconst ignoreClasses = ['el-messsage-box', 'ignore-key-press-canvas'];\n\tconst initialized = ref(false);\n\n\tconst onPasteCallback = ref<ClipboardEventFn | null>(onPasteFn || null);\n\n\t/**\n\t * Handles copy/paste events\n\t * @param event\n\t */\n\tfunction onPaste(event: ClipboardEvent) {\n\t\tif (!onPasteCallback.value) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if the event got emitted from a message box or from something\n\t\t// else which should ignore the copy/paste\n\t\tconst path = event.composedPath?.() as HTMLElement[];\n\t\tfor (const pathElement of path) {\n\t\t\tif (\n\t\t\t\tpathElement.className &&\n\t\t\t\tignoreClasses.some((className) => pathElement.className.includes?.(className))\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst clipboardData = event.clipboardData;\n\t\tif (clipboardData !== null) {\n\t\t\tconst clipboardValue = clipboardData.getData('text/plain');\n\t\t\tonPasteCallback.value(clipboardValue, event);\n\t\t}\n\t}\n\n\tconst throttledOnPaste = useThrottleFn(onPaste, 1000);\n\n\t/**\n\t * Initialize copy/paste elements and events\n\t */\n\tonMounted(() => {\n\t\tif (initialized.value) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.addEventListener('paste', throttledOnPaste);\n\n\t\tinitialized.value = true;\n\t});\n\n\t/**\n\t * Remove copy/paste elements and events\n\t */\n\tonBeforeUnmount(() => {\n\t\tif (initialized.value) {\n\t\t\tdocument.removeEventListener('paste', throttledOnPaste);\n\t\t}\n\t});\n\n\treturn {\n\t\tcopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t\tonPaste: onPasteCallback,\n\t};\n}\n"],"mappings":";;;;;;AAOA,SAAgB,aAAa,EAC5B,SAAS,kBAAkB,OAGxB,EAAE,EAAE;CACP,MAAM,+BAAsBA,qDAA0C,CAAC;CACvE,MAAM,EACL,MAAM,UACN,QACA,aACA,yCACoB,EACpB,QAAQ,MACR,CAAC;CAIF,eAAe,KAAK,OAAyC;EAC5D,MAAM,MAAM,cAAc,OAAO;AACjC,MAAI,KAAK,UACR,KAAI;GACH,MAAM,gBAAgB,OAAO,UAAU,aAAa,MAAM,OAAO,GAAG;AACpE,SAAM,IAAI,UAAU,UAAU,cAAc;AAC5C;UACO;AAIT,QAAM,SAAS,MAAM;;CAGtB,MAAM,gBAAgB,CAAC,mBAAmB,0BAA0B;CACpE,MAAM,2BAAkB,MAAM;CAE9B,MAAM,+BAA+C,aAAa,KAAK;;;;;CAMvE,SAAS,QAAQ,OAAuB;AACvC,MAAI,CAAC,gBAAgB,MACpB;EAKD,MAAM,OAAO,MAAM,gBAAgB;AACnC,OAAK,MAAM,eAAe,KACzB,KACC,YAAY,aACZ,cAAc,MAAM,cAAc,YAAY,UAAU,WAAW,UAAU,CAAC,CAE9E;EAIF,MAAM,gBAAgB,MAAM;AAC5B,MAAI,kBAAkB,MAAM;GAC3B,MAAM,iBAAiB,cAAc,QAAQ,aAAa;AAC1D,mBAAgB,MAAM,gBAAgB,MAAM;;;CAI9C,MAAM,oDAAiC,SAAS,IAAK;;;;AAKrD,0BAAgB;AACf,MAAI,YAAY,MACf;AAGD,WAAS,iBAAiB,SAAS,iBAAiB;AAEpD,cAAY,QAAQ;GACnB;;;;AAKF,gCAAsB;AACrB,MAAI,YAAY,MACf,UAAS,oBAAoB,SAAS,iBAAiB;GAEvD;AAEF,QAAO;EACN;EACA;EACA;EACA;EACA,SAAS;EACT"}
@@ -7,7 +7,7 @@ declare function useClipboard({
7
7
  }?: {
8
8
  onPaste?: ClipboardEventFn;
9
9
  }): {
10
- copy: (value: string) => Promise<void>;
10
+ copy: (value: string | (() => Promise<string>)) => Promise<void>;
11
11
  copied: Readonly<vue0.ShallowRef<boolean>>;
12
12
  isSupported: vue0.ComputedRef<boolean>;
13
13
  text: Readonly<vue0.ShallowRef<string>>;
@@ -7,7 +7,7 @@ declare function useClipboard({
7
7
  }?: {
8
8
  onPaste?: ClipboardEventFn;
9
9
  }): {
10
- copy: (value: string) => Promise<void>;
10
+ copy: (value: string | (() => Promise<string>)) => Promise<void>;
11
11
  copied: Readonly<vue0.ShallowRef<boolean>>;
12
12
  isSupported: vue0.ComputedRef<boolean>;
13
13
  text: Readonly<vue0.ShallowRef<string>>;
@@ -9,7 +9,8 @@ function useClipboard({ onPaste: onPasteFn = () => {} } = {}) {
9
9
  async function copy(value) {
10
10
  const nav = popOutWindow?.value?.navigator;
11
11
  if (nav?.clipboard) try {
12
- await nav.clipboard.writeText(value);
12
+ const resolvedValue = typeof value === "function" ? await value() : value;
13
+ await nav.clipboard.writeText(resolvedValue);
13
14
  return;
14
15
  } catch {}
15
16
  await coreCopy(value);
@@ -1 +1 @@
1
- {"version":3,"file":"useClipboard.mjs","names":["useClipboardCore"],"sources":["../src/useClipboard.ts"],"sourcesContent":["import { useClipboard as useClipboardCore, useThrottleFn } from '@vueuse/core';\nimport { inject, onBeforeUnmount, onMounted, ref } from 'vue';\n\nimport { PopOutWindowKey } from './injectionKeys';\n\ntype ClipboardEventFn = (data: string, event?: ClipboardEvent) => void;\n\nexport function useClipboard({\n\tonPaste: onPasteFn = () => {},\n}: {\n\tonPaste?: ClipboardEventFn;\n} = {}) {\n\tconst popOutWindow = inject(PopOutWindowKey, ref<Window | undefined>());\n\tconst {\n\t\tcopy: coreCopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t} = useClipboardCore({\n\t\tlegacy: true,\n\t});\n\n\t// Find the correct navigator at copy-time so it works even when the\n\t// pop-out window opens after the composable was created.\n\tasync function copy(value: string) {\n\t\tconst nav = popOutWindow?.value?.navigator;\n\t\tif (nav?.clipboard) {\n\t\t\ttry {\n\t\t\t\tawait nav.clipboard.writeText(value);\n\t\t\t\treturn;\n\t\t\t} catch {\n\t\t\t\t// Fall back to the core clipboard copy below.\n\t\t\t}\n\t\t}\n\t\tawait coreCopy(value);\n\t}\n\n\tconst ignoreClasses = ['el-messsage-box', 'ignore-key-press-canvas'];\n\tconst initialized = ref(false);\n\n\tconst onPasteCallback = ref<ClipboardEventFn | null>(onPasteFn || null);\n\n\t/**\n\t * Handles copy/paste events\n\t * @param event\n\t */\n\tfunction onPaste(event: ClipboardEvent) {\n\t\tif (!onPasteCallback.value) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if the event got emitted from a message box or from something\n\t\t// else which should ignore the copy/paste\n\t\tconst path = event.composedPath?.() as HTMLElement[];\n\t\tfor (const pathElement of path) {\n\t\t\tif (\n\t\t\t\tpathElement.className &&\n\t\t\t\tignoreClasses.some((className) => pathElement.className.includes?.(className))\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst clipboardData = event.clipboardData;\n\t\tif (clipboardData !== null) {\n\t\t\tconst clipboardValue = clipboardData.getData('text/plain');\n\t\t\tonPasteCallback.value(clipboardValue, event);\n\t\t}\n\t}\n\n\tconst throttledOnPaste = useThrottleFn(onPaste, 1000);\n\n\t/**\n\t * Initialize copy/paste elements and events\n\t */\n\tonMounted(() => {\n\t\tif (initialized.value) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.addEventListener('paste', throttledOnPaste);\n\n\t\tinitialized.value = true;\n\t});\n\n\t/**\n\t * Remove copy/paste elements and events\n\t */\n\tonBeforeUnmount(() => {\n\t\tif (initialized.value) {\n\t\t\tdocument.removeEventListener('paste', throttledOnPaste);\n\t\t}\n\t});\n\n\treturn {\n\t\tcopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t\tonPaste: onPasteCallback,\n\t};\n}\n"],"mappings":";;;;;AAOA,SAAgB,aAAa,EAC5B,SAAS,kBAAkB,OAGxB,EAAE,EAAE;CACP,MAAM,eAAe,OAAO,iBAAiB,KAAyB,CAAC;CACvE,MAAM,EACL,MAAM,UACN,QACA,aACA,SACGA,eAAiB,EACpB,QAAQ,MACR,CAAC;CAIF,eAAe,KAAK,OAAe;EAClC,MAAM,MAAM,cAAc,OAAO;AACjC,MAAI,KAAK,UACR,KAAI;AACH,SAAM,IAAI,UAAU,UAAU,MAAM;AACpC;UACO;AAIT,QAAM,SAAS,MAAM;;CAGtB,MAAM,gBAAgB,CAAC,mBAAmB,0BAA0B;CACpE,MAAM,cAAc,IAAI,MAAM;CAE9B,MAAM,kBAAkB,IAA6B,aAAa,KAAK;;;;;CAMvE,SAAS,QAAQ,OAAuB;AACvC,MAAI,CAAC,gBAAgB,MACpB;EAKD,MAAM,OAAO,MAAM,gBAAgB;AACnC,OAAK,MAAM,eAAe,KACzB,KACC,YAAY,aACZ,cAAc,MAAM,cAAc,YAAY,UAAU,WAAW,UAAU,CAAC,CAE9E;EAIF,MAAM,gBAAgB,MAAM;AAC5B,MAAI,kBAAkB,MAAM;GAC3B,MAAM,iBAAiB,cAAc,QAAQ,aAAa;AAC1D,mBAAgB,MAAM,gBAAgB,MAAM;;;CAI9C,MAAM,mBAAmB,cAAc,SAAS,IAAK;;;;AAKrD,iBAAgB;AACf,MAAI,YAAY,MACf;AAGD,WAAS,iBAAiB,SAAS,iBAAiB;AAEpD,cAAY,QAAQ;GACnB;;;;AAKF,uBAAsB;AACrB,MAAI,YAAY,MACf,UAAS,oBAAoB,SAAS,iBAAiB;GAEvD;AAEF,QAAO;EACN;EACA;EACA;EACA;EACA,SAAS;EACT"}
1
+ {"version":3,"file":"useClipboard.mjs","names":["useClipboardCore"],"sources":["../src/useClipboard.ts"],"sourcesContent":["import { useClipboard as useClipboardCore, useThrottleFn } from '@vueuse/core';\nimport { inject, onBeforeUnmount, onMounted, ref } from 'vue';\n\nimport { PopOutWindowKey } from './injectionKeys';\n\ntype ClipboardEventFn = (data: string, event?: ClipboardEvent) => void;\n\nexport function useClipboard({\n\tonPaste: onPasteFn = () => {},\n}: {\n\tonPaste?: ClipboardEventFn;\n} = {}) {\n\tconst popOutWindow = inject(PopOutWindowKey, ref<Window | undefined>());\n\tconst {\n\t\tcopy: coreCopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t} = useClipboardCore({\n\t\tlegacy: true,\n\t});\n\n\t// Find the correct navigator at copy-time so it works even when the\n\t// pop-out window opens after the composable was created.\n\tasync function copy(value: string | (() => Promise<string>)) {\n\t\tconst nav = popOutWindow?.value?.navigator;\n\t\tif (nav?.clipboard) {\n\t\t\ttry {\n\t\t\t\tconst resolvedValue = typeof value === 'function' ? await value() : value;\n\t\t\t\tawait nav.clipboard.writeText(resolvedValue);\n\t\t\t\treturn;\n\t\t\t} catch {\n\t\t\t\t// Fall back to the core clipboard copy below.\n\t\t\t}\n\t\t}\n\t\tawait coreCopy(value);\n\t}\n\n\tconst ignoreClasses = ['el-messsage-box', 'ignore-key-press-canvas'];\n\tconst initialized = ref(false);\n\n\tconst onPasteCallback = ref<ClipboardEventFn | null>(onPasteFn || null);\n\n\t/**\n\t * Handles copy/paste events\n\t * @param event\n\t */\n\tfunction onPaste(event: ClipboardEvent) {\n\t\tif (!onPasteCallback.value) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if the event got emitted from a message box or from something\n\t\t// else which should ignore the copy/paste\n\t\tconst path = event.composedPath?.() as HTMLElement[];\n\t\tfor (const pathElement of path) {\n\t\t\tif (\n\t\t\t\tpathElement.className &&\n\t\t\t\tignoreClasses.some((className) => pathElement.className.includes?.(className))\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst clipboardData = event.clipboardData;\n\t\tif (clipboardData !== null) {\n\t\t\tconst clipboardValue = clipboardData.getData('text/plain');\n\t\t\tonPasteCallback.value(clipboardValue, event);\n\t\t}\n\t}\n\n\tconst throttledOnPaste = useThrottleFn(onPaste, 1000);\n\n\t/**\n\t * Initialize copy/paste elements and events\n\t */\n\tonMounted(() => {\n\t\tif (initialized.value) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocument.addEventListener('paste', throttledOnPaste);\n\n\t\tinitialized.value = true;\n\t});\n\n\t/**\n\t * Remove copy/paste elements and events\n\t */\n\tonBeforeUnmount(() => {\n\t\tif (initialized.value) {\n\t\t\tdocument.removeEventListener('paste', throttledOnPaste);\n\t\t}\n\t});\n\n\treturn {\n\t\tcopy,\n\t\tcopied,\n\t\tisSupported,\n\t\ttext,\n\t\tonPaste: onPasteCallback,\n\t};\n}\n"],"mappings":";;;;;AAOA,SAAgB,aAAa,EAC5B,SAAS,kBAAkB,OAGxB,EAAE,EAAE;CACP,MAAM,eAAe,OAAO,iBAAiB,KAAyB,CAAC;CACvE,MAAM,EACL,MAAM,UACN,QACA,aACA,SACGA,eAAiB,EACpB,QAAQ,MACR,CAAC;CAIF,eAAe,KAAK,OAAyC;EAC5D,MAAM,MAAM,cAAc,OAAO;AACjC,MAAI,KAAK,UACR,KAAI;GACH,MAAM,gBAAgB,OAAO,UAAU,aAAa,MAAM,OAAO,GAAG;AACpE,SAAM,IAAI,UAAU,UAAU,cAAc;AAC5C;UACO;AAIT,QAAM,SAAS,MAAM;;CAGtB,MAAM,gBAAgB,CAAC,mBAAmB,0BAA0B;CACpE,MAAM,cAAc,IAAI,MAAM;CAE9B,MAAM,kBAAkB,IAA6B,aAAa,KAAK;;;;;CAMvE,SAAS,QAAQ,OAAuB;AACvC,MAAI,CAAC,gBAAgB,MACpB;EAKD,MAAM,OAAO,MAAM,gBAAgB;AACnC,OAAK,MAAM,eAAe,KACzB,KACC,YAAY,aACZ,cAAc,MAAM,cAAc,YAAY,UAAU,WAAW,UAAU,CAAC,CAE9E;EAIF,MAAM,gBAAgB,MAAM;AAC5B,MAAI,kBAAkB,MAAM;GAC3B,MAAM,iBAAiB,cAAc,QAAQ,aAAa;AAC1D,mBAAgB,MAAM,gBAAgB,MAAM;;;CAI9C,MAAM,mBAAmB,cAAc,SAAS,IAAK;;;;AAKrD,iBAAgB;AACf,MAAI,YAAY,MACf;AAGD,WAAS,iBAAiB,SAAS,iBAAiB;AAEpD,cAAY,QAAQ;GACnB;;;;AAKF,uBAAsB;AACrB,MAAI,YAAY,MACf,UAAS,oBAAoB,SAAS,iBAAiB;GAEvD;AAEF,QAAO;EACN;EACA;EACA;EACA;EACA,SAAS;EACT"}
@@ -1,4 +1,4 @@
1
- import * as vue3 from "vue";
1
+ import * as vue0 from "vue";
2
2
 
3
3
  //#region src/useDeviceSupport.d.ts
4
4
  declare function useDeviceSupport(): {
@@ -9,7 +9,7 @@ declare function useDeviceSupport(): {
9
9
  isMacOs: boolean;
10
10
  isMobileDevice: boolean;
11
11
  controlKeyCode: string;
12
- controlKeyText: vue3.ComputedRef<"⌘" | "Ctrl">;
12
+ controlKeyText: vue0.ComputedRef<"⌘" | "Ctrl">;
13
13
  isCtrlKeyPressed: (e: MouseEvent | KeyboardEvent) => boolean;
14
14
  };
15
15
  //#endregion
@@ -0,0 +1,5 @@
1
+ const require_useExternalHooks = require('./useExternalHooks2.cjs');
2
+
3
+ exports.ExternalHooksKey = require_useExternalHooks.ExternalHooksKey;
4
+ exports.setExternalHooks = require_useExternalHooks.setExternalHooks;
5
+ exports.useExternalHooks = require_useExternalHooks.useExternalHooks;
@@ -0,0 +1,12 @@
1
+ import { InjectionKey } from "vue";
2
+
3
+ //#region src/useExternalHooks.d.ts
4
+ interface ExternalHooks {
5
+ run(eventName: string, metadata?: unknown): Promise<void>;
6
+ }
7
+ declare const ExternalHooksKey: InjectionKey<ExternalHooks>;
8
+ declare function setExternalHooks(instance: ExternalHooks | undefined): void;
9
+ declare function useExternalHooks(): ExternalHooks;
10
+ //#endregion
11
+ export { ExternalHooks, ExternalHooksKey, setExternalHooks, useExternalHooks };
12
+ //# sourceMappingURL=useExternalHooks.d.cts.map
@@ -0,0 +1,12 @@
1
+ import { InjectionKey } from "vue";
2
+
3
+ //#region src/useExternalHooks.d.ts
4
+ interface ExternalHooks {
5
+ run(eventName: string, metadata?: unknown): Promise<void>;
6
+ }
7
+ declare const ExternalHooksKey: InjectionKey<ExternalHooks>;
8
+ declare function setExternalHooks(instance: ExternalHooks | undefined): void;
9
+ declare function useExternalHooks(): ExternalHooks;
10
+ //#endregion
11
+ export { ExternalHooks, ExternalHooksKey, setExternalHooks, useExternalHooks };
12
+ //# sourceMappingURL=useExternalHooks.d.mts.map
@@ -0,0 +1,3 @@
1
+ import { n as setExternalHooks, r as useExternalHooks, t as ExternalHooksKey } from "./useExternalHooks2.mjs";
2
+
3
+ export { ExternalHooksKey, setExternalHooks, useExternalHooks };
@@ -0,0 +1,56 @@
1
+ const require_useDebounce = require('./useDebounce.cjs');
2
+ let vue = require("vue");
3
+
4
+ //#region src/useExternalHooks.ts
5
+ /**
6
+ * Injection key for the external-hooks runner. The application may provide it
7
+ * (e.g. a pop-out window with its own runner); `useExternalHooks` reads it when
8
+ * called inside an injection context and otherwise falls back to the registered
9
+ * singleton.
10
+ */
11
+ const ExternalHooksKey = Symbol("ExternalHooks");
12
+ /**
13
+ * Null-object runner used when no concrete runner has been registered (e.g. in
14
+ * tests, or before bootstrap). External hooks are best-effort and must never
15
+ * throw or block the UI, so `run` resolves to a no-op.
16
+ */
17
+ const noopExternalHooks = { async run() {} };
18
+ let registeredExternalHooks;
19
+ /**
20
+ * Register the application's external-hooks runner. Called once at bootstrap by
21
+ * `editor-ui` so package-side `useExternalHooks` can resolve it from any
22
+ * context, including outside of component setup (routers, stores, plain
23
+ * modules).
24
+ */
25
+ function setExternalHooks(instance) {
26
+ registeredExternalHooks = instance;
27
+ }
28
+ /**
29
+ * Returns the active external-hooks runner. Resolution order: a
30
+ * component-provided runner (via {@link ExternalHooksKey}), then the
31
+ * app-registered singleton (via {@link setExternalHooks}), then a no-op fallback.
32
+ */
33
+ function useExternalHooks() {
34
+ return ((0, vue.hasInjectionContext)() ? (0, vue.inject)(ExternalHooksKey, null) : null) ?? registeredExternalHooks ?? noopExternalHooks;
35
+ }
36
+
37
+ //#endregion
38
+ Object.defineProperty(exports, 'ExternalHooksKey', {
39
+ enumerable: true,
40
+ get: function () {
41
+ return ExternalHooksKey;
42
+ }
43
+ });
44
+ Object.defineProperty(exports, 'setExternalHooks', {
45
+ enumerable: true,
46
+ get: function () {
47
+ return setExternalHooks;
48
+ }
49
+ });
50
+ Object.defineProperty(exports, 'useExternalHooks', {
51
+ enumerable: true,
52
+ get: function () {
53
+ return useExternalHooks;
54
+ }
55
+ });
56
+ //# sourceMappingURL=useExternalHooks2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExternalHooks2.cjs","names":["ExternalHooksKey: InjectionKey<ExternalHooks>","noopExternalHooks: ExternalHooks","registeredExternalHooks: ExternalHooks | undefined"],"sources":["../src/useExternalHooks.ts"],"sourcesContent":["import { hasInjectionContext, inject, type InjectionKey } from 'vue';\n\n/**\n * The external-hooks contract consumed across the frontend. External hooks are\n * an extension point: enterprise/embed builds register handlers on\n * `window.n8nExternalHooks`, and `run` dispatches a named event to them.\n *\n * This package owns the *type* only; the concrete runner lives in the\n * application (`editor-ui`) and is registered at bootstrap via\n * {@link setExternalHooks} / provided through {@link ExternalHooksKey}. Keeping\n * the contract here lets `useExternalHooks` return a working runner without the\n * package importing application code (notably the webhooks store).\n *\n * The contract is intentionally loose (`eventName: string`, `metadata:\n * unknown`): the strongly-typed event map stays in `editor-ui`, and the\n * application's public wrapper preserves per-event type-checking for call\n * sites that import it directly.\n */\nexport interface ExternalHooks {\n\trun(eventName: string, metadata?: unknown): Promise<void>;\n}\n\n/**\n * Injection key for the external-hooks runner. The application may provide it\n * (e.g. a pop-out window with its own runner); `useExternalHooks` reads it when\n * called inside an injection context and otherwise falls back to the registered\n * singleton.\n */\nexport const ExternalHooksKey: InjectionKey<ExternalHooks> = Symbol('ExternalHooks');\n\n/**\n * Null-object runner used when no concrete runner has been registered (e.g. in\n * tests, or before bootstrap). External hooks are best-effort and must never\n * throw or block the UI, so `run` resolves to a no-op.\n */\nconst noopExternalHooks: ExternalHooks = {\n\tasync run() {},\n};\n\nlet registeredExternalHooks: ExternalHooks | undefined;\n\n/**\n * Register the application's external-hooks runner. Called once at bootstrap by\n * `editor-ui` so package-side `useExternalHooks` can resolve it from any\n * context, including outside of component setup (routers, stores, plain\n * modules).\n */\nexport function setExternalHooks(instance: ExternalHooks | undefined): void {\n\tregisteredExternalHooks = instance;\n}\n\n/**\n * Returns the active external-hooks runner. Resolution order: a\n * component-provided runner (via {@link ExternalHooksKey}), then the\n * app-registered singleton (via {@link setExternalHooks}), then a no-op fallback.\n */\nexport function useExternalHooks(): ExternalHooks {\n\tconst injected = hasInjectionContext() ? inject(ExternalHooksKey, null) : null;\n\treturn injected ?? registeredExternalHooks ?? noopExternalHooks;\n}\n"],"mappings":";;;;;;;;;;AA4BA,MAAaA,mBAAgD,OAAO,gBAAgB;;;;;;AAOpF,MAAMC,oBAAmC,EACxC,MAAM,MAAM,IACZ;AAED,IAAIC;;;;;;;AAQJ,SAAgB,iBAAiB,UAA2C;AAC3E,2BAA0B;;;;;;;AAQ3B,SAAgB,mBAAkC;AAEjD,uCADsC,mBAAU,kBAAkB,KAAK,GAAG,SACvD,2BAA2B"}
@@ -0,0 +1,38 @@
1
+ import { hasInjectionContext, inject } from "vue";
2
+
3
+ //#region src/useExternalHooks.ts
4
+ /**
5
+ * Injection key for the external-hooks runner. The application may provide it
6
+ * (e.g. a pop-out window with its own runner); `useExternalHooks` reads it when
7
+ * called inside an injection context and otherwise falls back to the registered
8
+ * singleton.
9
+ */
10
+ const ExternalHooksKey = Symbol("ExternalHooks");
11
+ /**
12
+ * Null-object runner used when no concrete runner has been registered (e.g. in
13
+ * tests, or before bootstrap). External hooks are best-effort and must never
14
+ * throw or block the UI, so `run` resolves to a no-op.
15
+ */
16
+ const noopExternalHooks = { async run() {} };
17
+ let registeredExternalHooks;
18
+ /**
19
+ * Register the application's external-hooks runner. Called once at bootstrap by
20
+ * `editor-ui` so package-side `useExternalHooks` can resolve it from any
21
+ * context, including outside of component setup (routers, stores, plain
22
+ * modules).
23
+ */
24
+ function setExternalHooks(instance) {
25
+ registeredExternalHooks = instance;
26
+ }
27
+ /**
28
+ * Returns the active external-hooks runner. Resolution order: a
29
+ * component-provided runner (via {@link ExternalHooksKey}), then the
30
+ * app-registered singleton (via {@link setExternalHooks}), then a no-op fallback.
31
+ */
32
+ function useExternalHooks() {
33
+ return (hasInjectionContext() ? inject(ExternalHooksKey, null) : null) ?? registeredExternalHooks ?? noopExternalHooks;
34
+ }
35
+
36
+ //#endregion
37
+ export { setExternalHooks as n, useExternalHooks as r, ExternalHooksKey as t };
38
+ //# sourceMappingURL=useExternalHooks2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExternalHooks2.mjs","names":["ExternalHooksKey: InjectionKey<ExternalHooks>","noopExternalHooks: ExternalHooks","registeredExternalHooks: ExternalHooks | undefined"],"sources":["../src/useExternalHooks.ts"],"sourcesContent":["import { hasInjectionContext, inject, type InjectionKey } from 'vue';\n\n/**\n * The external-hooks contract consumed across the frontend. External hooks are\n * an extension point: enterprise/embed builds register handlers on\n * `window.n8nExternalHooks`, and `run` dispatches a named event to them.\n *\n * This package owns the *type* only; the concrete runner lives in the\n * application (`editor-ui`) and is registered at bootstrap via\n * {@link setExternalHooks} / provided through {@link ExternalHooksKey}. Keeping\n * the contract here lets `useExternalHooks` return a working runner without the\n * package importing application code (notably the webhooks store).\n *\n * The contract is intentionally loose (`eventName: string`, `metadata:\n * unknown`): the strongly-typed event map stays in `editor-ui`, and the\n * application's public wrapper preserves per-event type-checking for call\n * sites that import it directly.\n */\nexport interface ExternalHooks {\n\trun(eventName: string, metadata?: unknown): Promise<void>;\n}\n\n/**\n * Injection key for the external-hooks runner. The application may provide it\n * (e.g. a pop-out window with its own runner); `useExternalHooks` reads it when\n * called inside an injection context and otherwise falls back to the registered\n * singleton.\n */\nexport const ExternalHooksKey: InjectionKey<ExternalHooks> = Symbol('ExternalHooks');\n\n/**\n * Null-object runner used when no concrete runner has been registered (e.g. in\n * tests, or before bootstrap). External hooks are best-effort and must never\n * throw or block the UI, so `run` resolves to a no-op.\n */\nconst noopExternalHooks: ExternalHooks = {\n\tasync run() {},\n};\n\nlet registeredExternalHooks: ExternalHooks | undefined;\n\n/**\n * Register the application's external-hooks runner. Called once at bootstrap by\n * `editor-ui` so package-side `useExternalHooks` can resolve it from any\n * context, including outside of component setup (routers, stores, plain\n * modules).\n */\nexport function setExternalHooks(instance: ExternalHooks | undefined): void {\n\tregisteredExternalHooks = instance;\n}\n\n/**\n * Returns the active external-hooks runner. Resolution order: a\n * component-provided runner (via {@link ExternalHooksKey}), then the\n * app-registered singleton (via {@link setExternalHooks}), then a no-op fallback.\n */\nexport function useExternalHooks(): ExternalHooks {\n\tconst injected = hasInjectionContext() ? inject(ExternalHooksKey, null) : null;\n\treturn injected ?? registeredExternalHooks ?? noopExternalHooks;\n}\n"],"mappings":";;;;;;;;;AA4BA,MAAaA,mBAAgD,OAAO,gBAAgB;;;;;;AAOpF,MAAMC,oBAAmC,EACxC,MAAM,MAAM,IACZ;AAED,IAAIC;;;;;;;AAQJ,SAAgB,iBAAiB,UAA2C;AAC3E,2BAA0B;;;;;;;AAQ3B,SAAgB,mBAAkC;AAEjD,SADiB,qBAAqB,GAAG,OAAO,kBAAkB,KAAK,GAAG,SACvD,2BAA2B"}
@@ -0,0 +1,19 @@
1
+ const require_useDebounce = require('./useDebounce.cjs');
2
+ let __n8n_frontend_constants_z_indexes = require("@n8n/frontend-constants/z-indexes");
3
+
4
+ //#region src/useStyles.ts
5
+ const setAppZIndexes = () => {
6
+ Object.keys(__n8n_frontend_constants_z_indexes.APP_Z_INDEXES).forEach((key) => {
7
+ const variableName = `--${key.toLowerCase().replaceAll("_", "-")}--z`;
8
+ const value = __n8n_frontend_constants_z_indexes.APP_Z_INDEXES[key];
9
+ document.documentElement.style.setProperty(variableName, `${value}`);
10
+ });
11
+ };
12
+ const useStyles = () => ({
13
+ APP_Z_INDEXES: __n8n_frontend_constants_z_indexes.APP_Z_INDEXES,
14
+ setAppZIndexes
15
+ });
16
+
17
+ //#endregion
18
+ exports.useStyles = useStyles;
19
+ //# sourceMappingURL=useStyles.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStyles.cjs","names":["APP_Z_INDEXES"],"sources":["../src/useStyles.ts"],"sourcesContent":["import { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\n\nconst setAppZIndexes = () => {\n\tObject.keys(APP_Z_INDEXES).forEach((key) => {\n\t\tconst variableName = `--${key.toLowerCase().replaceAll('_', '-')}--z`;\n\t\tconst value = APP_Z_INDEXES[key as keyof typeof APP_Z_INDEXES];\n\t\tdocument.documentElement.style.setProperty(variableName, `${value}`);\n\t});\n};\n\nexport const useStyles = () => ({\n\tAPP_Z_INDEXES,\n\tsetAppZIndexes,\n});\n"],"mappings":";;;;AAEA,MAAM,uBAAuB;AAC5B,QAAO,KAAKA,iDAAc,CAAC,SAAS,QAAQ;EAC3C,MAAM,eAAe,KAAK,IAAI,aAAa,CAAC,WAAW,KAAK,IAAI,CAAC;EACjE,MAAM,QAAQA,iDAAc;AAC5B,WAAS,gBAAgB,MAAM,YAAY,cAAc,GAAG,QAAQ;GACnE;;AAGH,MAAa,mBAAmB;CAC/B;CACA;CACA"}
@@ -0,0 +1,31 @@
1
+ //#region src/useStyles.d.ts
2
+ declare const useStyles: () => {
3
+ APP_Z_INDEXES: {
4
+ readonly CONTEXT_MENU: 10;
5
+ readonly APP_HEADER: 99;
6
+ readonly SELECT_BOX: 100;
7
+ readonly CANVAS_ADD_BUTTON: 101;
8
+ readonly APP_SIDEBAR: 999;
9
+ readonly CANVAS_SELECT_BOX: 100;
10
+ readonly TOP_BANNERS: 999;
11
+ readonly NODE_CREATOR: 1700;
12
+ readonly ASK_ASSISTANT_CHAT: 1750;
13
+ readonly NDV: 1800;
14
+ readonly COMMAND_BAR: 1900;
15
+ readonly DIALOGS: 1950;
16
+ readonly MODALS: 2000;
17
+ readonly TOASTS: 2100;
18
+ readonly ASK_ASSISTANT_FLOATING_BUTTON: 3000;
19
+ readonly ASK_ASSISTANT_FLOATING_BUTTON_TOOLTIP: 3000;
20
+ readonly CODEMIRROR_TOOLTIP: 3000;
21
+ readonly FLOATING_UI: 3000;
22
+ readonly DRAGGABLE: 9999999;
23
+ readonly ACTIVE_STICKY: 9999999;
24
+ readonly WORKFLOW_PREVIEW_NDV: 9999999;
25
+ readonly NPS_SURVEY_MODAL: 3001;
26
+ };
27
+ setAppZIndexes: () => void;
28
+ };
29
+ //#endregion
30
+ export { useStyles };
31
+ //# sourceMappingURL=useStyles.d.cts.map
@@ -0,0 +1,31 @@
1
+ //#region src/useStyles.d.ts
2
+ declare const useStyles: () => {
3
+ APP_Z_INDEXES: {
4
+ readonly CONTEXT_MENU: 10;
5
+ readonly APP_HEADER: 99;
6
+ readonly SELECT_BOX: 100;
7
+ readonly CANVAS_ADD_BUTTON: 101;
8
+ readonly APP_SIDEBAR: 999;
9
+ readonly CANVAS_SELECT_BOX: 100;
10
+ readonly TOP_BANNERS: 999;
11
+ readonly NODE_CREATOR: 1700;
12
+ readonly ASK_ASSISTANT_CHAT: 1750;
13
+ readonly NDV: 1800;
14
+ readonly COMMAND_BAR: 1900;
15
+ readonly DIALOGS: 1950;
16
+ readonly MODALS: 2000;
17
+ readonly TOASTS: 2100;
18
+ readonly ASK_ASSISTANT_FLOATING_BUTTON: 3000;
19
+ readonly ASK_ASSISTANT_FLOATING_BUTTON_TOOLTIP: 3000;
20
+ readonly CODEMIRROR_TOOLTIP: 3000;
21
+ readonly FLOATING_UI: 3000;
22
+ readonly DRAGGABLE: 9999999;
23
+ readonly ACTIVE_STICKY: 9999999;
24
+ readonly WORKFLOW_PREVIEW_NDV: 9999999;
25
+ readonly NPS_SURVEY_MODAL: 3001;
26
+ };
27
+ setAppZIndexes: () => void;
28
+ };
29
+ //#endregion
30
+ export { useStyles };
31
+ //# sourceMappingURL=useStyles.d.mts.map
@@ -0,0 +1,18 @@
1
+ import { APP_Z_INDEXES } from "@n8n/frontend-constants/z-indexes";
2
+
3
+ //#region src/useStyles.ts
4
+ const setAppZIndexes = () => {
5
+ Object.keys(APP_Z_INDEXES).forEach((key) => {
6
+ const variableName = `--${key.toLowerCase().replaceAll("_", "-")}--z`;
7
+ const value = APP_Z_INDEXES[key];
8
+ document.documentElement.style.setProperty(variableName, `${value}`);
9
+ });
10
+ };
11
+ const useStyles = () => ({
12
+ APP_Z_INDEXES,
13
+ setAppZIndexes
14
+ });
15
+
16
+ //#endregion
17
+ export { useStyles };
18
+ //# sourceMappingURL=useStyles.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStyles.mjs","names":[],"sources":["../src/useStyles.ts"],"sourcesContent":["import { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\n\nconst setAppZIndexes = () => {\n\tObject.keys(APP_Z_INDEXES).forEach((key) => {\n\t\tconst variableName = `--${key.toLowerCase().replaceAll('_', '-')}--z`;\n\t\tconst value = APP_Z_INDEXES[key as keyof typeof APP_Z_INDEXES];\n\t\tdocument.documentElement.style.setProperty(variableName, `${value}`);\n\t});\n};\n\nexport const useStyles = () => ({\n\tAPP_Z_INDEXES,\n\tsetAppZIndexes,\n});\n"],"mappings":";;;AAEA,MAAM,uBAAuB;AAC5B,QAAO,KAAK,cAAc,CAAC,SAAS,QAAQ;EAC3C,MAAM,eAAe,KAAK,IAAI,aAAa,CAAC,WAAW,KAAK,IAAI,CAAC;EACjE,MAAM,QAAQ,cAAc;AAC5B,WAAS,gBAAgB,MAAM,YAAY,cAAc,GAAG,QAAQ;GACnE;;AAGH,MAAa,mBAAmB;CAC/B;CACA;CACA"}
@@ -0,0 +1,5 @@
1
+ const require_useTelemetry = require('./useTelemetry2.cjs');
2
+
3
+ exports.TelemetryKey = require_useTelemetry.TelemetryKey;
4
+ exports.setTelemetry = require_useTelemetry.setTelemetry;
5
+ exports.useTelemetry = require_useTelemetry.useTelemetry;
@@ -0,0 +1,42 @@
1
+ import { InjectionKey } from "vue";
2
+ import { ITelemetrySettings } from "@n8n/api-types";
3
+ import { InferTelemetryProps, TelemetryEventDef } from "@n8n/telemetry";
4
+ import { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from "n8n-workflow";
5
+ import { RouteLocation } from "vue-router";
6
+
7
+ //#region src/useTelemetry.d.ts
8
+ type TelemetryIdentifyOptions = {
9
+ instanceId: string;
10
+ userId?: string;
11
+ projectId?: string;
12
+ versionCli?: string;
13
+ userRole?: string;
14
+ };
15
+ interface TelemetryNodeParameterChange {
16
+ name: string;
17
+ key?: string;
18
+ value: NodeParameterValueType;
19
+ node?: string;
20
+ oldValue?: string | number;
21
+ type?: 'optionsOrderChanged';
22
+ }
23
+ interface Telemetry {
24
+ init(telemetrySettings: ITelemetrySettings, options: TelemetryIdentifyOptions & {
25
+ versionCli: string;
26
+ }): void;
27
+ identify(options: TelemetryIdentifyOptions): void;
28
+ track<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;
29
+ track(event: string, properties?: ITelemetryTrackProperties): void;
30
+ page(route: RouteLocation): void;
31
+ reset(): void;
32
+ flushPageEvents(): void;
33
+ trackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;
34
+ trackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;
35
+ trackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;
36
+ }
37
+ declare const TelemetryKey: InjectionKey<Telemetry>;
38
+ declare function setTelemetry(instance: Telemetry | undefined): void;
39
+ declare function useTelemetry(): Telemetry;
40
+ //#endregion
41
+ export { Telemetry, TelemetryIdentifyOptions, TelemetryKey, TelemetryNodeParameterChange, setTelemetry, useTelemetry };
42
+ //# sourceMappingURL=useTelemetry.d.cts.map
@@ -0,0 +1,42 @@
1
+ import { InjectionKey } from "vue";
2
+ import { RouteLocation } from "vue-router";
3
+ import { ITelemetrySettings } from "@n8n/api-types";
4
+ import { InferTelemetryProps, TelemetryEventDef } from "@n8n/telemetry";
5
+ import { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from "n8n-workflow";
6
+
7
+ //#region src/useTelemetry.d.ts
8
+ type TelemetryIdentifyOptions = {
9
+ instanceId: string;
10
+ userId?: string;
11
+ projectId?: string;
12
+ versionCli?: string;
13
+ userRole?: string;
14
+ };
15
+ interface TelemetryNodeParameterChange {
16
+ name: string;
17
+ key?: string;
18
+ value: NodeParameterValueType;
19
+ node?: string;
20
+ oldValue?: string | number;
21
+ type?: 'optionsOrderChanged';
22
+ }
23
+ interface Telemetry {
24
+ init(telemetrySettings: ITelemetrySettings, options: TelemetryIdentifyOptions & {
25
+ versionCli: string;
26
+ }): void;
27
+ identify(options: TelemetryIdentifyOptions): void;
28
+ track<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;
29
+ track(event: string, properties?: ITelemetryTrackProperties): void;
30
+ page(route: RouteLocation): void;
31
+ reset(): void;
32
+ flushPageEvents(): void;
33
+ trackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;
34
+ trackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;
35
+ trackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;
36
+ }
37
+ declare const TelemetryKey: InjectionKey<Telemetry>;
38
+ declare function setTelemetry(instance: Telemetry | undefined): void;
39
+ declare function useTelemetry(): Telemetry;
40
+ //#endregion
41
+ export { Telemetry, TelemetryIdentifyOptions, TelemetryKey, TelemetryNodeParameterChange, setTelemetry, useTelemetry };
42
+ //# sourceMappingURL=useTelemetry.d.mts.map
@@ -0,0 +1,3 @@
1
+ import { n as setTelemetry, r as useTelemetry, t as TelemetryKey } from "./useTelemetry2.mjs";
2
+
3
+ export { TelemetryKey, setTelemetry, useTelemetry };
@@ -0,0 +1,76 @@
1
+ const require_useDebounce = require('./useDebounce.cjs');
2
+ let vue = require("vue");
3
+
4
+ //#region src/useTelemetry.ts
5
+ /**
6
+ * Injection key for the telemetry instance. The application provides it at
7
+ * bootstrap; components may override it (e.g. a pop-out window with its own
8
+ * instance). `useTelemetry` reads it when called inside an injection context.
9
+ */
10
+ const TelemetryKey = Symbol("Telemetry");
11
+ /**
12
+ * Null-object telemetry used when no instance has been registered (e.g. in
13
+ * tests that never install the plugin). Telemetry is best-effort and must never
14
+ * throw or break the UI, so every method is a no-op. Any registered instance
15
+ * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.
16
+ *
17
+ * A plain object literal (not a `Proxy`) so method identity is stable, spies
18
+ * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`
19
+ * that would make `await useTelemetry()` hang.
20
+ */
21
+ const noopTelemetry = {
22
+ init() {},
23
+ identify() {},
24
+ track() {},
25
+ page() {},
26
+ reset() {},
27
+ flushPageEvents() {},
28
+ trackAskAI() {},
29
+ trackAiTransform() {},
30
+ trackNodeParametersValuesChange() {}
31
+ };
32
+ let registeredTelemetry;
33
+ let warnedAboutMissingTelemetry = false;
34
+ /**
35
+ * Register the application's telemetry instance. Called once at bootstrap by
36
+ * the editor-ui telemetry plugin so package-side `useTelemetry` can return it
37
+ * from any context, including outside of component setup.
38
+ */
39
+ function setTelemetry(instance) {
40
+ registeredTelemetry = instance;
41
+ }
42
+ /**
43
+ * Returns the active telemetry instance. Resolution order: a component-provided
44
+ * instance (via {@link TelemetryKey}), then the app-registered singleton (via
45
+ * {@link setTelemetry}), then a no-op fallback.
46
+ */
47
+ function useTelemetry() {
48
+ const instance = ((0, vue.hasInjectionContext)() ? (0, vue.inject)(TelemetryKey, null) : null) ?? registeredTelemetry;
49
+ if (instance) return instance;
50
+ if ({}.env.DEV && !warnedAboutMissingTelemetry) {
51
+ warnedAboutMissingTelemetry = true;
52
+ console.warn("[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.");
53
+ }
54
+ return noopTelemetry;
55
+ }
56
+
57
+ //#endregion
58
+ Object.defineProperty(exports, 'TelemetryKey', {
59
+ enumerable: true,
60
+ get: function () {
61
+ return TelemetryKey;
62
+ }
63
+ });
64
+ Object.defineProperty(exports, 'setTelemetry', {
65
+ enumerable: true,
66
+ get: function () {
67
+ return setTelemetry;
68
+ }
69
+ });
70
+ Object.defineProperty(exports, 'useTelemetry', {
71
+ enumerable: true,
72
+ get: function () {
73
+ return useTelemetry;
74
+ }
75
+ });
76
+ //# sourceMappingURL=useTelemetry2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTelemetry2.cjs","names":["TelemetryKey: InjectionKey<Telemetry>","noopTelemetry: Telemetry","registeredTelemetry: Telemetry | undefined"],"sources":["../src/useTelemetry.ts"],"sourcesContent":["import type { ITelemetrySettings } from '@n8n/api-types';\nimport type { InferTelemetryProps, TelemetryEventDef } from '@n8n/telemetry';\nimport type { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from 'n8n-workflow';\nimport { hasInjectionContext, inject, type InjectionKey } from 'vue';\nimport type { RouteLocation } from 'vue-router';\n\nexport type TelemetryIdentifyOptions = {\n\tinstanceId: string;\n\tuserId?: string;\n\tprojectId?: string;\n\tversionCli?: string;\n\tuserRole?: string;\n};\n\n/**\n * Shape of a node-parameter change tracked by telemetry. Structurally mirrors\n * editor-ui's `IUpdateInformation`; declared here so the telemetry contract\n * carries no dependency back into the application package.\n */\nexport interface TelemetryNodeParameterChange {\n\tname: string;\n\tkey?: string;\n\tvalue: NodeParameterValueType;\n\tnode?: string;\n\toldValue?: string | number;\n\ttype?: 'optionsOrderChanged';\n}\n\n/**\n * The telemetry contract consumed across the frontend.\n *\n * This package owns the *type* only; the concrete implementation lives in the\n * application (`editor-ui`'s telemetry plugin) and is registered at bootstrap\n * via {@link setTelemetry} / provided through {@link TelemetryKey}. Keeping the\n * contract here lets `useTelemetry` return a fully-typed instance without the\n * package importing application code.\n */\nexport interface Telemetry {\n\tinit(\n\t\ttelemetrySettings: ITelemetrySettings,\n\t\toptions: TelemetryIdentifyOptions & { versionCli: string },\n\t): void;\n\tidentify(options: TelemetryIdentifyOptions): void;\n\ttrack<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;\n\ttrack(event: string, properties?: ITelemetryTrackProperties): void;\n\tpage(route: RouteLocation): void;\n\treset(): void;\n\tflushPageEvents(): void;\n\ttrackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;\n}\n\n/**\n * Injection key for the telemetry instance. The application provides it at\n * bootstrap; components may override it (e.g. a pop-out window with its own\n * instance). `useTelemetry` reads it when called inside an injection context.\n */\nexport const TelemetryKey: InjectionKey<Telemetry> = Symbol('Telemetry');\n\n/**\n * Null-object telemetry used when no instance has been registered (e.g. in\n * tests that never install the plugin). Telemetry is best-effort and must never\n * throw or break the UI, so every method is a no-op. Any registered instance\n * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.\n *\n * A plain object literal (not a `Proxy`) so method identity is stable, spies\n * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`\n * that would make `await useTelemetry()` hang.\n */\nconst noopTelemetry: Telemetry = {\n\tinit() {},\n\tidentify() {},\n\ttrack() {},\n\tpage() {},\n\treset() {},\n\tflushPageEvents() {},\n\ttrackAskAI() {},\n\ttrackAiTransform() {},\n\ttrackNodeParametersValuesChange() {},\n};\n\nlet registeredTelemetry: Telemetry | undefined;\nlet warnedAboutMissingTelemetry = false;\n\n/**\n * Register the application's telemetry instance. Called once at bootstrap by\n * the editor-ui telemetry plugin so package-side `useTelemetry` can return it\n * from any context, including outside of component setup.\n */\nexport function setTelemetry(instance: Telemetry | undefined): void {\n\tregisteredTelemetry = instance;\n}\n\n/**\n * Returns the active telemetry instance. Resolution order: a component-provided\n * instance (via {@link TelemetryKey}), then the app-registered singleton (via\n * {@link setTelemetry}), then a no-op fallback.\n */\nexport function useTelemetry(): Telemetry {\n\tconst injected = hasInjectionContext() ? inject(TelemetryKey, null) : null;\n\tconst instance = injected ?? registeredTelemetry;\n\tif (instance) return instance;\n\n\t// Falling back to the no-op means the plugin has not registered an instance\n\t// yet. That should never happen in the app (bootstrap registers before any\n\t// consumer runs); warn once in dev so an ordering regression stays visible.\n\tif (import.meta.env.DEV && !warnedAboutMissingTelemetry) {\n\t\twarnedAboutMissingTelemetry = true;\n\t\tconsole.warn(\n\t\t\t'[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.',\n\t\t);\n\t}\n\treturn noopTelemetry;\n}\n"],"mappings":";;;;;;;;;AA0DA,MAAaA,eAAwC,OAAO,YAAY;;;;;;;;;;;AAYxE,MAAMC,gBAA2B;CAChC,OAAO;CACP,WAAW;CACX,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,kBAAkB;CAClB,aAAa;CACb,mBAAmB;CACnB,kCAAkC;CAClC;AAED,IAAIC;AACJ,IAAI,8BAA8B;;;;;;AAOlC,SAAgB,aAAa,UAAuC;AACnE,uBAAsB;;;;;;;AAQvB,SAAgB,eAA0B;CAEzC,MAAM,0CADgC,mBAAU,cAAc,KAAK,GAAG,SACzC;AAC7B,KAAI,SAAU,QAAO;AAKrB,QAAgB,IAAI,OAAO,CAAC,6BAA6B;AACxD,gCAA8B;AAC9B,UAAQ,KACP,yHACA;;AAEF,QAAO"}
@@ -0,0 +1,58 @@
1
+ import { hasInjectionContext, inject } from "vue";
2
+
3
+ //#region src/useTelemetry.ts
4
+ /**
5
+ * Injection key for the telemetry instance. The application provides it at
6
+ * bootstrap; components may override it (e.g. a pop-out window with its own
7
+ * instance). `useTelemetry` reads it when called inside an injection context.
8
+ */
9
+ const TelemetryKey = Symbol("Telemetry");
10
+ /**
11
+ * Null-object telemetry used when no instance has been registered (e.g. in
12
+ * tests that never install the plugin). Telemetry is best-effort and must never
13
+ * throw or break the UI, so every method is a no-op. Any registered instance
14
+ * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.
15
+ *
16
+ * A plain object literal (not a `Proxy`) so method identity is stable, spies
17
+ * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`
18
+ * that would make `await useTelemetry()` hang.
19
+ */
20
+ const noopTelemetry = {
21
+ init() {},
22
+ identify() {},
23
+ track() {},
24
+ page() {},
25
+ reset() {},
26
+ flushPageEvents() {},
27
+ trackAskAI() {},
28
+ trackAiTransform() {},
29
+ trackNodeParametersValuesChange() {}
30
+ };
31
+ let registeredTelemetry;
32
+ let warnedAboutMissingTelemetry = false;
33
+ /**
34
+ * Register the application's telemetry instance. Called once at bootstrap by
35
+ * the editor-ui telemetry plugin so package-side `useTelemetry` can return it
36
+ * from any context, including outside of component setup.
37
+ */
38
+ function setTelemetry(instance) {
39
+ registeredTelemetry = instance;
40
+ }
41
+ /**
42
+ * Returns the active telemetry instance. Resolution order: a component-provided
43
+ * instance (via {@link TelemetryKey}), then the app-registered singleton (via
44
+ * {@link setTelemetry}), then a no-op fallback.
45
+ */
46
+ function useTelemetry() {
47
+ const instance = (hasInjectionContext() ? inject(TelemetryKey, null) : null) ?? registeredTelemetry;
48
+ if (instance) return instance;
49
+ if (import.meta.env.DEV && !warnedAboutMissingTelemetry) {
50
+ warnedAboutMissingTelemetry = true;
51
+ console.warn("[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.");
52
+ }
53
+ return noopTelemetry;
54
+ }
55
+
56
+ //#endregion
57
+ export { setTelemetry as n, useTelemetry as r, TelemetryKey as t };
58
+ //# sourceMappingURL=useTelemetry2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTelemetry2.mjs","names":["TelemetryKey: InjectionKey<Telemetry>","noopTelemetry: Telemetry","registeredTelemetry: Telemetry | undefined"],"sources":["../src/useTelemetry.ts"],"sourcesContent":["import type { ITelemetrySettings } from '@n8n/api-types';\nimport type { InferTelemetryProps, TelemetryEventDef } from '@n8n/telemetry';\nimport type { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from 'n8n-workflow';\nimport { hasInjectionContext, inject, type InjectionKey } from 'vue';\nimport type { RouteLocation } from 'vue-router';\n\nexport type TelemetryIdentifyOptions = {\n\tinstanceId: string;\n\tuserId?: string;\n\tprojectId?: string;\n\tversionCli?: string;\n\tuserRole?: string;\n};\n\n/**\n * Shape of a node-parameter change tracked by telemetry. Structurally mirrors\n * editor-ui's `IUpdateInformation`; declared here so the telemetry contract\n * carries no dependency back into the application package.\n */\nexport interface TelemetryNodeParameterChange {\n\tname: string;\n\tkey?: string;\n\tvalue: NodeParameterValueType;\n\tnode?: string;\n\toldValue?: string | number;\n\ttype?: 'optionsOrderChanged';\n}\n\n/**\n * The telemetry contract consumed across the frontend.\n *\n * This package owns the *type* only; the concrete implementation lives in the\n * application (`editor-ui`'s telemetry plugin) and is registered at bootstrap\n * via {@link setTelemetry} / provided through {@link TelemetryKey}. Keeping the\n * contract here lets `useTelemetry` return a fully-typed instance without the\n * package importing application code.\n */\nexport interface Telemetry {\n\tinit(\n\t\ttelemetrySettings: ITelemetrySettings,\n\t\toptions: TelemetryIdentifyOptions & { versionCli: string },\n\t): void;\n\tidentify(options: TelemetryIdentifyOptions): void;\n\ttrack<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;\n\ttrack(event: string, properties?: ITelemetryTrackProperties): void;\n\tpage(route: RouteLocation): void;\n\treset(): void;\n\tflushPageEvents(): void;\n\ttrackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;\n}\n\n/**\n * Injection key for the telemetry instance. The application provides it at\n * bootstrap; components may override it (e.g. a pop-out window with its own\n * instance). `useTelemetry` reads it when called inside an injection context.\n */\nexport const TelemetryKey: InjectionKey<Telemetry> = Symbol('Telemetry');\n\n/**\n * Null-object telemetry used when no instance has been registered (e.g. in\n * tests that never install the plugin). Telemetry is best-effort and must never\n * throw or break the UI, so every method is a no-op. Any registered instance\n * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.\n *\n * A plain object literal (not a `Proxy`) so method identity is stable, spies\n * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`\n * that would make `await useTelemetry()` hang.\n */\nconst noopTelemetry: Telemetry = {\n\tinit() {},\n\tidentify() {},\n\ttrack() {},\n\tpage() {},\n\treset() {},\n\tflushPageEvents() {},\n\ttrackAskAI() {},\n\ttrackAiTransform() {},\n\ttrackNodeParametersValuesChange() {},\n};\n\nlet registeredTelemetry: Telemetry | undefined;\nlet warnedAboutMissingTelemetry = false;\n\n/**\n * Register the application's telemetry instance. Called once at bootstrap by\n * the editor-ui telemetry plugin so package-side `useTelemetry` can return it\n * from any context, including outside of component setup.\n */\nexport function setTelemetry(instance: Telemetry | undefined): void {\n\tregisteredTelemetry = instance;\n}\n\n/**\n * Returns the active telemetry instance. Resolution order: a component-provided\n * instance (via {@link TelemetryKey}), then the app-registered singleton (via\n * {@link setTelemetry}), then a no-op fallback.\n */\nexport function useTelemetry(): Telemetry {\n\tconst injected = hasInjectionContext() ? inject(TelemetryKey, null) : null;\n\tconst instance = injected ?? registeredTelemetry;\n\tif (instance) return instance;\n\n\t// Falling back to the no-op means the plugin has not registered an instance\n\t// yet. That should never happen in the app (bootstrap registers before any\n\t// consumer runs); warn once in dev so an ordering regression stays visible.\n\tif (import.meta.env.DEV && !warnedAboutMissingTelemetry) {\n\t\twarnedAboutMissingTelemetry = true;\n\t\tconsole.warn(\n\t\t\t'[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.',\n\t\t);\n\t}\n\treturn noopTelemetry;\n}\n"],"mappings":";;;;;;;;AA0DA,MAAaA,eAAwC,OAAO,YAAY;;;;;;;;;;;AAYxE,MAAMC,gBAA2B;CAChC,OAAO;CACP,WAAW;CACX,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,kBAAkB;CAClB,aAAa;CACb,mBAAmB;CACnB,kCAAkC;CAClC;AAED,IAAIC;AACJ,IAAI,8BAA8B;;;;;;AAOlC,SAAgB,aAAa,UAAuC;AACnE,uBAAsB;;;;;;;AAQvB,SAAgB,eAA0B;CAEzC,MAAM,YADW,qBAAqB,GAAG,OAAO,cAAc,KAAK,GAAG,SACzC;AAC7B,KAAI,SAAU,QAAO;AAKrB,KAAI,OAAO,KAAK,IAAI,OAAO,CAAC,6BAA6B;AACxD,gCAA8B;AAC9B,UAAQ,KACP,yHACA;;AAEF,QAAO"}
@@ -0,0 +1,175 @@
1
+ const require_useDebounce = require('./useDebounce.cjs');
2
+ const require_useExternalHooks = require('./useExternalHooks2.cjs');
3
+ const require_useTelemetry = require('./useTelemetry2.cjs');
4
+ let vue = require("vue");
5
+ let __n8n_frontend_constants_z_indexes = require("@n8n/frontend-constants/z-indexes");
6
+ let __n8n_frontend_constants_views = require("@n8n/frontend-constants/views");
7
+ let __n8n_frontend_utils_htmlUtils = require("@n8n/frontend-utils/htmlUtils");
8
+ let __n8n_i18n = require("@n8n/i18n");
9
+ let __n8n_stores_notifications_store = require("@n8n/stores/notifications.store");
10
+ let vue_router = require("vue-router");
11
+
12
+ //#region src/useToast.ts
13
+ let registeredNotify;
14
+ /**
15
+ * Register the notification function. Called once at bootstrap by
16
+ * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`
17
+ * can issue notifications without importing element-plus directly — keeping
18
+ * the DTS build lightweight.
19
+ */
20
+ function setNotify(fn) {
21
+ registeredNotify = fn;
22
+ }
23
+ const noopHandle = { close() {} };
24
+ const noopNotify = () => noopHandle;
25
+ const stickyNotificationQueue = [];
26
+ function useToast() {
27
+ const notify = registeredNotify ?? noopNotify;
28
+ const telemetry = require_useTelemetry.useTelemetry();
29
+ const route = (0, vue_router.useRoute)();
30
+ const workflowId = (0, vue.computed)(() => {
31
+ if (route?.name === __n8n_frontend_constants_views.VIEWS.DEMO || route?.name === __n8n_frontend_constants_views.VIEWS.DEMO_DIFF) return "demo";
32
+ const id = route?.params?.workflowId;
33
+ return (Array.isArray(id) ? id[0] : id) ?? "";
34
+ });
35
+ const notificationsStore = (0, __n8n_stores_notifications_store.useNotificationsStore)();
36
+ const externalHooks = require_useExternalHooks.useExternalHooks();
37
+ const i18n = (0, __n8n_i18n.useI18n)();
38
+ function causedByCredential(message) {
39
+ if (!message || typeof message !== "string") return false;
40
+ return message.includes("Credentials for") && message.includes("are not set");
41
+ }
42
+ function showMessage(messageData, track = true) {
43
+ const suppressed = notificationsStore.areNotificationsSuppressed;
44
+ const allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;
45
+ if (suppressed && !(allowErrors && messageData.type === "error")) return { close: () => {} };
46
+ const messageDefaults = {
47
+ dangerouslyUseHTMLString: true,
48
+ position: "bottom-right",
49
+ zIndex: __n8n_frontend_constants_z_indexes.APP_Z_INDEXES.TOASTS,
50
+ appendTo: "#n8n-app",
51
+ customClass: "content-toast"
52
+ };
53
+ const { message, title } = messageData;
54
+ const params = {
55
+ ...messageDefaults,
56
+ ...messageData
57
+ };
58
+ if (typeof message === "string") params.message = (0, __n8n_frontend_utils_htmlUtils.sanitizeHtml)(message);
59
+ if (typeof title === "string") params.title = (0, __n8n_frontend_utils_htmlUtils.sanitizeHtml)(title);
60
+ const notification = notify(params);
61
+ if (params.duration === 0) stickyNotificationQueue.push(notification);
62
+ if (params.type === "error" && track) {
63
+ let messageForTelemetry;
64
+ if (typeof params.message === "string") messageForTelemetry = params.message;
65
+ else if (params.message && typeof params.message === "object" && "props" in params.message && params.message.props) {
66
+ const props = params.message.props;
67
+ const hasErrorMessage = typeof props === "object" && props !== null && "errorMessage" in props;
68
+ const hasMessage = typeof props === "object" && props !== null && "message" in props;
69
+ if (hasErrorMessage) messageForTelemetry = String(props.errorMessage);
70
+ else if (hasMessage) messageForTelemetry = String(props.message);
71
+ else messageForTelemetry = "Unknown error";
72
+ } else messageForTelemetry = "Unknown error";
73
+ telemetry.track("Instance FE emitted error", {
74
+ error_title: params.title,
75
+ error_message: messageForTelemetry,
76
+ caused_by_credential: causedByCredential(messageForTelemetry),
77
+ workflow_id: workflowId.value
78
+ });
79
+ }
80
+ return notification;
81
+ }
82
+ function showToast(config) {
83
+ let notification;
84
+ if (config.closeOnClick) {
85
+ const originalOnClick = config.onClick;
86
+ config.onClick = () => {
87
+ if (notification) notification.close();
88
+ if (originalOnClick) originalOnClick();
89
+ };
90
+ }
91
+ notification = showMessage({
92
+ title: config.title,
93
+ message: config.message,
94
+ onClick: config.onClick,
95
+ onClose: config.onClose,
96
+ duration: config.duration,
97
+ customClass: config.customClass,
98
+ type: config.type
99
+ });
100
+ return notification;
101
+ }
102
+ function collapsableDetails(description) {
103
+ const errorDescription = description.length > 500 ? `${description.slice(0, 500)}...` : description;
104
+ return `
105
+ <br>
106
+ <br>
107
+ <details>
108
+ <summary
109
+ style="color: #ff6d5a; font-weight: bold; cursor: pointer;"
110
+ >
111
+ ${i18n.baseText("showMessage.showDetails")}
112
+ </summary>
113
+ <p>${errorDescription}</p>
114
+ </details>
115
+ `;
116
+ }
117
+ function showError(e, title, options) {
118
+ const error = e;
119
+ const message = options?.message;
120
+ const description = options?.description ?? error.description;
121
+ showMessage({
122
+ title,
123
+ message: `
124
+ ${message ? `${message}<br/>` : ""}
125
+ <i>${error.message}</i>
126
+ ${description ? collapsableDetails(description) : ""}`,
127
+ type: "error",
128
+ duration: 0
129
+ }, false);
130
+ externalHooks.run("showMessage.showError", {
131
+ title,
132
+ message,
133
+ errorMessage: error.message
134
+ });
135
+ telemetry.track("Instance FE emitted error", {
136
+ error_title: title,
137
+ error_description: message,
138
+ error_message: error.message,
139
+ caused_by_credential: causedByCredential(error.message),
140
+ workflow_id: workflowId.value
141
+ });
142
+ }
143
+ function clearAllStickyNotifications() {
144
+ stickyNotificationQueue.forEach((notification) => {
145
+ if (notification) notification.close();
146
+ });
147
+ stickyNotificationQueue.length = 0;
148
+ }
149
+ function showNotificationForViews(views) {
150
+ const notifications = [];
151
+ views.forEach((view) => {
152
+ notifications.push(...notificationsStore.pendingNotificationsForViews[view] ?? []);
153
+ });
154
+ if (notifications.length) {
155
+ notifications.forEach((notification) => {
156
+ setTimeout(() => {
157
+ showMessage(notification);
158
+ }, 5);
159
+ });
160
+ notificationsStore.setNotificationsForView(__n8n_frontend_constants_views.VIEWS.WORKFLOW, []);
161
+ }
162
+ }
163
+ return {
164
+ showMessage,
165
+ showToast,
166
+ showError,
167
+ clearAllStickyNotifications,
168
+ showNotificationForViews
169
+ };
170
+ }
171
+
172
+ //#endregion
173
+ exports.setNotify = setNotify;
174
+ exports.useToast = useToast;
175
+ //# sourceMappingURL=useToast.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToast.cjs","names":["registeredNotify: NotifyFn | undefined","noopHandle: NotificationHandle","noopNotify: NotifyFn","stickyNotificationQueue: NotificationHandle[]","useTelemetry","VIEWS","useExternalHooks","messageDefaults: Partial<Omit<NotificationOptions, 'message'>>","APP_Z_INDEXES","messageForTelemetry: string","notification: NotificationHandle","notifications: NotificationOptions[]"],"sources":["../src/useToast.ts"],"sourcesContent":["import { VIEWS } from '@n8n/frontend-constants/views';\nimport { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\nimport { sanitizeHtml } from '@n8n/frontend-utils/htmlUtils';\nimport { useI18n } from '@n8n/i18n';\nimport type { NotificationOptions } from '@n8n/stores/notifications.store';\nimport { useNotificationsStore } from '@n8n/stores/notifications.store';\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { useExternalHooks } from './useExternalHooks';\nimport { useTelemetry } from './useTelemetry';\n\n/**\n * Handle returned by the notification function. Declared locally so the DTS\n * build stays free of the full element-plus type graph.\n */\nexport interface NotificationHandle {\n\tclose: () => void;\n}\n\n/** Notification severity — mirrors `MessageBoxState['type']` from element-plus. */\nexport type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';\n\n/**\n * Notification function contract — matches `ElNotification` from element-plus.\n * The application registers the concrete implementation at bootstrap via\n * {@link setNotify}; this package owns only the contract.\n */\ntype NotifyFn = (options: Record<string, unknown>) => NotificationHandle;\n\nlet registeredNotify: NotifyFn | undefined;\n\n/**\n * Register the notification function. Called once at bootstrap by\n * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`\n * can issue notifications without importing element-plus directly — keeping\n * the DTS build lightweight.\n */\nexport function setNotify(fn: NotifyFn): void {\n\tregisteredNotify = fn;\n}\n\nconst noopHandle: NotificationHandle = { close() {} };\nconst noopNotify: NotifyFn = () => noopHandle;\n\nconst stickyNotificationQueue: NotificationHandle[] = [];\n\nexport function useToast() {\n\tconst notify = registeredNotify ?? noopNotify;\n\tconst telemetry = useTelemetry();\n\tconst route = useRoute();\n\tconst workflowId = computed(() => {\n\t\tif (route?.name === VIEWS.DEMO || route?.name === VIEWS.DEMO_DIFF) return 'demo';\n\t\tconst id = route?.params?.workflowId;\n\t\treturn (Array.isArray(id) ? id[0] : id) ?? '';\n\t});\n\tconst notificationsStore = useNotificationsStore();\n\tconst externalHooks = useExternalHooks();\n\tconst i18n = useI18n();\n\n\tfunction causedByCredential(message: string | undefined) {\n\t\tif (!message || typeof message !== 'string') return false;\n\n\t\treturn message.includes('Credentials for') && message.includes('are not set');\n\t}\n\n\tfunction showMessage(messageData: Partial<NotificationOptions>, track = true) {\n\t\tconst suppressed = notificationsStore.areNotificationsSuppressed;\n\t\tconst allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;\n\t\tif (suppressed && !(allowErrors && messageData.type === 'error')) {\n\t\t\treturn { close: () => {} } as NotificationHandle;\n\t\t}\n\n\t\tconst messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = {\n\t\t\tdangerouslyUseHTMLString: true,\n\t\t\tposition: 'bottom-right',\n\t\t\t// Layer above NDV and modal overlays, sourced from the shared scale.\n\t\t\tzIndex: APP_Z_INDEXES.TOASTS,\n\t\t\tappendTo: '#n8n-app',\n\t\t\tcustomClass: 'content-toast',\n\t\t};\n\t\tconst { message, title } = messageData;\n\t\tconst params = { ...messageDefaults, ...messageData };\n\n\t\tif (typeof message === 'string') {\n\t\t\tparams.message = sanitizeHtml(message);\n\t\t}\n\n\t\tif (typeof title === 'string') {\n\t\t\tparams.title = sanitizeHtml(title);\n\t\t}\n\n\t\tconst notification = notify(params as unknown as Record<string, unknown>);\n\n\t\tif (params.duration === 0) {\n\t\t\tstickyNotificationQueue.push(notification);\n\t\t}\n\n\t\tif (params.type === 'error' && track) {\n\t\t\t// Extract string message for telemetry - don't send VNode objects as they have circular refs\n\t\t\tlet messageForTelemetry: string;\n\t\t\tif (typeof params.message === 'string') {\n\t\t\t\tmessageForTelemetry = params.message;\n\t\t\t} else if (\n\t\t\t\tparams.message &&\n\t\t\t\ttypeof params.message === 'object' &&\n\t\t\t\t'props' in params.message &&\n\t\t\t\tparams.message.props\n\t\t\t) {\n\t\t\t\t// Extract error message from VNode props (e.g., NodeExecutionErrorMessage component)\n\t\t\t\tconst props = params.message.props;\n\t\t\t\tconst hasErrorMessage =\n\t\t\t\t\ttypeof props === 'object' && props !== null && 'errorMessage' in props;\n\t\t\t\tconst hasMessage = typeof props === 'object' && props !== null && 'message' in props;\n\n\t\t\t\tif (hasErrorMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.errorMessage);\n\t\t\t\t} else if (hasMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.message);\n\t\t\t\t} else {\n\t\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t}\n\n\t\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\t\terror_title: params.title,\n\t\t\t\terror_message: messageForTelemetry,\n\t\t\t\tcaused_by_credential: causedByCredential(messageForTelemetry),\n\t\t\t\tworkflow_id: workflowId.value,\n\t\t\t});\n\t\t}\n\n\t\treturn notification;\n\t}\n\n\tfunction showToast(config: {\n\t\ttitle: string;\n\t\tmessage: NotificationOptions['message'];\n\t\tonClick?: (event?: MouseEvent) => void;\n\t\tonClose?: () => void;\n\t\tduration?: number;\n\t\tcustomClass?: string;\n\t\tcloseOnClick?: boolean;\n\t\ttype?: NotificationType;\n\t}) {\n\t\t// eslint-disable-next-line prefer-const\n\t\tlet notification: NotificationHandle;\n\t\tif (config.closeOnClick) {\n\t\t\tconst originalOnClick = config.onClick;\n\t\t\tconfig.onClick = () => {\n\t\t\t\tif (notification) {\n\t\t\t\t\tnotification.close();\n\t\t\t\t}\n\n\t\t\t\tif (originalOnClick) {\n\t\t\t\t\toriginalOnClick();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tnotification = showMessage({\n\t\t\ttitle: config.title,\n\t\t\tmessage: config.message,\n\t\t\tonClick: config.onClick,\n\t\t\tonClose: config.onClose,\n\t\t\tduration: config.duration,\n\t\t\tcustomClass: config.customClass,\n\t\t\ttype: config.type,\n\t\t});\n\n\t\treturn notification;\n\t}\n\n\tfunction collapsableDetails(description: string) {\n\t\tconst errorDescription =\n\t\t\tdescription.length > 500 ? `${description.slice(0, 500)}...` : description;\n\n\t\treturn `\n\t\t\t\t<br>\n\t\t\t\t<br>\n\t\t\t\t<details>\n\t\t\t\t\t<summary\n\t\t\t\t\t\tstyle=\"color: #ff6d5a; font-weight: bold; cursor: pointer;\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${i18n.baseText('showMessage.showDetails')}\n\t\t\t\t\t</summary>\n\t\t\t\t\t<p>${errorDescription}</p>\n\t\t\t\t</details>\n\t\t\t`;\n\t}\n\n\tfunction showError(\n\t\te: unknown,\n\t\ttitle: string,\n\t\toptions?: { message?: string; description?: string },\n\t) {\n\t\tconst error = e as Error & { description?: string };\n\t\tconst message = options?.message;\n\t\tconst description = options?.description ?? error.description;\n\t\tconst messageLine = message ? `${message}<br/>` : '';\n\t\tshowMessage(\n\t\t\t{\n\t\t\t\ttitle,\n\t\t\t\tmessage: `\n\t\t\t\t\t${messageLine}\n\t\t\t\t\t<i>${error.message}</i>\n\t\t\t\t\t${description ? collapsableDetails(description) : ''}`,\n\t\t\t\ttype: 'error',\n\t\t\t\tduration: 0,\n\t\t\t},\n\t\t\tfalse,\n\t\t);\n\n\t\tvoid externalHooks.run('showMessage.showError', {\n\t\t\ttitle,\n\t\t\tmessage,\n\t\t\terrorMessage: error.message,\n\t\t});\n\n\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\terror_title: title,\n\t\t\terror_description: message,\n\t\t\terror_message: error.message,\n\t\t\tcaused_by_credential: causedByCredential(error.message),\n\t\t\tworkflow_id: workflowId.value,\n\t\t});\n\t}\n\n\tfunction clearAllStickyNotifications() {\n\t\tstickyNotificationQueue.forEach((notification) => {\n\t\t\tif (notification) {\n\t\t\t\tnotification.close();\n\t\t\t}\n\t\t});\n\n\t\tstickyNotificationQueue.length = 0;\n\t}\n\n\t// Pick up and display notifications for the given list of views\n\tfunction showNotificationForViews(views: VIEWS[]) {\n\t\tconst notifications: NotificationOptions[] = [];\n\t\tviews.forEach((view) => {\n\t\t\tnotifications.push(...(notificationsStore.pendingNotificationsForViews[view] ?? []));\n\t\t});\n\t\tif (notifications.length) {\n\t\t\tnotifications.forEach((notification) => {\n\t\t\t\t// Notifications show on top of each other without this timeout\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tshowMessage(notification);\n\t\t\t\t}, 5);\n\t\t\t});\n\t\t\t// Clear the queue once all notifications are shown\n\t\t\tnotificationsStore.setNotificationsForView(VIEWS.WORKFLOW, []);\n\t\t}\n\t}\n\n\treturn {\n\t\tshowMessage,\n\t\tshowToast,\n\t\tshowError,\n\t\tclearAllStickyNotifications,\n\t\tshowNotificationForViews,\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { VIEWS } from "@n8n/frontend-constants/views";
2
+ import { NotificationOptions } from "@n8n/stores/notifications.store";
3
+
4
+ //#region src/useToast.d.ts
5
+ interface NotificationHandle {
6
+ close: () => void;
7
+ }
8
+ type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';
9
+ type NotifyFn = (options: Record<string, unknown>) => NotificationHandle;
10
+ declare function setNotify(fn: NotifyFn): void;
11
+ declare function useToast(): {
12
+ showMessage: (messageData: Partial<NotificationOptions>, track?: boolean) => NotificationHandle;
13
+ showToast: (config: {
14
+ title: string;
15
+ message: NotificationOptions["message"];
16
+ onClick?: (event?: MouseEvent) => void;
17
+ onClose?: () => void;
18
+ duration?: number;
19
+ customClass?: string;
20
+ closeOnClick?: boolean;
21
+ type?: NotificationType;
22
+ }) => NotificationHandle;
23
+ showError: (e: unknown, title: string, options?: {
24
+ message?: string;
25
+ description?: string;
26
+ }) => void;
27
+ clearAllStickyNotifications: () => void;
28
+ showNotificationForViews: (views: VIEWS[]) => void;
29
+ };
30
+ //#endregion
31
+ export { NotificationHandle, NotificationType, setNotify, useToast };
32
+ //# sourceMappingURL=useToast.d.cts.map
@@ -0,0 +1,32 @@
1
+ import { VIEWS } from "@n8n/frontend-constants/views";
2
+ import { NotificationOptions } from "@n8n/stores/notifications.store";
3
+
4
+ //#region src/useToast.d.ts
5
+ interface NotificationHandle {
6
+ close: () => void;
7
+ }
8
+ type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';
9
+ type NotifyFn = (options: Record<string, unknown>) => NotificationHandle;
10
+ declare function setNotify(fn: NotifyFn): void;
11
+ declare function useToast(): {
12
+ showMessage: (messageData: Partial<NotificationOptions>, track?: boolean) => NotificationHandle;
13
+ showToast: (config: {
14
+ title: string;
15
+ message: NotificationOptions["message"];
16
+ onClick?: (event?: MouseEvent) => void;
17
+ onClose?: () => void;
18
+ duration?: number;
19
+ customClass?: string;
20
+ closeOnClick?: boolean;
21
+ type?: NotificationType;
22
+ }) => NotificationHandle;
23
+ showError: (e: unknown, title: string, options?: {
24
+ message?: string;
25
+ description?: string;
26
+ }) => void;
27
+ clearAllStickyNotifications: () => void;
28
+ showNotificationForViews: (views: VIEWS[]) => void;
29
+ };
30
+ //#endregion
31
+ export { NotificationHandle, NotificationType, setNotify, useToast };
32
+ //# sourceMappingURL=useToast.d.mts.map
@@ -0,0 +1,173 @@
1
+ import { r as useExternalHooks } from "./useExternalHooks2.mjs";
2
+ import { r as useTelemetry } from "./useTelemetry2.mjs";
3
+ import { computed } from "vue";
4
+ import { APP_Z_INDEXES } from "@n8n/frontend-constants/z-indexes";
5
+ import { VIEWS } from "@n8n/frontend-constants/views";
6
+ import { sanitizeHtml } from "@n8n/frontend-utils/htmlUtils";
7
+ import { useI18n } from "@n8n/i18n";
8
+ import { useNotificationsStore } from "@n8n/stores/notifications.store";
9
+ import { useRoute } from "vue-router";
10
+
11
+ //#region src/useToast.ts
12
+ let registeredNotify;
13
+ /**
14
+ * Register the notification function. Called once at bootstrap by
15
+ * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`
16
+ * can issue notifications without importing element-plus directly — keeping
17
+ * the DTS build lightweight.
18
+ */
19
+ function setNotify(fn) {
20
+ registeredNotify = fn;
21
+ }
22
+ const noopHandle = { close() {} };
23
+ const noopNotify = () => noopHandle;
24
+ const stickyNotificationQueue = [];
25
+ function useToast() {
26
+ const notify = registeredNotify ?? noopNotify;
27
+ const telemetry = useTelemetry();
28
+ const route = useRoute();
29
+ const workflowId = computed(() => {
30
+ if (route?.name === VIEWS.DEMO || route?.name === VIEWS.DEMO_DIFF) return "demo";
31
+ const id = route?.params?.workflowId;
32
+ return (Array.isArray(id) ? id[0] : id) ?? "";
33
+ });
34
+ const notificationsStore = useNotificationsStore();
35
+ const externalHooks = useExternalHooks();
36
+ const i18n = useI18n();
37
+ function causedByCredential(message) {
38
+ if (!message || typeof message !== "string") return false;
39
+ return message.includes("Credentials for") && message.includes("are not set");
40
+ }
41
+ function showMessage(messageData, track = true) {
42
+ const suppressed = notificationsStore.areNotificationsSuppressed;
43
+ const allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;
44
+ if (suppressed && !(allowErrors && messageData.type === "error")) return { close: () => {} };
45
+ const messageDefaults = {
46
+ dangerouslyUseHTMLString: true,
47
+ position: "bottom-right",
48
+ zIndex: APP_Z_INDEXES.TOASTS,
49
+ appendTo: "#n8n-app",
50
+ customClass: "content-toast"
51
+ };
52
+ const { message, title } = messageData;
53
+ const params = {
54
+ ...messageDefaults,
55
+ ...messageData
56
+ };
57
+ if (typeof message === "string") params.message = sanitizeHtml(message);
58
+ if (typeof title === "string") params.title = sanitizeHtml(title);
59
+ const notification = notify(params);
60
+ if (params.duration === 0) stickyNotificationQueue.push(notification);
61
+ if (params.type === "error" && track) {
62
+ let messageForTelemetry;
63
+ if (typeof params.message === "string") messageForTelemetry = params.message;
64
+ else if (params.message && typeof params.message === "object" && "props" in params.message && params.message.props) {
65
+ const props = params.message.props;
66
+ const hasErrorMessage = typeof props === "object" && props !== null && "errorMessage" in props;
67
+ const hasMessage = typeof props === "object" && props !== null && "message" in props;
68
+ if (hasErrorMessage) messageForTelemetry = String(props.errorMessage);
69
+ else if (hasMessage) messageForTelemetry = String(props.message);
70
+ else messageForTelemetry = "Unknown error";
71
+ } else messageForTelemetry = "Unknown error";
72
+ telemetry.track("Instance FE emitted error", {
73
+ error_title: params.title,
74
+ error_message: messageForTelemetry,
75
+ caused_by_credential: causedByCredential(messageForTelemetry),
76
+ workflow_id: workflowId.value
77
+ });
78
+ }
79
+ return notification;
80
+ }
81
+ function showToast(config) {
82
+ let notification;
83
+ if (config.closeOnClick) {
84
+ const originalOnClick = config.onClick;
85
+ config.onClick = () => {
86
+ if (notification) notification.close();
87
+ if (originalOnClick) originalOnClick();
88
+ };
89
+ }
90
+ notification = showMessage({
91
+ title: config.title,
92
+ message: config.message,
93
+ onClick: config.onClick,
94
+ onClose: config.onClose,
95
+ duration: config.duration,
96
+ customClass: config.customClass,
97
+ type: config.type
98
+ });
99
+ return notification;
100
+ }
101
+ function collapsableDetails(description) {
102
+ const errorDescription = description.length > 500 ? `${description.slice(0, 500)}...` : description;
103
+ return `
104
+ <br>
105
+ <br>
106
+ <details>
107
+ <summary
108
+ style="color: #ff6d5a; font-weight: bold; cursor: pointer;"
109
+ >
110
+ ${i18n.baseText("showMessage.showDetails")}
111
+ </summary>
112
+ <p>${errorDescription}</p>
113
+ </details>
114
+ `;
115
+ }
116
+ function showError(e, title, options) {
117
+ const error = e;
118
+ const message = options?.message;
119
+ const description = options?.description ?? error.description;
120
+ showMessage({
121
+ title,
122
+ message: `
123
+ ${message ? `${message}<br/>` : ""}
124
+ <i>${error.message}</i>
125
+ ${description ? collapsableDetails(description) : ""}`,
126
+ type: "error",
127
+ duration: 0
128
+ }, false);
129
+ externalHooks.run("showMessage.showError", {
130
+ title,
131
+ message,
132
+ errorMessage: error.message
133
+ });
134
+ telemetry.track("Instance FE emitted error", {
135
+ error_title: title,
136
+ error_description: message,
137
+ error_message: error.message,
138
+ caused_by_credential: causedByCredential(error.message),
139
+ workflow_id: workflowId.value
140
+ });
141
+ }
142
+ function clearAllStickyNotifications() {
143
+ stickyNotificationQueue.forEach((notification) => {
144
+ if (notification) notification.close();
145
+ });
146
+ stickyNotificationQueue.length = 0;
147
+ }
148
+ function showNotificationForViews(views) {
149
+ const notifications = [];
150
+ views.forEach((view) => {
151
+ notifications.push(...notificationsStore.pendingNotificationsForViews[view] ?? []);
152
+ });
153
+ if (notifications.length) {
154
+ notifications.forEach((notification) => {
155
+ setTimeout(() => {
156
+ showMessage(notification);
157
+ }, 5);
158
+ });
159
+ notificationsStore.setNotificationsForView(VIEWS.WORKFLOW, []);
160
+ }
161
+ }
162
+ return {
163
+ showMessage,
164
+ showToast,
165
+ showError,
166
+ clearAllStickyNotifications,
167
+ showNotificationForViews
168
+ };
169
+ }
170
+
171
+ //#endregion
172
+ export { setNotify, useToast };
173
+ //# sourceMappingURL=useToast.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useToast.mjs","names":["registeredNotify: NotifyFn | undefined","noopHandle: NotificationHandle","noopNotify: NotifyFn","stickyNotificationQueue: NotificationHandle[]","messageDefaults: Partial<Omit<NotificationOptions, 'message'>>","messageForTelemetry: string","notification: NotificationHandle","notifications: NotificationOptions[]"],"sources":["../src/useToast.ts"],"sourcesContent":["import { VIEWS } from '@n8n/frontend-constants/views';\nimport { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\nimport { sanitizeHtml } from '@n8n/frontend-utils/htmlUtils';\nimport { useI18n } from '@n8n/i18n';\nimport type { NotificationOptions } from '@n8n/stores/notifications.store';\nimport { useNotificationsStore } from '@n8n/stores/notifications.store';\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { useExternalHooks } from './useExternalHooks';\nimport { useTelemetry } from './useTelemetry';\n\n/**\n * Handle returned by the notification function. Declared locally so the DTS\n * build stays free of the full element-plus type graph.\n */\nexport interface NotificationHandle {\n\tclose: () => void;\n}\n\n/** Notification severity — mirrors `MessageBoxState['type']` from element-plus. */\nexport type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';\n\n/**\n * Notification function contract — matches `ElNotification` from element-plus.\n * The application registers the concrete implementation at bootstrap via\n * {@link setNotify}; this package owns only the contract.\n */\ntype NotifyFn = (options: Record<string, unknown>) => NotificationHandle;\n\nlet registeredNotify: NotifyFn | undefined;\n\n/**\n * Register the notification function. Called once at bootstrap by\n * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`\n * can issue notifications without importing element-plus directly — keeping\n * the DTS build lightweight.\n */\nexport function setNotify(fn: NotifyFn): void {\n\tregisteredNotify = fn;\n}\n\nconst noopHandle: NotificationHandle = { close() {} };\nconst noopNotify: NotifyFn = () => noopHandle;\n\nconst stickyNotificationQueue: NotificationHandle[] = [];\n\nexport function useToast() {\n\tconst notify = registeredNotify ?? noopNotify;\n\tconst telemetry = useTelemetry();\n\tconst route = useRoute();\n\tconst workflowId = computed(() => {\n\t\tif (route?.name === VIEWS.DEMO || route?.name === VIEWS.DEMO_DIFF) return 'demo';\n\t\tconst id = route?.params?.workflowId;\n\t\treturn (Array.isArray(id) ? id[0] : id) ?? '';\n\t});\n\tconst notificationsStore = useNotificationsStore();\n\tconst externalHooks = useExternalHooks();\n\tconst i18n = useI18n();\n\n\tfunction causedByCredential(message: string | undefined) {\n\t\tif (!message || typeof message !== 'string') return false;\n\n\t\treturn message.includes('Credentials for') && message.includes('are not set');\n\t}\n\n\tfunction showMessage(messageData: Partial<NotificationOptions>, track = true) {\n\t\tconst suppressed = notificationsStore.areNotificationsSuppressed;\n\t\tconst allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;\n\t\tif (suppressed && !(allowErrors && messageData.type === 'error')) {\n\t\t\treturn { close: () => {} } as NotificationHandle;\n\t\t}\n\n\t\tconst messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = {\n\t\t\tdangerouslyUseHTMLString: true,\n\t\t\tposition: 'bottom-right',\n\t\t\t// Layer above NDV and modal overlays, sourced from the shared scale.\n\t\t\tzIndex: APP_Z_INDEXES.TOASTS,\n\t\t\tappendTo: '#n8n-app',\n\t\t\tcustomClass: 'content-toast',\n\t\t};\n\t\tconst { message, title } = messageData;\n\t\tconst params = { ...messageDefaults, ...messageData };\n\n\t\tif (typeof message === 'string') {\n\t\t\tparams.message = sanitizeHtml(message);\n\t\t}\n\n\t\tif (typeof title === 'string') {\n\t\t\tparams.title = sanitizeHtml(title);\n\t\t}\n\n\t\tconst notification = notify(params as unknown as Record<string, unknown>);\n\n\t\tif (params.duration === 0) {\n\t\t\tstickyNotificationQueue.push(notification);\n\t\t}\n\n\t\tif (params.type === 'error' && track) {\n\t\t\t// Extract string message for telemetry - don't send VNode objects as they have circular refs\n\t\t\tlet messageForTelemetry: string;\n\t\t\tif (typeof params.message === 'string') {\n\t\t\t\tmessageForTelemetry = params.message;\n\t\t\t} else if (\n\t\t\t\tparams.message &&\n\t\t\t\ttypeof params.message === 'object' &&\n\t\t\t\t'props' in params.message &&\n\t\t\t\tparams.message.props\n\t\t\t) {\n\t\t\t\t// Extract error message from VNode props (e.g., NodeExecutionErrorMessage component)\n\t\t\t\tconst props = params.message.props;\n\t\t\t\tconst hasErrorMessage =\n\t\t\t\t\ttypeof props === 'object' && props !== null && 'errorMessage' in props;\n\t\t\t\tconst hasMessage = typeof props === 'object' && props !== null && 'message' in props;\n\n\t\t\t\tif (hasErrorMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.errorMessage);\n\t\t\t\t} else if (hasMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.message);\n\t\t\t\t} else {\n\t\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t}\n\n\t\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\t\terror_title: params.title,\n\t\t\t\terror_message: messageForTelemetry,\n\t\t\t\tcaused_by_credential: causedByCredential(messageForTelemetry),\n\t\t\t\tworkflow_id: workflowId.value,\n\t\t\t});\n\t\t}\n\n\t\treturn notification;\n\t}\n\n\tfunction showToast(config: {\n\t\ttitle: string;\n\t\tmessage: NotificationOptions['message'];\n\t\tonClick?: (event?: MouseEvent) => void;\n\t\tonClose?: () => void;\n\t\tduration?: number;\n\t\tcustomClass?: string;\n\t\tcloseOnClick?: boolean;\n\t\ttype?: NotificationType;\n\t}) {\n\t\t// eslint-disable-next-line prefer-const\n\t\tlet notification: NotificationHandle;\n\t\tif (config.closeOnClick) {\n\t\t\tconst originalOnClick = config.onClick;\n\t\t\tconfig.onClick = () => {\n\t\t\t\tif (notification) {\n\t\t\t\t\tnotification.close();\n\t\t\t\t}\n\n\t\t\t\tif (originalOnClick) {\n\t\t\t\t\toriginalOnClick();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tnotification = showMessage({\n\t\t\ttitle: config.title,\n\t\t\tmessage: config.message,\n\t\t\tonClick: config.onClick,\n\t\t\tonClose: config.onClose,\n\t\t\tduration: config.duration,\n\t\t\tcustomClass: config.customClass,\n\t\t\ttype: config.type,\n\t\t});\n\n\t\treturn notification;\n\t}\n\n\tfunction collapsableDetails(description: string) {\n\t\tconst errorDescription =\n\t\t\tdescription.length > 500 ? `${description.slice(0, 500)}...` : description;\n\n\t\treturn `\n\t\t\t\t<br>\n\t\t\t\t<br>\n\t\t\t\t<details>\n\t\t\t\t\t<summary\n\t\t\t\t\t\tstyle=\"color: #ff6d5a; font-weight: bold; cursor: pointer;\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${i18n.baseText('showMessage.showDetails')}\n\t\t\t\t\t</summary>\n\t\t\t\t\t<p>${errorDescription}</p>\n\t\t\t\t</details>\n\t\t\t`;\n\t}\n\n\tfunction showError(\n\t\te: unknown,\n\t\ttitle: string,\n\t\toptions?: { message?: string; description?: string },\n\t) {\n\t\tconst error = e as Error & { description?: string };\n\t\tconst message = options?.message;\n\t\tconst description = options?.description ?? error.description;\n\t\tconst messageLine = message ? `${message}<br/>` : '';\n\t\tshowMessage(\n\t\t\t{\n\t\t\t\ttitle,\n\t\t\t\tmessage: `\n\t\t\t\t\t${messageLine}\n\t\t\t\t\t<i>${error.message}</i>\n\t\t\t\t\t${description ? collapsableDetails(description) : ''}`,\n\t\t\t\ttype: 'error',\n\t\t\t\tduration: 0,\n\t\t\t},\n\t\t\tfalse,\n\t\t);\n\n\t\tvoid externalHooks.run('showMessage.showError', {\n\t\t\ttitle,\n\t\t\tmessage,\n\t\t\terrorMessage: error.message,\n\t\t});\n\n\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\terror_title: title,\n\t\t\terror_description: message,\n\t\t\terror_message: error.message,\n\t\t\tcaused_by_credential: causedByCredential(error.message),\n\t\t\tworkflow_id: workflowId.value,\n\t\t});\n\t}\n\n\tfunction clearAllStickyNotifications() {\n\t\tstickyNotificationQueue.forEach((notification) => {\n\t\t\tif (notification) {\n\t\t\t\tnotification.close();\n\t\t\t}\n\t\t});\n\n\t\tstickyNotificationQueue.length = 0;\n\t}\n\n\t// Pick up and display notifications for the given list of views\n\tfunction showNotificationForViews(views: VIEWS[]) {\n\t\tconst notifications: NotificationOptions[] = [];\n\t\tviews.forEach((view) => {\n\t\t\tnotifications.push(...(notificationsStore.pendingNotificationsForViews[view] ?? []));\n\t\t});\n\t\tif (notifications.length) {\n\t\t\tnotifications.forEach((notification) => {\n\t\t\t\t// Notifications show on top of each other without this timeout\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tshowMessage(notification);\n\t\t\t\t}, 5);\n\t\t\t});\n\t\t\t// Clear the queue once all notifications are shown\n\t\t\tnotificationsStore.setNotificationsForView(VIEWS.WORKFLOW, []);\n\t\t}\n\t}\n\n\treturn {\n\t\tshowMessage,\n\t\tshowToast,\n\t\tshowError,\n\t\tclearAllStickyNotifications,\n\t\tshowNotificationForViews,\n\t};\n}\n"],"mappings":";;;;;;;;;;;AA8BA,IAAIA;;;;;;;AAQJ,SAAgB,UAAU,IAAoB;AAC7C,oBAAmB;;AAGpB,MAAMC,aAAiC,EAAE,QAAQ,IAAI;AACrD,MAAMC,mBAA6B;AAEnC,MAAMC,0BAAgD,EAAE;AAExD,SAAgB,WAAW;CAC1B,MAAM,SAAS,oBAAoB;CACnC,MAAM,YAAY,cAAc;CAChC,MAAM,QAAQ,UAAU;CACxB,MAAM,aAAa,eAAe;AACjC,MAAI,OAAO,SAAS,MAAM,QAAQ,OAAO,SAAS,MAAM,UAAW,QAAO;EAC1E,MAAM,KAAK,OAAO,QAAQ;AAC1B,UAAQ,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,OAAO;GAC1C;CACF,MAAM,qBAAqB,uBAAuB;CAClD,MAAM,gBAAgB,kBAAkB;CACxC,MAAM,OAAO,SAAS;CAEtB,SAAS,mBAAmB,SAA6B;AACxD,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AAEpD,SAAO,QAAQ,SAAS,kBAAkB,IAAI,QAAQ,SAAS,cAAc;;CAG9E,SAAS,YAAY,aAA2C,QAAQ,MAAM;EAC7E,MAAM,aAAa,mBAAmB;EACtC,MAAM,cAAc,mBAAmB;AACvC,MAAI,cAAc,EAAE,eAAe,YAAY,SAAS,SACvD,QAAO,EAAE,aAAa,IAAI;EAG3B,MAAMC,kBAAiE;GACtE,0BAA0B;GAC1B,UAAU;GAEV,QAAQ,cAAc;GACtB,UAAU;GACV,aAAa;GACb;EACD,MAAM,EAAE,SAAS,UAAU;EAC3B,MAAM,SAAS;GAAE,GAAG;GAAiB,GAAG;GAAa;AAErD,MAAI,OAAO,YAAY,SACtB,QAAO,UAAU,aAAa,QAAQ;AAGvC,MAAI,OAAO,UAAU,SACpB,QAAO,QAAQ,aAAa,MAAM;EAGnC,MAAM,eAAe,OAAO,OAA6C;AAEzE,MAAI,OAAO,aAAa,EACvB,yBAAwB,KAAK,aAAa;AAG3C,MAAI,OAAO,SAAS,WAAW,OAAO;GAErC,IAAIC;AACJ,OAAI,OAAO,OAAO,YAAY,SAC7B,uBAAsB,OAAO;YAE7B,OAAO,WACP,OAAO,OAAO,YAAY,YAC1B,WAAW,OAAO,WAClB,OAAO,QAAQ,OACd;IAED,MAAM,QAAQ,OAAO,QAAQ;IAC7B,MAAM,kBACL,OAAO,UAAU,YAAY,UAAU,QAAQ,kBAAkB;IAClE,MAAM,aAAa,OAAO,UAAU,YAAY,UAAU,QAAQ,aAAa;AAE/E,QAAI,gBACH,uBAAsB,OAAO,MAAM,aAAa;aACtC,WACV,uBAAsB,OAAO,MAAM,QAAQ;QAE3C,uBAAsB;SAGvB,uBAAsB;AAGvB,aAAU,MAAM,6BAA6B;IAC5C,aAAa,OAAO;IACpB,eAAe;IACf,sBAAsB,mBAAmB,oBAAoB;IAC7D,aAAa,WAAW;IACxB,CAAC;;AAGH,SAAO;;CAGR,SAAS,UAAU,QAShB;EAEF,IAAIC;AACJ,MAAI,OAAO,cAAc;GACxB,MAAM,kBAAkB,OAAO;AAC/B,UAAO,gBAAgB;AACtB,QAAI,aACH,cAAa,OAAO;AAGrB,QAAI,gBACH,kBAAiB;;;AAKpB,iBAAe,YAAY;GAC1B,OAAO,OAAO;GACd,SAAS,OAAO;GAChB,SAAS,OAAO;GAChB,SAAS,OAAO;GAChB,UAAU,OAAO;GACjB,aAAa,OAAO;GACpB,MAAM,OAAO;GACb,CAAC;AAEF,SAAO;;CAGR,SAAS,mBAAmB,aAAqB;EAChD,MAAM,mBACL,YAAY,SAAS,MAAM,GAAG,YAAY,MAAM,GAAG,IAAI,CAAC,OAAO;AAEhE,SAAO;;;;;;;QAOD,KAAK,SAAS,0BAA0B,CAAC;;UAEvC,iBAAiB;;;;CAK1B,SAAS,UACR,GACA,OACA,SACC;EACD,MAAM,QAAQ;EACd,MAAM,UAAU,SAAS;EACzB,MAAM,cAAc,SAAS,eAAe,MAAM;AAElD,cACC;GACC;GACA,SAAS;OAJS,UAAU,GAAG,QAAQ,SAAS,GAKjC;UACT,MAAM,QAAQ;OACjB,cAAc,mBAAmB,YAAY,GAAG;GACnD,MAAM;GACN,UAAU;GACV,EACD,MACA;AAED,EAAK,cAAc,IAAI,yBAAyB;GAC/C;GACA;GACA,cAAc,MAAM;GACpB,CAAC;AAEF,YAAU,MAAM,6BAA6B;GAC5C,aAAa;GACb,mBAAmB;GACnB,eAAe,MAAM;GACrB,sBAAsB,mBAAmB,MAAM,QAAQ;GACvD,aAAa,WAAW;GACxB,CAAC;;CAGH,SAAS,8BAA8B;AACtC,0BAAwB,SAAS,iBAAiB;AACjD,OAAI,aACH,cAAa,OAAO;IAEpB;AAEF,0BAAwB,SAAS;;CAIlC,SAAS,yBAAyB,OAAgB;EACjD,MAAMC,gBAAuC,EAAE;AAC/C,QAAM,SAAS,SAAS;AACvB,iBAAc,KAAK,GAAI,mBAAmB,6BAA6B,SAAS,EAAE,CAAE;IACnF;AACF,MAAI,cAAc,QAAQ;AACzB,iBAAc,SAAS,iBAAiB;AAEvC,qBAAiB;AAChB,iBAAY,aAAa;OACvB,EAAE;KACJ;AAEF,sBAAmB,wBAAwB,MAAM,UAAU,EAAE,CAAC;;;AAIhE,QAAO;EACN;EACA;EACA;EACA;EACA;EACA"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@n8n/composables",
3
3
  "type": "module",
4
- "version": "1.22.0",
4
+ "version": "1.23.1",
5
5
  "files": [
6
6
  "dist",
7
- "LICENSE_EE.md",
8
- "LICENSE.md"
7
+ "LICENSE.md",
8
+ "LICENSE_EE.md"
9
9
  ],
10
10
  "exports": {
11
11
  "./*": {
@@ -17,24 +17,35 @@
17
17
  "dependencies": {
18
18
  "@vueuse/core": "^14.3.0",
19
19
  "lodash": "4.18.1",
20
- "vue": "^3.5.13"
20
+ "vue": "^3.5.13",
21
+ "vue-router": "^4.5.0",
22
+ "@n8n/frontend-constants": "0.2.0",
23
+ "@n8n/frontend-utils": "0.2.0",
24
+ "@n8n/i18n": "2.33.1",
25
+ "@n8n/api-types": "1.33.1",
26
+ "@n8n/stores": "2.33.1",
27
+ "n8n-workflow": "2.33.1"
21
28
  },
22
29
  "devDependencies": {
30
+ "@pinia/testing": "^0.1.6",
31
+ "element-plus": "2.4.3",
23
32
  "@testing-library/vue": "^8.1.0",
24
33
  "@testing-library/jest-dom": "^6.6.3",
25
34
  "@testing-library/user-event": "^14.6.1",
26
35
  "@types/lodash": "4.17.17",
27
36
  "@vitejs/plugin-vue": "^5.2.4",
28
37
  "@vue/tsconfig": "^0.7.0",
38
+ "pinia": "^2.2.4",
29
39
  "tsdown": "^0.16.5",
30
40
  "typescript": "6.0.2",
31
41
  "vite": "^8.0.2",
32
42
  "vitest": "^4.1.9",
33
43
  "vue-tsc": "^2.2.8",
34
- "@n8n/playwright-janitor": "0.1.0",
35
44
  "@n8n/eslint-config": "0.0.1",
45
+ "@n8n/playwright-janitor": "0.1.0",
36
46
  "@n8n/typescript-config": "1.9.0",
37
- "@n8n/vitest-config": "1.19.0"
47
+ "@n8n/vitest-config": "1.19.0",
48
+ "@n8n/telemetry": "1.1.1"
38
49
  },
39
50
  "license": "SEE LICENSE IN LICENSE.md",
40
51
  "homepage": "https://n8n.io",