Skip to content

Writing a static dialog

In this tutorial, you’ll write a static dialog for a widget in the web client. A static dialog has no state and doesn’t change its content during rendering.

Prerequisites

To complete this tutorial, you should be familiar with TypeScript language and the React framework. It’s good to have basic knowledge about the Telestion Client framework and Adobe’s React Spectrum UI library.

What you’ll build

In this tutorial, you’ll build a static dialog in a widget which asks the user for a confirmation to send a specific telecommand.

The full code for this tutorial looks like this:

widget.tsx
import { useState } from 'react';
import { ActionButton, Flex, TextField, View } from '@adobe/react-spectrum';
import { showDialog } from '@wuespace/telestion-client-common';

function sendTC(command: string): void {
    console.log('Send telecommand: ' + command);
}

export function Widget() {
    const [command, setCommand] = useState('default-command');

    const handle = () => {
        showDialog('custom-tc', {
            title: 'Send telecommand',
            content:
                `Are you sure you want to send the telecommand "${command}"?` ,
            initialState: undefined
        }).then(() => sendTC(command));
    };

    return (
        <View padding="size-200">
            <Flex direction="column" gap="size-100">
                <TextField
                    label="Telecommand"
                    width="100%"
                    value={command}
                    onChange={setCommand}
                />
                <ActionButton onPress={handle}>Send</ActionButton>
            </Flex>
        </View>
    );
}

Step 1: Generate a new widget

Create a new widget with the Telestion Client CLI:

tc-cli generate widget custom-tc-widget

This generates the required files for you. Now navigate to src/widgets/custom-tc-widget and open the widget.tsx source file.

If you already created a widget, open the widget component source file to begin.

Step 2: Define the widget structure

You get greeted with a Heading component generated by the CLI.

Remove it and add a View component with a Flex component as child:

widget.tsx
import { Flex, View } from '@adobe/react-spectrum';

export function Widget() {
    return (
        <View>
            <Flex>{/* ... */}</Flex>
        </View>
    );
}

Add some padding to the View and configure the Flex to column mode with a gap size.

widget.tsx
import { Flex, View } from '@adobe/react-spectrum';

export function Widget() {
    return (
        <View padding="size-200">
            <Flex direction="column" gapsize="size-100">
                {/* ... */}
            </Flex>
        </View>
    );
}

To input and send custom telecommands, you need a text field and a button. Add these two components into the Flex container. Give the TextField a label for better usability and set the width to 100%:

widget.tsx
import { ActionButton, Flex, TextField, View } from '@adobe/react-spectrum';

export function Widget() {
    return (
        <View padding="size-200">
            <Flex direction="column" gapsize="size-100">
                <TextField label="Telecommand" width="100%" />
                <ActionButton>Send</ActionButton>
            </Flex>
        </View>
    );
}

Now, add the widget to your dashboard. If you need help, please take a look at the tutorial on bootstrapping a widget:

Now, start the Web Client and you should see something like this:

The custom telecommand widget

Step 3: Add some state

To send custom telecommands, you need access to the user input from the TextField. Add a React state which holds the current user input and switch the TextField from uncontrolled to controlled mode:

widget.tsx
import { useState } from 'react';
import { ActionButton, Flex, TextField, View } from '@adobe/react-spectrum';

export function Widget() {
    const [command, setCommand] = useState('default-command');

    return (
        <View padding="size-200">
            <Flex direction="column" gapsize="size-100">
                <TextField
                    label="Telecommand"
                    width="100%"
                    value={command}
                    onChange={setCommand}
                />
                <ActionButton>Send</ActionButton>
            </Flex>
        </View>
    );
}

The useState hook from React provides the current state and a function to update it. Thus, you only need to pass these two things to the TextField which now renders the current command and updates it on user input.

Add an onPress event handler to react on send requests from the ActionButton:

widget.tsx
import { useState } from 'react';
import { ActionButton, Flex, TextField, View } from '@adobe/react-spectrum';

function sendTC(command: string): void {
    console.log('A telecommand was sent: ' + command);
}

export function Widget() {
    const [command, setCommand] = useState('default-command');

    const handle = () => {
        sendTC(command);
    };

    return (
        <View padding="size-200">
            <Flex direction="column" gapsize="size-100">
                <TextField
                    label="Telecommand"
                    width="100%"
                    value={command}
                    onChange={setCommand}
                />
                <ActionButton onPress={handle}>Send</ActionButton>
            </Flex>
        </View>
    );
}

This introduces an external function which represents a call method to an external API to actually send the telecommand.

Next, create an event handler which sends the entered telecommand to the external function you defined before. The ActionButton calls the event handler if the user presses the action button.

Step 4: Show a dialog before sending

Because telecommands can be generally disruptive to the remote system, it’s useful to add a modal to prevent sending of unintended commands by the user.

Import the showDialog function from the @wuespace/telestion-client-common package and include it into the event handler:

widget.tsx
import { useState } from 'react';
import { ActionButton, Flex, TextField, View } from '@adobe/react-spectrum';
import { showDialog } from '@wuespace/telestion-client-common';

function sendTC(command: string): void {
    console.log('Send telecommand: ' + command);
}

export function Widget() {
    const [command, setCommand] = useState('default-command');

    const handle = () => {
        showDialog('custom-tc', {
            title: 'Send telecommand',
            content:
                `Are you sure you want to send the telecommand "${command}"?`,
            initialState: undefined
        }).then(() => sendTC(command));
    };

    return (
        <View padding="size-200">
            <Flex direction="column" gapsize="size-100">
                <TextField
                    label="Telecommand"
                    width="100%"
                    value={command}
                    onChange={setCommand}
                />
                <ActionButton onPress={handle}>Send</ActionButton>
            </Flex>
        </View>
    );
}

The showDialog function needs a unique id across the Web Client and a configuration object.

The object is the main part of the dialog. It defines the content of the different parts in the dialog. For example, the title property defines the content in the upper left corner or the content property the center part of the dialog.

For a better understanding take a look at the Spectrum design guidelines for a modal:

Spectrum Dialog

The current example only using simple strings as parameters and build a “dynamic” string out of the entered command.

The dialog can also be stateful. The initialState property defines the initial state of the dialog. In this example, you need no state, so set the dialog state to undefined.

When the showDialog function gets called, a dialog opens with the given configuration. If the user confirms, the returned promise resolves. If the user cancels the dialog, the promise rejects.

Here, you can then react on the success of the promise and send the telecommand.

Now go back to your open Web Client and press the “Send” button. A dialog should open, asking you if you’re sure that you want to send this telecommand:

The open telecommand confirm dialog

Next steps

That’s it. You’ve created your first dialog. 🎉

As mentioned earlier, the dialog itself can be stateful and is much more customizable.

In the next tutorial, you’ll create a more complex example with a stateful dialog.

Writing a stateful dialog