diff --git a/flowfile_frontend/src/renderer/app/features/designer/editor/pythonEditor.vue b/flowfile_frontend/src/renderer/app/features/designer/editor/pythonEditor.vue index 4a42c9e67..f2a77cde2 100644 --- a/flowfile_frontend/src/renderer/app/features/designer/editor/pythonEditor.vue +++ b/flowfile_frontend/src/renderer/app/features/designer/editor/pythonEditor.vue @@ -20,13 +20,13 @@ + + diff --git a/flowfile_frontend/src/renderer/app/pages/nodeDesigner/ProcessCodeEditor.vue b/flowfile_frontend/src/renderer/app/pages/nodeDesigner/ProcessCodeEditor.vue index 726d6b36c..ab9dac9ad 100644 --- a/flowfile_frontend/src/renderer/app/pages/nodeDesigner/ProcessCodeEditor.vue +++ b/flowfile_frontend/src/renderer/app/pages/nodeDesigner/ProcessCodeEditor.vue @@ -1,6 +1,12 @@ - Process Method + + Process Method + + + Help + + Write your data transformation logic. Access settings via self.settings_schema.section_name.component_name.value @@ -17,12 +23,16 @@ @update:model-value="emit('update:modelValue', $event)" /> + + diff --git a/flowfile_frontend/src/renderer/app/pages/nodeDesigner/composables/usePolarsAutocompletion.ts b/flowfile_frontend/src/renderer/app/pages/nodeDesigner/composables/usePolarsAutocompletion.ts index 2baedb61b..03565e0d6 100644 --- a/flowfile_frontend/src/renderer/app/pages/nodeDesigner/composables/usePolarsAutocompletion.ts +++ b/flowfile_frontend/src/renderer/app/pages/nodeDesigner/composables/usePolarsAutocompletion.ts @@ -2,11 +2,11 @@ * Composable for Polars autocompletion in CodeMirror */ import { EditorView, keymap } from '@codemirror/view'; -import { EditorState, Extension } from '@codemirror/state'; +import { EditorState, Extension, Prec } from '@codemirror/state'; import { python } from '@codemirror/lang-python'; import { oneDark } from '@codemirror/theme-one-dark'; -import { autocompletion, CompletionContext, CompletionResult, acceptCompletion } from '@codemirror/autocomplete'; -import { indentMore } from '@codemirror/commands'; +import { autocompletion, completionKeymap, CompletionContext, CompletionResult, acceptCompletion } from '@codemirror/autocomplete'; +import { indentMore, indentLess } from '@codemirror/commands'; import type { DesignerSection } from '../types'; import { toSnakeCase } from './useCodeGeneration'; @@ -141,12 +141,61 @@ const polarsCompletions = [ { label: '.over', type: 'method', info: 'Window function over groups', apply: '.over("")' }, ]; +// SecretStr methods for autocompletion +const secretStrMethods = [ + { + label: 'get_secret_value', + type: 'method', + info: 'Get the decrypted secret value as a string', + apply: 'get_secret_value()', + detail: 'SecretStr', + }, +]; + export function usePolarsAutocompletion(getSections: () => DesignerSection[]) { + // Helper to find SecretStr typed variables in the code + function findSecretStrVariables(doc: string): string[] { + const variables: string[] = []; + // Match patterns like: var_name: SecretStr = ... or var_name: SecretStr=... + const typeAnnotationPattern = /(\w+)\s*:\s*SecretStr\s*=/g; + let match; + while ((match = typeAnnotationPattern.exec(doc)) !== null) { + variables.push(match[1]); + } + return variables; + } + // Dynamic autocompletion based on schema function schemaCompletions(context: CompletionContext): CompletionResult | null { const beforeCursor = context.state.doc.sliceString(0, context.pos); + const fullDoc = context.state.doc.toString(); const sections = getSections(); + // Check for SecretStr variable method completion (e.g., my_secret.) + const secretStrVars = findSecretStrVariables(fullDoc); + for (const varName of secretStrVars) { + const varMethodMatch = beforeCursor.match(new RegExp(`\\b${varName}\\.(\\w*)$`)); + if (varMethodMatch) { + const typed = varMethodMatch[1]; + return { + from: context.pos - typed.length, + options: secretStrMethods, + validFor: /^\w*$/, + }; + } + } + + // Check for SecretStr method completion (after .secret_value.) + const secretStrMethodMatch = beforeCursor.match(/\.secret_value\.(\w*)$/); + if (secretStrMethodMatch) { + const typed = secretStrMethodMatch[1]; + return { + from: context.pos - typed.length, + options: secretStrMethods, + validFor: /^\w*$/, + }; + } + // Check for ".value" or ".secret_value" completion after a component field for (const section of sections) { const sectionName = section.name || toSnakeCase(section.title || 'section'); @@ -263,7 +312,7 @@ export function usePolarsAutocompletion(getSections: () => DesignerSection[]) { }; } - // Tab keymap for accepting completions + // Tab keymap for accepting completions and indentation const tabKeymap = keymap.of([ { key: 'Tab', @@ -274,19 +323,26 @@ export function usePolarsAutocompletion(getSections: () => DesignerSection[]) { return indentMore(view); }, }, + { + key: 'Shift-Tab', + run: (view: EditorView): boolean => { + return indentLess(view); + }, + }, ]); // CodeMirror extensions for editing + // Note: Prec.highest ensures completion keybindings take priority over other keymaps const extensions: Extension[] = [ python(), oneDark, EditorState.tabSize.of(4), autocompletion({ override: [schemaCompletions], - defaultKeymap: false, + defaultKeymap: true, // Enable default keymap for arrow navigation closeOnBlur: false, }), - tabKeymap, + Prec.highest(tabKeymap), // Tab keymap with highest precedence ]; // Read-only CodeMirror extensions for code preview diff --git a/flowfile_frontend/src/renderer/styles/main.css b/flowfile_frontend/src/renderer/styles/main.css index 450228960..51131df75 100644 --- a/flowfile_frontend/src/renderer/styles/main.css +++ b/flowfile_frontend/src/renderer/styles/main.css @@ -506,9 +506,12 @@ button { background-color: var(--color-background-hover) !important; } -.cm-editor .cm-selectionBackground, +.cm-editor .cm-selectionBackground { + background-color: rgba(8, 145, 178, 0.15) !important; +} + .cm-editor.cm-focused .cm-selectionBackground { - background-color: var(--color-background-selected) !important; + background-color: rgba(8, 145, 178, 0.25) !important; } /* Placeholder styling */
Write your data transformation logic. Access settings via self.settings_schema.section_name.component_name.value @@ -17,12 +23,16 @@ @update:model-value="emit('update:modelValue', $event)" />
self.settings_schema.section_name.component_name.value