English | [简体中文](../../zh/develop/3-7-ModalAction-introduction.md)

# Usage

![Modal Form](../../zh/develop/images/form/modal.png)

- After click the action button, the form modal will display.
- After click the `Confirm` button, the `loading` status will be displayed according to the status of request.
- After click the `Cancel` button, the modal form will disappear.
- If the request is sent successfully, a prompt message of successful action will be displayed in the upper right corner, and it will automatically disappear after a few seconds.
- If the request fails, an error message will be displayed in the upper right corner of the form page, which can only disappear after clicking the close button.
- Support batch action, after selecting multiple items in the table, you can click the action button above the table to perform batch action.

# ModalAction code file

- `src/containers/Action/ModalAction/index.jsx`

# ModalAction attribute and function definitions introduction

- Modal forms are all inherited from `ModalAction` component
- Code location: `pages/xxxx/containers/XXXX/actions/xxx.jsx`
- For the case where the form item is relatively less, the modal form is usually used
- Only need to override some functions and the development of page will be completed
- Attributes and functions are divided into the following four types:
  - The attributes and functions that must be override, mainly include:
    - Action ID
    - Action title
    - Action permissions
    - Judgment whether to disable the action button
    - Form Item config
    - Function to send request
  - The attributes and functions that override in need, mainly include:
    - Form default value
    - Form size
    - Form's label & content layout
    - Whether it is an asynchronous action
    - Resource name
    - Whether to display the resource name in the prompt of the request result
    - Action button text
  - The attributes and functions that do not need to be override, mainly include:
    - Whether the current page is a admin page
  - The basic functions in the parent class, mainly include:
    - Render page
    - Display of request status
    - Display of request results
- See below for a more detailed and comprehensive introduction

## The attributes and functions that must be override

- `id`
  - Static
  - Resource action ID
  - Need to be unique, only for all actions in the `actions` of the resource to be unique
  - Must be override
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :

    ```javascript
    static id = 'attach-volume';
    ```

- `title`
  - Static
  - Resource action title
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :

    ```javascript
    static title = t('Attach Volume');
    ```

- `name`
  - Resource action name
  - Use the name in the prompt after the request
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :

    ```javascript
    get name() {
      return t('Attach volume');
    }
    ```

- `policy`
  - Static (Fill in the policy that complies with the openstack rules here)
  - Action permission, if the permission verify failed, the action button will not be displayed on the resource list page
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :

    ```javascript
    static policy = 'os_compute_api:os-volumes-attachments:create';
    ```

- `aliasPolicy`
  - Static (Fill in the custom policy with module prefix here)
  - Action permission, if the permission verify failed, the action button will not be displayed on the resource list page
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :

    ```javascript
    static aliasPolicy = 'nova:os_compute_api:os-volumes-attachments:create';
    ```

- `allowed`
  - Static
  - Determine whether the action button needs to be disabled
  - Return `Promise`
  - Button that no need to be disabled, write directly:

    ```javascript
    static allowed() {
      return Promise.resolve(true);
    }
    ```

  - Param `item`, the item data in the resource list is generally used to determine the action of the item in the resource list.
  - Param `containerProps`, parent container's (That is, the resource list page where the button is located) `props` attribute, generally used to determine the action of related resources under the details page.
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :
    - The admin page does not display the action button
    - The button will show when the server is not: active / deleting / locked / ironic

    ```javascript
    static allowed = (item, containerProps) => {
      const { isAdminPage } = containerProps;
      return Promise.resolve(
        !isAdminPage &&
          isActive(item) &&
          isNotDeleting(item) &&
          isNotLocked(item) &&
          !isIronicInstance(item)
      );
    };
    ```

- `formItems`
  - The form item configuration list corresponding to the action
  - The configuration of each form item can be referred to [3-10-FormItem introduction](3-10-FormItem-introduction.md)
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :
    - Form items includes: instance name label, volume selector

    ```javascript
    get formItems() {
      return [
        {
          name: 'instance',
          label: t('Instance'),
          type: 'label',
          iconType: 'instance',
        },
        {
          name: 'volume',
          label: t('Volume'),
          type: 'volume-select-table',
          tip: multiTip,
          isMulti: false,
          required: true,
          serverId: this.item.id,
          disabledFunc: (record) => {
            const diskFormat = _get(
              record,
              'origin_data.volume_image_metadata.disk_format'
            );
            return diskFormat === 'iso';
          },
        },
      ];
    }
    ```

- `onSubmit`
  - The request function of the action
  - After the action request is successful, the modal will disappear, and a successful prompt will be displayed, and the prompt will disappear after a few seconds
  - After the action fails, the modal will disappear and an error message will be displayed. You need to close the prompt manually before the prompt disappears.
  - Return `Promise`.
  - Return the function in the `store` that corresponding to the form.
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :

    ```javascript
    onSubmit = (values) => {
      const { volume } = values;
      const { id } = this.item;
      const volumeId = volume.selectedRowKeys[0];
      const body = {
        volumeAttachment: {
          volumeId,
        },
      };
      return this.store.attachVolume({ id, body });
    };
    ```

## The attributes and functions that override in need

- `init`
  - Initial operation
  - Defines `this.store` in it, `loading` status is based on `this.store.isSubmitting`
  - Call the function to obtain other data required by the form in it
  - Update attributes in `this.state` .
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :
    - Defines the corresponding `store` for the action

    ```javascript
    init() {
      this.store = globalServerStore;
    }
    ```

