All files / src/flow/actions set_run_result.ts

82.82% Statements 82/99
54.54% Branches 6/11
80% Functions 4/5
82.82% Lines 82/99

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 98 99 100132x 1x 1x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 4x 4x 4x 4x 4x 1x 1x 4x 4x 4x 132x 132x 132x 132x 132x 132x 132x                               132x 132x 132x 132x 7x     7x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 132x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 132x 132x 132x 132x 131x 132x 132x 132x 132x 132x 132x 132x 132x 132x  
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,
      maxLength: 64,
      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,
      maxLength: 10000,
      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 || ''
    };
  }
};