All files / src/flow/actions set_run_result.ts

81.44% Statements 79/97
54.54% Branches 6/11
80% Functions 4/5
81.44% Lines 79/97

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 9898x 1x 1x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 4x 4x 4x 4x 4x 1x 1x 4x 4x 98x 98x 98x 98x 98x 98x 98x                               98x 98x 98x 98x 5x       98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 98x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 98x 98x 98x 98x 97x 98x 98x 98x 98x 98x 98x 98x 98x 98x  
import { html } from 'lit-html';
import { ActionConfig, ACTION_GROUPS, FormData, FlowTypes } from '../types';
import { Node, SetRunResult } from '../../store/flow-definition';
import { getStore } from '../../store/Store';
import { renderClamped, renderHighlightedText } from '../utils';
 
export const set_run_result: ActionConfig = {
  name: 'Save Flow Result',
  group: ACTION_GROUPS.save,
  flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
  render: (_node: Node, action: SetRunResult) => {
    return renderClamped(
      html`Set <strong>${action.name}</strong> to
        ${renderHighlightedText(action.value, true)}`,
      `Set ${action.name} to ${action.value}`
    );
  },
  form: {
    name: {
      type: 'select',
      label: 'Result Name',
      helpText: 'Select an existing result name or type a new one',
      required: true,
      placeholder: 'Select or enter result name...',
      createArbitraryOption: (input, options) => {
        const exists = options.some(
          (option: any) =>
            option.value.toLowerCase() === input.toLowerCase() ||
            option.name.toLowerCase() === input.toLowerCase()
        );
        return !exists && input.trim().length > 0
          ? { value: input, name: input }
          : null;
      },
      searchable: true,
      clearable: false,
      getDynamicOptions: () => {
        const store = getStore();
        return store
          ? store
              .getState()
              .getFlowResults()
              .map((r) => ({ value: r.name, name: r.name }))
          : [];
      }
    },
    value: {
      type: 'textarea',
      label: 'Value',
      helpText: 'The value to save for this result (can use expressions)',
      required: false,
      evaluated: true,
      placeholder: 'Enter value...'
    },
    category: {
      type: 'text',
      label: 'Category',
      helpText: 'Optional category for this result',
      required: false,
      maxLength: 36,
      placeholder: 'Enter category...'
    }
  },
  layout: ['name', 'value', 'category'],
  toFormData: (action: SetRunResult) => {
    return {
      uuid: action.uuid,
      name: action.name ? [{ name: action.name, value: action.name }] : null,
      value: action.value || '',
      category: action.category || ''
    };
  },
  fromFormData: (formData: FormData): SetRunResult => {
    // Ensure name is a simple string, handling both direct values and select option objects
    let name = formData.name || '';
    if (Array.isArray(name) && name.length > 0) {
      // If it's an array (from multi-select), take the first item
      name = name[0];
    }
    if (typeof name === 'object' && name.value) {
      // If it's an option object, extract the value
      name = name.value;
    }
    if (typeof name === 'object' && name.name) {
      // If it's an option object with name property, extract it
      name = name.name;
    }
 
    return {
      uuid: formData.uuid,
      type: 'set_run_result',
      name: String(name), // Ensure it's always a string
      value: formData.value || '',
      category: formData.category || ''
    };
  }
};