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.