feat: External Secrets storage for credentials (#6477)
Github issue / Community forum post (link here to close automatically): --------- Co-authored-by: Romain Minaud <romain.minaud@gmail.com> Co-authored-by: Valya Bullions <valya@n8n.io> Co-authored-by: Csaba Tuncsik <csaba@n8n.io> Co-authored-by: Giulio Andreini <g.andreini@gmail.com> Co-authored-by: Omar Ajoue <krynble@gmail.com>
This commit is contained in:
@@ -172,6 +172,7 @@ export const completerExtension = defineComponent({
|
||||
|
||||
if (value === '$execution') return this.executionCompletions(context, variable);
|
||||
if (value === '$vars') return this.variablesCompletions(context, variable);
|
||||
|
||||
if (value === '$workflow') return this.workflowCompletions(context, variable);
|
||||
if (value === '$prevNode') return this.prevNodeCompletions(context, variable);
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import Vue from 'vue';
|
||||
import { addVarType } from '../utils';
|
||||
import type { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
||||
import type { CodeNodeEditorMixin } from '../types';
|
||||
import { useExternalSecretsStore } from '@/stores';
|
||||
|
||||
const escape = (str: string) => str.replace('$', '\\$');
|
||||
|
||||
export const secretsCompletions = (Vue as CodeNodeEditorMixin).extend({
|
||||
methods: {
|
||||
/**
|
||||
* Complete `$secrets.` to `$secrets.providerName` and `$secrets.providerName.secretName`.
|
||||
*/
|
||||
secretsCompletions(context: CompletionContext, matcher = '$secrets'): CompletionResult | null {
|
||||
const pattern = new RegExp(`${escape(matcher)}\..*`);
|
||||
const preCursor = context.matchBefore(pattern);
|
||||
|
||||
if (!preCursor || (preCursor.from === preCursor.to && !context.explicit)) return null;
|
||||
|
||||
const provider = preCursor.text.split('.')[1];
|
||||
const externalSecretsStore = useExternalSecretsStore();
|
||||
let options: Completion[];
|
||||
|
||||
const optionsForObject = (leftSide: string, object: object): Completion[] => {
|
||||
return Object.entries(object).flatMap(([key, value]) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
return optionsForObject(`${leftSide}.${key}`, value);
|
||||
}
|
||||
return {
|
||||
label: `${leftSide}.${key}`,
|
||||
info: '*******',
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
if (provider) {
|
||||
options = optionsForObject(
|
||||
`${matcher}.${provider}`,
|
||||
externalSecretsStore.secretsAsObject[provider],
|
||||
);
|
||||
} else {
|
||||
options = Object.keys(externalSecretsStore.secretsAsObject).map((provider) => ({
|
||||
label: `${matcher}.${provider}`,
|
||||
info: JSON.stringify(externalSecretsStore.secretsAsObject[provider]),
|
||||
}));
|
||||
}
|
||||
|
||||
return {
|
||||
from: preCursor.from,
|
||||
options: options.map(addVarType),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -8,7 +8,7 @@ const escape = (str: string) => str.replace('$', '\\$');
|
||||
export const variablesCompletions = defineComponent({
|
||||
methods: {
|
||||
/**
|
||||
* Complete `$workflow.` to `.id .name .active`.
|
||||
* Complete `$vars.` to `$vars.VAR_NAME`.
|
||||
*/
|
||||
variablesCompletions(context: CompletionContext, matcher = '$vars'): CompletionResult | null {
|
||||
const pattern = new RegExp(`${escape(matcher)}\..*`);
|
||||
|
||||
Reference in New Issue
Block a user