Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't stop a graph, unless use this.deactivate(context) in process API #1048

Open
linonetwo opened this issue Aug 18, 2023 · 0 comments
Open

Comments

@linonetwo
Copy link
Contributor

I found:

  const stopGraph = useCallback(async () => {
    // this may await forever, if some component have process that haven't call `output.done()` or return without calling `this.deactivate(context)`.
    await currentNetworkReference.current?.stop();
    setGraphIsRunning(false);
  }, []);

So in my component I have to write alog of

      if (!input.hasData('control')) {
        this.deactivate(context);
        return;
      }

for example:

/* eslint-disable @typescript-eslint/strict-boolean-expressions */
/* eslint-disable unicorn/no-null, @typescript-eslint/require-await */
// Load the NoFlo interface
import { getDataOrDefault } from '@/pages/Workflow/GraphEditor/utils/getDataOrDefault';
import { Component } from 'noflo';
import type { ITextFieldProps, UIEffectsContext } from '../types/UIEffectsContext';

export const getComponent = () => new TextField();
class TextField extends Component {
  description = 'Wait for user input some text.';
  icon = 'commenting-o';
  uiElementID?: string;
  uiEffects?: UIEffectsContext;
  defaultValues: Record<string, string> = {};

  constructor() {
    super();

    // Define the component's inports
    this.inPorts.add('control', {
      datatype: 'bang',
      description: 'Trigger the input box to show.',
    });

    this.inPorts.add('label', {
      datatype: 'string',
      description: 'Name of this input, should be a short text.',
      required: true,
    });
    this.inPorts.add('desc', {
      datatype: 'string',
      description: 'Description text show on the input box. Can be a one line long text.',
    });
    this.inPorts.add('intro', {
      datatype: 'string',
      description: 'Introduction text show before the input box. Can be a multiple line long text.',
    });
    this.inPorts.add('placeholder', {
      datatype: 'string',
      description: 'Text to display when the input box is empty.',
    });

    this.inPorts.add('ui_effects', {
      datatype: 'object',
      description: 'Used by system, inject UI related methods.',
      required: true,
    });

    this.outPorts.add('out', {
      datatype: 'string',
    });

    // Register a process handler for incoming data
    this.process((input, output, context) => {
      this.uiEffects ??= input.getData('ui_effects') as UIEffectsContext | undefined;
      if (this.uiEffects === undefined) {
        this.deactivate(context);
        return;
      }
      // If 'in' port is not triggered, return
      if (!input.hasData('control')) {
        this.deactivate(context);
        return;
      }
      const control = input.getData('control') as undefined | null | true;
      // rapidly receive null here, still stuck
      if (control !== true) {
        this.deactivate(context);
        return;
      }
      const props: ITextFieldProps = {
        label: getDataOrDefault('label', input, this.defaultValues),
        description: getDataOrDefault('desc', input, this.defaultValues),
        introduction: getDataOrDefault('intro', input, this.defaultValues),
        placeholder: getDataOrDefault('placeholder', input, this.defaultValues),
      };
      // If we already have an UI element created, update it. Otherwise, create a new one.
      if (this.uiElementID === undefined) {
        this.uiElementID = this.uiEffects.addElement({ type: 'textField', props });
        // wait for result, and sent to outPort
        // TODO: change to async await when https://github.com/noflo/noflo/issues/1047 is fixed.
        void this.uiEffects.onSubmit(this.uiElementID).then(resultText => {
          this.uiElementID = undefined;
          output.sendDone({ out: resultText });
        });
      } else {
        this.uiEffects.updateElementProps({ id: this.uiElementID, props });
        this.deactivate(context);
      }
    });
  }

  async tearDown() {
    if (this.uiElementID !== undefined) {
      // set to submit state
      this.uiEffects?.submitElement?.(this.uiElementID, null);
    }
  }
}

This is annoying. Combine with #1047 , I think process API need some upgrade @bergie @trustmaster @jonnor what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant