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:
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:
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:
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.
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%:
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:
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:
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:
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:
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:
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:
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.