- `defaultValue`
  - The initial value of the form
  - Default value is `{}`
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx`为例
    - Set the initial value of the server name in the form

    ```javascript
    get defaultValue() {
      const { name } = this.item;
      const value = {
        instance: name,
      };
      return value;
    }
    ```

- `nameForStateUpdate`
  - Update key-value into `this.state` when form item value changed
  - The key-value stored in `this.state` often affect the display of form items, generally need to be used with `get formItems`
    - Such as expand and hide more configuration items
    - Such as the `required` attribute change of some form items
  - By default, the change of form item which `type` is `radio` or `more` will automaticly save to `this.state`
  - Take attach interface to instance as an example `src/pages/compute/containers/Instance/actions/AttachInterface.jsx` :
    - After select network in the form, the content of the subnet list will be updated
    - However, after select the subnet in the form, the judgment of the input IP will be updated, etc.

    ```javascript
    get nameForStateUpdate() {
      return ['network', 'ipType', 'subnet'];
    }
    ```

- `instanceName`
  - After the request is sent, the resource name in the prompt message
  - Default is `this.values.name`
  - Take edit fip as an example `src/pages/network/containers/FloatingIp/actions/Edit.jsx` :
    - The prompt name is the address of the floating IP

    ```javascript
    get instanceName() {
      return this.item.floating_ip_address;
    }
    ```

- `isAsyncAction`
  - Whether the current action is an asynchronous action
  - Default is `false`
  - If is asynchronous action, the prompt will be : `The xxx instruction has been issued, instance: xxx. \n You can wait for a few seconds to follow the changes of the list data or manually refresh the data to get the final display result.`
  - If is synchronous action, the prompt will be : `xxx successfully, instance: xxx.`
  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :

    ```javascript
    get isAsyncAction() {
      return true;
    }
    ```

- `messageHasItemName`
  - Whether to include the instance name in the prompt of the request result
  - Default is `true`
  - For some resources without `name` attribute, you can set the value `false`
  - Take create snat as an example `src/pages/network/containers/Router/Snat/actions/Create.jsx` :

    ```javascript
    get messageHasItemName() {
      return false;
    }
    ```

- `buttonText`
  - Static
  - When the text on the action button is inconsistent with the title of the modal, this attribute needs to be override
  - Take edit image as an example `src/pages/compute/containers/Image/actions/Edit.jsx` ：

    ```javascript
    static buttonText = t('Edit');
    ```

- `buttonType`
  - Static
  - The type of button, support `primary`, `default`, `link`

- `isDanger`
  - Static
  - Support boolean `false`, `true`, the default value is `false`
  - When the button is to emphasize the risk of action, the button or the text on the button is generally red, use `true`
  - As the example of disable cinder service`src/pages/configuration/containers/SystemInfo/CinderService/actions/Disable.jsx` :

    ```javascript
    static isDanger = true;
    ```

- `modalSize`
  - Static
  - Identifies the width of the modal: the value is`small`、`middle`、`large`
  - The correspondence between value and width is :
    - `small`: 520
    - `middle`: 720
    - `large`: 1200
  - Use with `getModalSize`
  - Default is `small`, means the width of modal is 520px

    ```javascript
    static get modalSize() {
      return 'small';
    }
    ```

  - Take attach volume as an example `src/pages/compute/containers/Instance/actions/AttachVolume.jsx` :
    - the size of modal is `large`

    ```javascript
    static get modalSize() {
      return 'large';
    }

    getModalSize() {
      return 'large';
    }
    ```

- `getModalSize`
  - Identifies the width of the modal
  - The value is`small`、`middle`、`large`

- `labelCol`
  - Configure the layout of the labels on the left side of the form
  - Default is :

    ```javascript
    get labelCol() {
      const size = this.getModalSize();
      if (size === 'large') {
        return {
          xs: { span: 6 },
          sm: { span: 4 },
        };
      }
      return {
        xs: { span: 8 },
        sm: { span: 6 },
      };
    }
    ```

  - Take edit domain as an example `src/pages/identity/containers/Domain/actions/Edit.jsx` :

    ```javascript
    get labelCol() {
      return {
        xs: { span: 6 },
        sm: { span: 5 },
      };
    }
    ```

- `wrapperCol`
  - Configure the layout of the content on the right side of the form
  - Default is :

    ```javascript
    get wrapperCol() {
      return {
        xs: { span: 16 },
        sm: { span: 16 },
      };
    }
    ```

  - Take manage metadata of flavor as an example `src/pages/compute/containers/Flavor/actions/ManageMetadata.jsx` :

    ```javascript
    get wrapperCol() {
      return {
        xs: { span: 18 },
        sm: { span: 20 },
      };
    }
    ```

## The attributes and functions that do not need to be override

- `isAdminPage`
  - Whether current page is a "management platform" page
- `successText`
  - Successful prompt generated after the request
- `errorText`
  - Error prompt generated after the request fails
- `containerProps`
  - Get the `props` of the father component of the button
- `item`
  - Get the data of the item that the action corresponding to
- `items`
  - Get the data corresponding to the batch action

## The basic functions in the parent class

- `ModalAction` extends `BaseForm`
- Recommend to see `src/components/Form/index.jsx`
