Was this page helpful?

Understanding Target State

The targetState data structure defines where an app will render. It is responsible for assigning an app to specific fields, sidebars and editors in the web app during the configuration of an app as well as setting any instance parameters required by the app. We use the term targetState because it refers to the state of an environment after the app is configured.

Understanding the targetState object

To get a better understanding when and how targetState is used, we will go through an example. The following code shows a component that is used for the app.

class Config extends Component {
  // We are skipping the render example because it is not relevant to this example.
  render() { ... }
  // This method will be called when a user clicks on "Install"
  // or "Save" in the configuration screen.
  //
  // We want to do two things in here:
  // 1. Persist selected values as a parameter
  // 2. Assign the app to sidebars of all Content Types
  async onConfigure() {
    // Get current state
    // This will be used as base for next state updates
    const currentState = await sdk.app.getCurrentState();
    // The return value of `onConfigure` is used to install
    // or update the configuration.
    return {
      // Parameters to be persisted as the app's installation parameters.
      parameters: { ... },
      // Transformation of an environment performed in the
      // installation process.
      targetState: {
        EditorInterface: {
          // Always pass in the `currentState` to avoid
          // removing any previous location configuration
          ...currentState?.EditorInterface,
          // A content type id where we will assign the app to the sidebar
          'my-content-type-id': {
              // assignment to sidebar in position 0 (will show up at the very top of the sidebar)
              sidebar: { position: 0 }
          }
        }
      },
    };
  }
}

The targetState is part of the object that you can optionally return in your onConfigure function. The keys of the EditorInterface are the IDs of content types we want to configure for the app. In the code example above, my-content-type-id is the ID of a content type that will have our example app in the sidebar at position 0, which means it will be the first thing you see. Apps can leverage different locations to cover different use cases. It is especially important to note here that we always include the currentState to preserve the current EditorInterface state upon configuration updates. In the example above we were only interested in installing the app in the sidebar location. Below, we will illustrate how to install an app into different locations.

Omitting the targetState key in the object returned by onConfigure will remove any previous app location assignment and instance parameters!

Entry editor location

If you want an app to be rendered as a new entry editor, you need to specify the key editors property for the desired content type. The expected value is an object whose position represents the location (zero-based) of the editor in the list of editors. The editors object can also contain an optional key settings which can be used to set any instance parameters used by the app.

async onConfigure() {
  // Get current state
  // This will be used as base for next state updates.
  const currentState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration.
        ...currentState?.EditorInterface,
        'my-content-type-id': {
            editors: {
              // Places the entry at the second position
              // (position = 1) in the editors list for the
              // content type with ID `my-content-type-id`.
              position: 1,

              // Set values for this location for the app's instance parameters
              settings: {
                parameterOne: true,
                anotherParamter: 'orange'
              }
            }
        }
      }
    },
  };
}

Field location

If you want an app to render as an entry field, specify the controls property with the field IDs of the content type you want to replace with your app. Each control object can also contain an optional key settings which can be used to set any instance parameters used by the app.

async onConfigure() {
  // Get current state
  // This will be used as base for next state updates
  const currentState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration
        ...currentState?.EditorInterface,
        // Render the app as two field editors of the content
        // type with ID `another-content-type` (field: `my-field-id`)
        'my-content-type-id': {
            controls: [
            { fieldId: 'my-field-id' },
            { fieldId: 'a-field-with-instance-parameters', settings: { parameter: true } },
          ]
        }
      }
    },
  };

Entry sidebar location

If you want an app to render in the sidebar of your entry editor, you need to specify the sidebar property as the key for your desired content type. The position value refers to the order in which the app is rendered in the sidebar. 0 means that the app is rendered at the first position. The sidebar object can also contain an optional key settings which can be used to set any instance parameters used by the app.

async onConfigure() {
  // Get current state
  // This will be used as base for next state updates
  const currentState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration
        ...currentState?.EditorInterface,
        'my-content-type-id': {
          sidebar: {
            // Render the app on the top (position = 0) of the
            // sidebar for the content type with ID `my-content-type-id`.
            position: 0,

            // Optionally set instance parameters used by the app
            settings: {
              parameterOne: true,
              anotherParamter: 'orange'
            }
          }
        }
      }
    },
  };
}

Entry dialog location

Dialog locations are enabled by default and do not require any extra properties in the targetState.

Page location

Since the page location is its own route in the web app and does not interfere with the EditorInterface at all, there is no extra property needed for the targetState.

Multiple content types and locations

Since the targetState is a plain JavaScript object, we can add multiple keys to the EditorInterface property. This allows us to support multiple content types and location configurations to build more complex apps. The following example defines a targetState using three content types.

async onConfigure() {
   // Get current state
  // This will be used as base for next state updates
  const appState = await sdk.app.getCurrentState();
  // The return value of `onConfigure` is used to install
  // or update the configuration.
  return {
    // Parameters to be persisted as the app configuration.
    parameters: { ... },
    // Transformation of an environment performed in the
    // installation process.
    targetState: {
      EditorInterface: {
        // Always pass in the `currentState` to avoid
        // removing any previous location configuration
        ...currentState?.EditorInterface,
        // Places the entry at the second position in the editors
        // list for the content type with ID `my-content-type-id`
        'my-content-type-id': {
            editors: { position: 1 }
        },
        // Places the entry at the first position in the editors
        // list for the content type `another-content-type-id`
        'another-content-type-id': {
            editors: { position: 0 }
        },
        // Render the app as two field editors
        // and render the app on the top (position = 0) of the
        // sidebar for the content type with ID `another-content-type`
        'another-content-type': {
          sidebar: { position: 0 },
          controls: [
            { fieldId: 'title' },
            { fieldId: 'metadata' }
          ]
        }
      }
    },
  };
}